sulfurious Posted July 9, 2010 Posted July 9, 2010 Hi. Been awhile since I have been here. I have searched and found many snippets, but am stumped. I have a small script that is able to detect when a double/single click happens in Windows Explorer SysListView32 control. But I am looking to find how to see which column of the SysListView to monitor the click action for. I had seen this snippet in how to monitor for a double click expandcollapse popup#include <GuiConstantsEx.au3> #include <WindowsConstants.au3> #include <Constants.au3> #include <WinAPI.au3> Global Const $WM_LBUTTONDBLCLK = 0x203 $hGUI = GUICreate("Test GUI", 300, 200) $edit = GUICtrlCreateEdit("", 10, 10, 280, 180) $wProcHandle = DllCallbackRegister("_WindowProc", "ptr", "hwnd;uint;wparam;lparam") $wProcOld = _WinAPI_SetWindowLong(GUICtrlGetHandle($edit), $GWL_WNDPROC, DllCallbackGetPtr($wProcHandle)) GUISetState() Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGui) DllCallbackFree($wProcHandle) Func _WindowProc($hWnd, $Msg, $wParam, $lParam) Switch $hWnd Case GUICtrlGetHandle($edit) Switch $Msg Case $WM_LBUTTONDBLCLK ConsoleWrite("-> Left mouse double click" & @LF) Return 0 EndSwitch EndSwitch Local $aRet = DllCall("user32.dll", "int", "CallWindowProc", "ptr", $wProcOld, _ "hwnd", $hWnd, "uint", $Msg, "wparam", $wParam, "lparam", $lParam) Return $aRet[0] EndFunc I like how that code is small and can watch for a dblclick, but I don't know if it can nor understand how to apply that to the windows explorer handle/syslist handle, it seems locked to only the controls in the GUI if I understand it correctly. All of this is compliments of others here, and are good starting points. I was hoping not to have a mousehook, more like a callback from explorer itself. I haven't used much of this sort of thing, only hacking away at it when I need to. This is the piece I am playing with currently; expandcollapse popup#include <WinAPI.au3> #include <GuiListView.au3> Opt('MustDeclareVars', 1) HotKeySet('{ESC}', '_EXIT') Global Const $tagMSLLHOOKSTRUCT = 'int X;int Y;uint;uint;uint;ulong_ptr' Global Const $WM_MOUSEMOVE = 0x0200 Global Const $WM_LBUTTONDOWN = 0x0201 Global Const $WM_LBUTTONUP = 0x0202 Global Const $WM_LBUTTONDBLCLK = 0x0203 Global Const $WM_RBUTTONDOWN = 0x0204 Global Const $WM_RBUTTONUP = 0x0205 Global Const $WM_RBUTTONDBLCLK = 0x0206 Global Const $SHELLDLL_DefView = "SHELLDLL_DefView" Dim $hMHook, $pMHook, $hHook Dim $iDiff = TimerInit() $hMHook = DllCallbackRegister('LowLevelMouseProc', 'long', 'int;wparam;lparam') $pMHook = DllCallbackGetPtr($hMHook) $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pMHook, _WinAPI_GetModuleHandle(0)) While 1 Sleep(50) WEnd Func _EXIT() Exit EndFunc Func OnAutoItExit() DllCallbackFree($hMHook) _WinAPI_UnhookWindowsHookEx($hHook) EndFunc Func LowLevelMouseProc($iCode, $iwParam, $ilParam) Local $tMSLLHOOKSTRUCT = DllStructCreate($tagMSLLHOOKSTRUCT, $ilParam) Local $hWnd If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) If $iwParam = $WM_LBUTTONDOWN Then If TimerDiff($iDiff) < 501 Then ConsoleWrite('click ::: ' & $iDiff & @CRLF) $hWnd = _WinAPI_WindowFromPoint($tMSLLHOOKSTRUCT) ConsoleWrite(_WinAPI_GetClassName(_WinAPI_GetParent($hWnd)) & @CRLF) ;~ If _WinAPI_GetClassName(_WinAPI_GetParent($hWnd)) = $SHELLDLL_DefView And _ ;~ _WinAPI_IsClassName($hWnd, $__LISTVIEWCONSTANT_ClassName) Then ;~ Local $avArray = _GUICtrlListView_HitTest($hWnd) ;~ If $avArray[0] > -1 Then ;~ $filename=_GUICtrlListView_GetItemText($hWnd, $avArray[0]) ;~ if Stringright($filename,3)="au3" then ;~ if ControlGetFocus('Program Manager','') = "SysListView321" then ShellExecute("C:\applications\autoit\AutoIt3.exe",'"'&@DesktopDir&"\"&$filename&'"') ;~ if ControlGetFocus("[class:ExploreWClass]") = "SysListView321" or ControlGetFocus("[class:CabinetWClass]")= "SysListView321" then ShellExecute("C:\applications\autoit\AutoIt3.exe",'"'&ControlGetText("", "", "Edit1")&"\"&$filename&'"') ;~ ConsoleWrite(_GUICtrlListView_GetItemText($hWnd, $avArray[0]) & @LF) ;~ return 1 ;~ EndIf ;~ EndIf ;~ EndIf EndIf $iDiff = TimerInit() EndIf Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) EndFunc ;~ Func LowLevelMouseProc($iCode, $iwParam, $ilParam) ;~ Local $tMSLLHOOKSTRUCT = DllStructCreate($tagMSLLHOOKSTRUCT, $ilParam) ;~ Local $hWnd ;~ If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) ;~ If $iwParam = $WM_LBUTTONDOWN Then ;~ If TimerDiff($iDiff) < 501 Then ;~ $hWnd = _WinAPI_WindowFromPoint($tMSLLHOOKSTRUCT) ;~ If _WinAPI_GetClassName(_WinAPI_GetParent($hWnd)) = $SHELLDLL_DefView And _ ;~ _WinAPI_IsClassName($hWnd, $__LISTVIEWCONSTANT_ClassName) Then ;~ Local $avArray = _GUICtrlListView_HitTest($hWnd) ;~ If $avArray[0] > -1 Then ConsoleWrite(_GUICtrlListView_GetItemText($hWnd, $avArray[0]) & @LF) ;~ EndIf ;~ EndIf ;~ $iDiff = TimerInit() ;~ EndIf ;~ Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) ;~ EndFunc As you can see if you run this piece, it will print out the class name of whatever is under it. No problem to focus on the syslistview control, but I haven't found the correct method to pick one specific column to focus on, if that is even possible. Any comments appreciated. Sul.
sulfurious Posted July 9, 2010 Author Posted July 9, 2010 Turns out no matter what I use, Explorer does not return a column value for any but index 1 (Name). You can move this column if you like, but still it remains column 1. I was able to build a routine that checks for any indices, and if none goes on. This is useful if you need to be sure you can do something without interfering with normal mousing on objects, but not for column specific use. The low level mouse hook uses up quite a bit of resources on a fast machine if you click more than just infrequently. Would this be normal, or is it because of the timer functions? Using the second code in my examples, I am able to isolate the SysListView only for processing, but because of the return value it cannot tell if a DblClick event happened, you have to use a timer to do this. Is there a way to simply watch a control/window, such as SysListView32, and retrieve when a double click action occured, without the use of a timer? I don't want to watch all windows, but specifically the active window IF it is the correct one, and even more better IF the chosen control has the focus. Any input? Sul.
sulfurious Posted July 10, 2010 Author Posted July 10, 2010 This sure is a hot topic After examining the APIs more, it seems like this is the only way to get the mouse clicks from the explorer window (the mouse hook). I tried a bunch of other stuff, including registering my own class and using the CS_DBLCLKS style, which is what is needed to get actual double clicks. But it makes no difference that I can see when it comes to explorer, at least I can't get it to work. I had thought that perhaps by creating a window with that style I could then recieve the DblClck message properly. So let me pose a new question. The testing of handles, parent handles and properties chews up some cycles. Explorer itself, when navigating chews up a few cycles, but hook it and it does even more. Maybe not an issue really, but I have noticed that the global mouse hook can cause some effects, such as when you drag a mid-sized explorer window about it can sort of lag and jitter. This is presumably due to the function getting all the mouse messages and dropping them if not the type I want or maybe just because it is filling the struct every time. So, how would one go about fixing this? One idea is that the callback is not established until an explorer window is active. Maybe a WinWaitActive, then put the hook into place. But, how fast is the unhook/hook? It would be a likely scenario to have 2 explorer windows open, and switching between one explorer instance and the other, as well as other process windows will happen. Is the hook/unhook best utilized in a fashion like this, to only apply the hook when the target window(s) are active? As well, perhaps there is a better routine for handling the messages the hook sends. Maybe one that drops undesired quicker so that less processing occurs. It is too bad that mouse movement in included in this hook, as I think that is what is causeing the lag. Here is a working example of what I am playing with in case anyone cares to take a peek. expandcollapse popup#NoTrayIcon #include <WinAPI.au3> #include <GuiListView.au3> Opt('TrayMenuMode',1) $tExit = TrayCreateItem('Exit') TraySetState() Global Const $GA_PARENT = 1 Global Const $GA_ROOT = 2 Global Const $GA_ROOTOWNER = 3 Global Const $tagMSLLHOOKSTRUCT = 'int X;int Y;uint;uint;uint;ulong_ptr' Global Const $WM_LBUTTONDOWN = 0x0201 Global Const $SHELLDLL_DefView = "SHELLDLL_DefView" Global Const $cWEX = "[CLASS:CabinetWClass]" Global Const $cSys = "[CLASS:SysListView32;INSTANCE:1]" Global $msSPEED = 501 Dim $hMHook, $pMHook, $hHook Dim $iDiff = TimerInit() $hMHook = DllCallbackRegister('LowLevelMouseProc', 'long', 'int;wparam;lparam') $pMHook = DllCallbackGetPtr($hMHook) $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pMHook, _WinAPI_GetModuleHandle(0)) While 1 Sleep(50) $msg = TrayGetMsg() Select Case $msg = $tExit ExitLoop EndSelect WEnd Func OnAutoItExit() DllCallbackFree($hMHook) _WinAPI_UnhookWindowsHookEx($hHook) EndFunc Func LowLevelMouseProc($iCode, $iwParam, $ilParam) Local $tMSLLHOOKSTRUCT = DllStructCreate($tagMSLLHOOKSTRUCT, $ilParam) Local $hWnd, $vIndice If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) ;~ ConsoleWrite('iWparm :: ' & $iwParam & ' ::: ' & Random(1,100,1) & @CRLF) If $iwParam = $WM_LBUTTONDOWN Then If TimerDiff($iDiff) < $msSPEED Then $hWnd = _WinAPI_WindowFromPoint($tMSLLHOOKSTRUCT) If _WinAPI_GetClassName(_WinAPI_GetAncestor($hWnd,$GA_ROOT)) = 'CabinetWClass' Then If _WinAPI_GetClassName(_WinAPI_GetParent($hWnd)) = $SHELLDLL_DefView And _ _WinAPI_IsClassName($hWnd, $__LISTVIEWCONSTANT_ClassName) Then $vIndice = _GUICtrlListView_GetSelectedIndices($hWnd) ;~ ConsoleWrite('vIndice :: ' & $vIndice & ' ::: ' & Random(1,100,1) & @CRLF) If $vIndice = '' Then ConsoleWrite('doing something now -- ' & Random(1,100,1) & @CRLF) EndIf EndIf EndIf EndIf $iDiff = TimerInit() EndIf Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) EndFunc Sul.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now