Monday, April 28, 2014

Logitech G510 Keyboard dismantled, it's RGB led light guide system, and a palm rest fix

About 2 years ago I built my new PC, and I wanted a led-lighted keyboard.
After a lot of searching I decided for the Logitech G510 gaming keyboard. Not that I do much gaming... but being a software developer, I like the idea of having 18 extra programmable keys :-)
And the G510 was the only keyboard (with a decent price) where I can choose the color of the keys illuminations.
I simply wanted to have white lighted keys... and the majority of lighted keyboard have all sorts of  colors but the white.

I knew, from the reviews I read, that the brightness of this keyboard isn't very high, but it still does the job. I haven't had any issue in seeing the keys.. I just think it would be esthetically nicer if the keys had a bit more brightness.

So, mainly out of curiosity, I decided to take the G510 apart, just to see how the keys are illuminated.

Here we go with some photos of my G510.

My Logitech G510




The Palm Rest Fix
While we are at it, the G510 palm rest could have been projected in a better way.
The following image (from the Logitech G510 Review of  www.axonnsays.com) explain very well the issue you'll have with this palm rest.
Photos of palm rest from the Logitech G510 Review on  www.axonnsays.com
You need to use 2 hand each time you need to move, or lift, the keyboard, this is very annoying.
So I fixed it after some days of use :-)

Here is my fix: a glued piece of plastic that will keep the palm rest in line with the keyboard.
The strange shape of the piece of plastic is due to where it came from: a CD jewel case.
The plastic is glued with hot glue.
I've scratched the back of the keyboard (the back of the plastic is also scratched) to have better gluing performance.
The perimeter of the added plastic is shaved wit a cutter, so that the added thickness won't interfere with the feet of the keyboard.

 And TADAAAA!!! Here is a Logitech G510 keyboard with a fixed palm rest! :-)

Dismantling the G510

 Remove 15 screws...

Remove the logitech logo: this is required by the palm rest fix.
By removing the logitech logo the palm rest gain the mobility needed to remove the back of the keyboard

 After removing the screws, we can lift up the back of the keyboard.
 And here is a connector to detach.
After detaching the connector we can remove the back, and take a look a it... not much to see there.

 the cable of the keyboard is well fixed.

The lighting system

Here is the interesting part of the keyboard.
 And here is the keyboard with the white reflecting background removed.

This keyboard use an light guide to illumination the keys.
The back of the keyboard is composed by a transparent sheet of plastick thick about 3mm.
The back (and also the sides) of this transparent plastic are covered with a white background (removed in the above photo).
The Leds that illuminate the keys are on the bottom side of this transparent plastic.
Under each key there is a square "dotted" part of this transparent plastic that help the light to be reflect up through the key.

I think that with this kind of illumination system it will be very hard to attain high level of brightness.

The fact is that it doesn't seem to be a very efficient way to light the keys.
The leds push the light in the light guide, the light get (more or less) uniformly scattered around the light guide, a part of the light is absorbed by the white background, another part is reflected by the dotted part of the light guide, another part is lost (absorbed by anything that is not a 'hole through a key' on the front part of the light guide, or trough the side of the light guide that are not shielded with white reflecting material (the bottom side of the light guide is not covered with the white background)

So it is like having 6 leds that try to illuminate a white sheet big as all the keyboard, and then we look at this illuminated sheet through some translucent letter shaped hole on top of the keys.
Not very efficient...


Now, some more images of the G510.

I've counted 6 RGB LED that illuminate the keyboard, these led are soldered on 3 PCB, on the lower side of  the keyboard.
Here is the right PCB, with 2 leds
This PCB is interesting, because it seem to have an unused connector (you can see it in the bottom left part of the PCB, in the above image).
This could be useful for some light hacking project...

(white background removed)
Here is the central PCB, with other 2 leds


(white background removed)
  and here is the left PCB, with the last 2 leds.

(white background removed)

 A side view of the transparent plastic that work as a light guide, it's thick about 3mm.

 A side view of one of the 3 PCB with the leds

The volume knob, and it's encoder.



 The top circuit board, and the PCB behind the LCD display.



A detail of the white background that cover the back of the light guide, even the side are "shielded" with the white reflector.  (but not the bottom one... and anyway these side shielding is far from optimal, because they are not very straight)
Here is the white background placed on the light guide.

Here you can see the dotted square behind each key, they'll help the light to reflected up through each key.
Now I understand why, from some angle, the light from the G510 keys seem somewhat 'dotted'.

Here is a frontal view of some of the dotted squares.


 Another image of the keyboard

On the perimeter of the keyboard you'll find a lot of these screws, doing apparently nothing... I think they hold the gray plastic on the front of the keyboard.

The mysterious ferrite
And now a tiny mystery: inside the keyboard I found this tiny piece of ferrite.
 
Where does it came from? I don't know.

I thought it was plastic... but after reassembling the keyboard, I found that it was attached to my tiny magnets (I use these tiny neodymium magnet to hold the screws when I dismantle somethings).
I've looked to all the photos, and I didn't see ferrite anywhere.

SCOOP: The mysterious ferrite origins unveiled! :-)
As suggested from an anonymous reader in the comments, the ferrite come from the curly part of the internal usb cable.
In fact, zooming-in in one of the photos, you can see the other piece of ferrite near the cable:
Thanks again to the anonymous commenter who suggested where to look for the ferrite :-)

Monday, April 14, 2014

Refresh tray icons - How to remove dead tray icon after killing a program/process

Sometime you  just need to automate something, like running a script, killing a program, refreshing something...
Killing a program from a script, sometime, have an unwanted side effect: the tray icon of this program wont go away until you move your mouse over it.
So after, say, 10 run of the script, you find yourself with 10 copy of the same (dead) icons.


The solution seam easy: just move your mouse over the dead icons, and they will go away.
But after years of applying this same old solution, I got tired, and I started looking for a better way :-)

And I found it: I found an AutoHotKey script that refresh the trayicons, removing the dead one.
There are various version of this specific script, the one I found seem to works perfectly on Win7 x64 (it's supposed to works even on x32 system, but I didn't try it) 
I would like to credit the original author, but I don't remember the specific forum/website where I downloaded this specific version (I downloaded a lot of ahk script before finding one that worked...)

Here are the download links:

Here is the source code (formatting by  http://codeformatter.blogspot.it/  and  http://prettyprinter.de/module.php?name=PrettyPrinter)
 tray_iconCleanup()  
 tray_icons()  
 {  
   static TB_BUTTONCOUNT := 0x0418, TB_GETBUTTON := 0x0417  
   array := []  
   array[0] := ["sProcess","toolTip","nMsg","uID","idx","idn","Pid","hwnd","sClass","hIcon"]  
   Index := 0  
   detectHiddenWindows_old := a_detectHiddenWindows  
   detectHiddenWindows, on  
   trayWindows := "Shell_TrayWnd,NotifyIconOverflowWindow"  
   loop, parse, trayWindows, csv  
   {  
     winGet, taskbar_pid, PID, ahk_class %a_loopField%  
     hProc := dllCall( "OpenProcess", "Uint", 0x38, "int", 0, "Uint", taskbar_pid )  
     pProc := dllCall( "VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4 )  
     idxTB := tray_getTrayBar()  
     sendMessage, %TB_BUTTONCOUNT%, 0, 0, ToolbarWindow32%idxTB%, ahk_class %a_loopField%  
     loop, %errorLevel%  
     {  
       sendMessage, %TB_GETBUTTON%, a_index-1, pProc, ToolbarWindow32%idxTB%, ahk_class %a_loopField%  
       varSetCapacity( btn,32,0 ), varSetCapacity( nfo,32,0 )  
       dllCall( "ReadProcessMemory", "Uint", hProc, "Uint", pProc, "Uint", &btn, "Uint", 32, "Uint", 0 )  
       iBitmap := numGet( btn, 0 )  
       idn := numGet( btn, 4 )  
       Statyle := numGet( btn, 8 )  
       if dwData := numGet( btn,12,"Uint" )  
       iString := numGet( btn,16 )  
       else dwData := numGet( btn,16,"int64" ), iString := numGet( btn,24,"int64" )  
       dllCall( "ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 32, "Uint", 0 )  
       if numGet( btn,12,"Uint" )  
       {  
         hwnd := numGet( nfo, 0 )  
         uID := numGet( nfo, 4 )  
         nMsg := numGet( nfo, 8 )  
         hIcon := numGet( nfo,20 )  
       }  
       else hwnd := numGet( nfo, 0,"int64" ), uID := numGet( nfo, 8,"Uint" ), nMsg := numGet( nfo,12,"Uint" )  
       winGet, pid, PID, ahk_id %hwnd%  
       winGet, sProcess, ProcessName, ahk_id %hwnd%  
       winGetClass, sClass, ahk_id %hwnd%  
       varSetCapacity( sTooltip,128 ), varSetCapacity( wTooltip,128*2 )  
       dllCall( "ReadProcessMemory", "Uint", hProc, "Uint", iString, "Uint", &wTooltip, "Uint", 128*2, "Uint", 0 )  
       dllCall( "WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0 )  
       idx := a_index-1  
       toolTip := a_isUnicode ? wTooltip : sTooltip  
       Index++  
       for a,b in array[0]  
       array[Index,b] := %b%  
     }  
     dllCall( "VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000 )  
     dllCall( "CloseHandle", "Uint", hProc )  
   }  
   detectHiddenWindows, %detectHiddenWindows_old%  
   return array  
 }  
 tray_iconCleanup()  
 {  
   /*  
   remove orphan icons ( Their processes have been killed )  
   */  
   tray_icons := tray_icons()  
   for index in tray_icons  
   {  
     ifEqual,index,0,continue  
     if ( tray_icons[index, "sProcess"] = "" )  
     tray_iconRemove( tray_icons[index, "hwnd"], tray_icons[index, "uID"],"", tray_icons[index, "hIcon"] )  
   }  
 }  
 tray_iconRemove( hwnd, uID, nMsg = 0, hIcon = 0, nRemove = 0x2 )  
 {  
   /*  
   NIM_DELETE := 0x00000002  
   typedef struct _NOTIFYICONDATA {  
     DWORD cbSize; x00  
     hwnd hwnd; x04  
     UINT uID; x0c/d12  
     UINT uFlags; x10/d16  
     UINT uCallbackMessage; x14/d20  
     HICON hIcon; x18/d24  
     TCHAR szTip[64]; x20 ( UNICODE )  
     DWORD dwState; xa0  
     DWORD dwStateMask; xa4  
     TCHAR szInfo[256]; xa8 ( UNICODE )  
     union {  
       UINT uTimeout; x01a8  
       UINT uVersion; x01a8  
     };  
     TCHAR szInfoTitle[64]; x01ac ( UNICODE )  
     DWORD dwInfoFlags; x022c  
     GUID guidItem; ( 128bits ) x0230  
     HICON hBalloonIcon; x023c  
     ;end x0244  
   } NOTIFYICONDATA, *PNOTIFYICONDATA;  
   MSDN:  
   http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352%28v=vs.85%29.aspx  
   */  
   varSetCapacity( nid,size := 936+4*a_ptrSize )  
   numPut( size, nid, 0, "uint" )  
   numPut( hwnd, nid, a_ptrSize )  
   numPut( uID, nid,a_ptrSize*2, "uint" )  
   numPut( 1|2|4, nid,a_ptrSize*3, "uint" )  
   numPut( nMsg , nid,a_ptrSize*4, "uint" )  
   numPut( hIcon, nid,a_ptrSize*5, "uint" )  
   return dllCall( "shell32\Shell_NotifyIconA", "Uint", nRemove, "Uint", &nid )  
 }  
 tray_iconHide( idn, bHide = true )  
 {  
   static TB_HIDEBUTTON := 0x404, WM_SETTINGCHANGE := 0x001A  
   idxTB := tray_getTrayBar()  
   sendMessage, %TB_HIDEBUTTON%, idn, bHide, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd  ;NotifyIconOverflowWindow  
   sendMessage, %WM_SETTINGCHANGE%, 0, 0, , ahk_class Shell_TrayWnd  
 }  
 tray_iconDelete( idx )  
 {  
   static TB_DELETEBUTTON := 0x416, WM_SETTINGCHANGE := 0x001A  
   idxTB := tray_getTrayBar()  
   sendMessage, %TB_DELETEBUTTON%, idx - 1, 0, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd  
   sendMessage, %WM_SETTINGCHANGE%, 0, 0, , ahk_class Shell_TrayWnd  
 }  
 tray_iconMove( idxOld, idxNew )  
 {  
   static TB_MOVEBUTTON := 0x452  
   idxTB := tray_getTrayBar()  
   sendMessage, %TB_MOVEBUTTON%, idxOld - 1, idxNew - 1, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd  
 }  
 tray_getTrayBar()  
 {  
   detectHiddenWindows_old := a_detectHiddenWindows  
   detectHiddenWindows, on  
   controlGet, hParent, hwnd,, TrayNotifyWnd1 , ahk_class Shell_TrayWnd  
   controlGet, hChild , hwnd,, ToolbarWindow321, ahk_id %hParent%  
   loop  
   {  
     controlGet, hwnd, hwnd,, ToolbarWindow32%a_index%, ahk_class Shell_TrayWnd  
     if !hwnd  
     break  
     else if ( hwnd = hChild )  
     {  
       idxTB := a_index  
       break  
     }  
   }  
   detectHiddenWindows, %detectHiddenWindows_old%  
   return idxTB  
 }