and figured it wouldn't be too difficult to monitor the mouse in/out of systray icons. Turns out it was a bit more involved than I had thought. Processing the mousemove message sent automatically was simple enough, but how to know when the mouse leaves? Nonetheless I believe I have something usable:
Code: Select all
;======================================================================
; Library: MonitorSysTrayMouseEvents
; Author: Lloyd Gallant (netmaestro)
; Date: August 1, 2009
; Target OS: Microsoft Windows XP (maybe more)
; Target Compiler: PureBasic 4.31 and later
; License: Unrestricted, no warranty expressed or implied
;======================================================================
#MSG_ST_MOUSEENTER = #WM_APP+1
#MSG_ST_MOUSELEAVE = #WM_APP+2
Structure TRAYICONRECT
id.l
loc.RECT
hot.b
EndStructure
NewList pbTrayButton.TRAYICONRECT()
Procedure Find_PB_TrayIcons()
Structure TRAYDATA
hwnd.l
uID.l
uCallbackMessage.l
Reserved.l[2]
hIcon.l
EndStructure
Shared pbTrayButton()
; Find the System Tray Icon Toolbar
Protected hwnd
hWnd = FindWindow_("Shell_TrayWnd", #Null)
If hWnd
hWnd = FindWindowEx_(hWnd, #Null, "TrayNotifyWnd", #Null)
If hWnd
hWnd = FindWindowEx_(hWnd,#Null, "SysPager", #Null)
If hWnd
hTray = FindWindowEx_(hWnd, #Null, "ToolbarWindow32", #Null)
Else
ProcedureReturn 0
EndIf
Else
ProcedureReturn 0
EndIf
Else
ProcedureReturn 0
EndIf
; If we're still here we found the systray toolbar
count = SendMessage_(hTray, #TB_BUTTONCOUNT, 0, 0)
Dim button.TBBUTTON (count)
Dim button_td.TRAYDATA(count)
; Put it in the can opener
dwExplorerThreadId=GetWindowThreadProcessId_(hTray, @dwExplorerProcessId)
hProc = OpenProcess_(#PROCESS_ALL_ACCESS, #False, dwExplorerProcessId)
*lpData = VirtualAllocEx_(hProc, #Null, SizeOf(TBBUTTON)*count, #MEM_COMMIT, #PAGE_READWRITE)
*lpRect = VirtualAllocEx_(hProc, #Null, SizeOf(RECT)*count, #MEM_COMMIT, #PAGE_READWRITE)
; Enumerate the systray buttons, ignore all but our own
For i = 0 To count-1
SendMessage_(hTray, #TB_GETBUTTON, i, *lpData+i*SizeOf(TBBUTTON) )
ReadProcessMemory_(hProc, *lpData+(i*SizeOf(TBBUTTON)), @button.TBBUTTON(i), SizeOf(TBBUTTON), #Null)
ReadProcessMemory_(hProc, button(i)\dwData, @button_td.TRAYDATA(i), SizeOf(TRAYDATA), #Null)
; Is it one of ours?
If button_td(i)\uCallbackMessage = 12501 ; PB team-chosen callback messageid, if true it belongs to us
AddElement(pbTrayButton())
SendMessage_(hTray, #TB_GETITEMRECT, i, *lpRect+i*SizeOf(RECT))
ReadProcessMemory_(hProc, *lpRect+(i*SizeOf(RECT)), @pbTrayButton()\loc, SizeOf(RECT), #Null)
pbTraybutton()\id = button_td(i)\uid
MapWindowPoints_(hTray, 0, pbTrayButton()\loc,2)
EndIf
Next
; Wipe off the can opener and put it away
VirtualFreeEx_(hProc, *lpData, #Null, #MEM_RELEASE)
VirtualFreeEx_(hProc, *lpRect, #Null, #MEM_RELEASE)
CloseHandle_(hProc)
; Return the number of our Tray icons found and processed
ProcedureReturn ListSize(pbTrayButton())
EndProcedure
Procedure MonitorTray(window)
Shared pbTrayButton()
If Find_PB_TrayIcons()
Repeat
ForEach pbTrayButton()
GetCursorPos_(@cp.POINT)
If PtInRect_(pbTrayButton()\loc, cp\x|(cp\y<<32))
If Not pbTrayButton()\hot
pbTrayButton()\hot = 1
If IsWindow_(window)
PostMessage_(window, #MSG_ST_MOUSEENTER, pbTrayButton()\id, 0)
EndIf
EndIf
Else
If pbTrayButton()\hot
pbTrayButton()\hot = 0
If IsWindow_(window)
PostMessage_(window, #MSG_ST_MOUSELEAVE, pbTrayButton()\id, 0)
EndIf
EndIf
EndIf
Delay(1)
Next
ForEver
EndIf
EndProcedure
Procedure ProcessSystrayMouseMessages(window)
CreateThread(@MonitorTray(),window)
EndProcedure
Code: Select all
IncludeFile "MonitorSysTrayMouseEvents.pbi"
OpenWindow(0, 100, 150, 300, 100, "PureBasic - SysTray Example", #PB_Window_SystemMenu)
IconName$ = #PB_Compiler_Home+"examples\sources\data\CdPlayer.ico"
AddSysTrayIcon(0, WindowID(0), LoadImage(0, IconName$))
AddSysTrayIcon(1, WindowID(0), LoadImage(0, IconName$))
SysTrayIconToolTip(1, "Icon 1")
ProcessSystrayMouseMessages(WindowID(0))
Repeat
EventID = WaitWindowEvent()
Select EventID
Case #MSG_ST_MOUSEENTER
Debug "Entered Systray Icon " + Str(EventwParam())
Case #MSG_ST_MOUSELEAVE
Debug "Left Systray Icon " + Str(EventwParam())
EndSelect
Until EventID = #PB_Event_CloseWindow
Tested on XP SP2 only. If it works on other versions, please let me know.