Opened 21 months ago
Last modified 8 months ago
#3942 assigned Feature Request
@EVT_POS, @EVT_TIME, @EVT_INFO event macros — at Initial Version
Reported by: | AutoXenon | Owned by: | |
---|---|---|---|
Milestone: | Component: | AutoIt | |
Version: | Severity: | None | |
Keywords: | Cc: |
Description
References:
learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessagepos learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessagetime learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo devblogs.microsoft.com/oldnewthing/20121101-00/?p=6193
Motivation:
Manually calling MouseGetPos() when an OnEvent function is triggered may result in an incorrect position as there might be new mouse movements from the time the message is posted. The correct way to retrieve the associated cursor position or message timestamp is to make a DllCall to GetMessagePos/GetMessageTime within the OnEvent function. This results in frequently re-used boilerplate code in every GUISetOnEvent and GUIRegisterMsg callbacks. It also has a bit of overhead for frequently received messages, having to call it from within AutoIt's interpreter
Since these data are always associated with every Windows Message, it makes sense to just make it a built-in macro that is called from the C++ core for all Windows Messages. The syscall is pretty fast so I don't think it would be necessary to make it optionally activated, but if it turns out that it needs it after all then we could always just have it hidden behind an Opt('EventExtraInfo',1) flag or something like that.
Note that the raw @EVT_POS returned from the WinAPI call is a 32-bit dword where x and y are signed 16-bits. In my boilerplates I use DllStructCreate with pointers to recast them into two signed shorts like so:
Func GetMessagePos($dll='user32.dll') Local $pos = DllCall($dll,'dword','GetMessagePos')[0] Local $_ = DllStructCreate('dword;') DllStructSetData($_,1,$pos) Local $val = DllStructCreate('short x;short y',DllStructGetPtr($_)) Local $pos = [$val.x,$val.y] Return $pos EndFunc
And the boilerplates for GetMessageTime and GetMessageExtraInfo is as follows
Func GetMessageTime($dll='user32.dll') Return DllCall($dll,'long','GetMessageTime')[0] EndFunc Func GetMessageExtraInfo($dll='user32.dll') Return DllCall($dll,'lparam','GetMessageExtraInfo')[0] EndFunc
A sample application using the above boilerplates:
#OnAutoItStartRegister SetProcessDPIAware Opt("GUIOnEventMode",1) Global Const $user32 = DllOpen('user32.dll') GUICreate('',@DesktopWidth,@DesktopHeight,0,0,0x80000000,8) GUISetOnEvent(-3,Quit) GUISetOnEvent(-7,OnPrimaryDown) GUISetOnEvent(-8,OnPrimaryUp) GUISetOnEvent(-9,OnSecondaryDown) GUISetOnEvent(-10,OnSecondaryUp) GUISetState() HotKeySet('{space}',OnSpace) While Sleep(1000) WEnd Func Quit() Exit EndFunc Func OnPrimaryDown() Local $pos = GetMessagePos($user32), $time = GetMessageTime($user32), $info = GetMessageExtraInfo($user32) ToolTip('pos: '&$pos[0]&','&$pos[1]&@CRLF&'time: '&$time&@CRLF&'info: '&Hex($info),$pos[0],$pos[1],'PrimaryDown') EndFunc Func OnSecondaryDown() Local $pos = GetMessagePos($user32), $time = GetMessageTime($user32), $info = GetMessageExtraInfo($user32) ToolTip('pos: '&$pos[0]&','&$pos[1]&@CRLF&'time: '&$time&@CRLF&'info: '&Hex($info),$pos[0],$pos[1],'SecondaryDown') EndFunc Func OnPrimaryUp() ToolTip('') EndFunc Func OnSecondaryUp() ToolTip('') EndFunc Func OnSpace() Local Static $on = False $on = not $on Local $_ = DllStructCreate('dword;struct;long;long;dword;dword;dword;ulong_ptr;endstruct;') DllStructSetData($_,1,0) DllStructSetData($_,5,$on ? 2 : 4) DllStructSetData($_,6,420) DllStructSetData($_,7,0xdeadbeef) Return DllCall( $user32, 'uint', 'SendInput', 'uint', 1, 'struct*', $_, 'int', DllStructGetSize($_) )[0] EndFunc Func GetMessagePos($dll='user32.dll') Local $pos = DllCall($dll,'dword','GetMessagePos')[0] Local $_ = DllStructCreate('dword;') DllStructSetData($_,1,$pos) Local $val = DllStructCreate('short;short',DllStructGetPtr($_)) Local $pos = [DllStructGetData($val,1),DllStructGetData($val,2)] Return $pos EndFunc Func GetMessageTime($dll='user32.dll') Return DllCall($dll,'long','GetMessageTime')[0] EndFunc Func GetMessageExtraInfo($dll='user32.dll') Return DllCall($dll,'lparam','GetMessageExtraInfo')[0] EndFunc Func SetProcessDPIAware() GUICreate('') DllCall('user32.dll', 'bool', 'SetProcessDPIAware') GUIDelete() EndFunc