Developers: Code SnippetsHere's my sample AHK low level mouse hook. The comments should be pretty self-explanatory. This is the hook I'm hoping to implement in eXpresso. #Persistent
#NoEnv
SetBatchLines -1
ListLines off
pMouseHook := RegisterCallback("MouseHookProc", "", 3) ; LowLevelMouseProc
hMouseHook := DllCall("SetWindowsHookEx", "int", 14, "uint", pMouseHook, "uint", DllCall("GetModuleHandle", "uint", 0), "uint", 0) ; set the WH_MOUSE_LL hook
DblClick := DllCall("GetDoubleClickTime") ; gets system dbl click time
DllCall("SetDoubleClickTime", "uint", 30) ; set a very low system dbl click time
; this will allow us to programmatically send our own dbl clicks without interference from the system
; effectively disabling human dbl clicks
; window classes for dbl click subroutine
; for this example we're handling dbl clicks on the Desktop and Explorer windows
aWinClass := "Progman,CabinetWClass,ExploreWClass"
fromEnter := False ; init variable
OnExit, ExitSub ; unregister the hook on exit
Return
; catch the Enter button as well
$Enter::
Critical
fromEnter := True ; cannot use A_ThisHotKey
SetTimer, DoubleClick, -10 ; run timed sub only once
Return
MouseHookProc(nCode, wParam, lParam)
{
Critical ; prevent this thread from being interrupted
Global DblClick, ClickTime, hMouseHook, MouseX, MouseY, fromEnter
; only process messages withe nCode >= 0
; incoming callback params are UINTs, so this is the test for >= 0
If (nCode < 0x80000000)
{
If (wParam = 0x201) ; WM_LBUTTONDOWN
{
; get the mouse position from the MSLLHOOKSTRUCT at lParam (first two elements are a POINT struct)
xpos := NumGet(lParam+0, 0, "int") ; must pass the actual number stored in lParam by using lParam+0
ypos := NumGet(lParam+0, 4, "int")
If (((NumGet(lParam+0, 16, "uint") - ClickTime) < DblClick)
And (Abs(xpos - MouseX) < 8) And (Abs(ypos - MouseY) < 8))
{
; a double click has occurred within a 16x16 area, trigger subroutine
; we'll use a timer so we can get out of this callback as fast as possible
; Critical prevents the timer from interrupting this callback before it has a chance to return
fromEnter := False
SetTimer, DoubleClick, -10 ; run timed sub only once
Return 1 ; suppress the double click, we'll handle it in the timer sub
}
; store last click time and mouse position
ClickTime := NumGet(lParam+0, 16, "uint") ; time stamp from struct
MouseX := xpos
MouseY := ypos
}
}
Return DllCall("CallNextHookEx", "uint", hMouseHook, "int", nCode, "uint", wParam, "uint", lParam)
}
DoubleClick:
; this example handles double clicks in specified windows
WinGet, HWndActiveWin, ID, A ; get active window handle
WinGetClass, classActiveWin, ahk_id %HWndActiveWin% ; get active window class
MouseGetPos,,,,mouseControlClass ; get control class under mouse cursor
Loop, Parse, aWinClass, `, ; parse the string of allowed classes
{
If (classActiveWin = A_LoopField)
{
; only do stuff to a matching window class
ControlGetFocus, activeControl, A
; if we are here because of a double click and the mouse is not over the active control
; (like a dbl click on the title bar), then get out and let the click through
; this allows dbl clicks on other parts of a window that don't steal focus
If (!fromEnter And (mouseControlClass <> activeControl))
Goto EndDblClickSub
; check for supported controls
IfInString, activeControl, SysListView32
{
; we got a list view, use an optimized method to find the selection
; find out if anything is selected
ControlGet, selItems, List, Selected, %activeControl%, ahk_id %HWndActiveWin%
If (selItems <> "")
{
; something is selected, get the result
Loop, Parse, selItems, `n
{
; rows are delimited by `n, columns by A_Tab
; we only want the first column which has the file name
Loop, Parse, A_LoopField, %A_Tab%
{
MsgBox %A_LoopField%
Break ; only interested in first column
}
}
Return ; suppress the click / enter
}
}
; else use generic Ctrl+c copy processing
newClip := ""
oldClip := ClipboardAll ; save old clipboard
Clipboard := "" ; empty it
Send ^c
ClipWait 0.15 ; wait 150 ms
If !ErrorLevel
newClip := Clipboard
If (newClip <> "")
{
Loop, Parse, newClip, `n, `r ; parse the clipboard contents
{
MsgBox %A_LoopField%
}
}
Clipboard := oldClip ; restore clipboard contents
; done processing click / enter
Return ; break the loop and suppress the input
}
}
EndDblClickSub:
; if no matches, send the click or Enter through
If fromEnter
Send {Enter} ; send the Enter key
Else
{
Click ; click primary mouse button
ClickTime :=0 ; prevent hook from seeing dbl click
Click ; trigger the system dbl click
}
Return
ExitSub:
DllCall("UnhookWindowsHookEx", "uint", hMouseHook) ; unregister the hook
DllCall("SetDoubleClickTime", "uint", DblClick) ; reset default dbl click time
ExitApp
( categories: )
|


Very Nice
Thanks for posting this wraithdu. What kind of increase in accuracy have you noted with this approach? I'll definitely be looking at how I can utilize this in some of my scripts.
Again, Thanks
"If knowledge can create problems, is it not through ignorance that we can solve them." -Isaac Asimov
Not sure yet. I'm waiting
Not sure yet. I'm waiting for the source from Oliver when he's done with it. It may or may not be better than the hotkey method that I think Cafe currently uses. The only way to tell will be when someone who is having problems with the hotkey method actually tests this method. I have some other ideas to get away from the Ctrl+C (copy) that Cafe currently uses to get file paths in certain controls, that I hope will be more accurate. But I'll have to wait and see how the implementation goes in Cafe to see if it will be a viable option.
New code posted above. This
New code posted above. This will be closer to what I hope to implement in eXpresso. Note that in Win7 an Explorer window is NO LONGER a 'SysListView32' control, it is a 'DirectUIHWND' control, so we are back to using the Ctrl+c copy technique right now. On my system 150ms to process Ctrl+s seems pretty good. In eXpresso this time will be configurable. I will look into working with this new control and see if it can be directly accessed (like a SysListView32) from AHK.
Also interesting...
I use XYplorer as my at home file explorer. It is a Delphi (I think) program and does not use standard windows controls (SysListView32, etc). In older versions Ctrl+c worked to copy a file path from the list view window. This no longer works in current versions. If a file is selected Ctrl+c yields blank, and if nothing is selected XYplorer pops an error message!
I don't see any way around this at this point, so eXpresso is not likely to work in conjunction with current versions of XYplorer.