VAN0 Posted December 27, 2023 Share Posted December 27, 2023 I'm trying get keyup/down events on a control created with _WinAPI_CreateWindowEx() GUI* event's don't work, so I found how to use _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL ...) It works great for my purpose, but with one side effect: it captures events globally, even when other windows are in focus. Is there way restrict events on GUI window only? I know I can check what window is in focus, but I'd like if possible don't get any notifications if they are not coming from my GUI Thank you. expandcollapse popup#Include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <WinAPI.au3> Opt("GUIOnEventMode", 1) OnAutoItExitRegister("onExit") Global $sHexKeys, $sMouse, $sString, $hHookKeyboard, $pStub_KeyProc Global Const $HKM_GETHOTKEY = $WM_USER + 2 global $mKeys[] Global $iKeys = 0 global $hGui = GUICreate("test", 220, 50) GUISetOnEvent($GUI_EVENT_CLOSE, "onClose") global $hInput = _WinAPI_CreateWindowEx (0, "msctls_hotkey32", "", BitOR($WS_CHILD, $WS_VISIBLE), 10, 10, 200, 24, $hGui) GUISetState() $pStub_KeyProc = DllCallbackRegister("_KeyProc", "int", "int;ptr;ptr") $hHookKeyboard = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($pStub_KeyProc), _WinAPI_GetModuleHandle(0), 0) While 1 Sleep(10) WEnd func onChange() ConsoleWrite("onChange: " & SendMessage($hInput, $HKM_GETHOTKEY) & @CRLF) EndFunc func onClose() exit EndFunc Func onExit() _WinAPI_DestroyWindow($hInput) DllCallbackFree($pStub_KeyProc) _WinAPI_UnhookWindowsHookEx($hHookKeyboard) EndFunc Func SendMessage($hWnd, $Msg, $wParam = 0, $lParam = 0) Return DllCall('user32.dll', 'int', 'SendMessage', 'hwnd', $hWnd, 'int', $Msg, 'int', $wParam, 'int', $lParam)[0] EndFunc Func _KeyProc($nCode, $wParam, $lParam) If not $nCode Then Local $KBDLLHOOKSTRUCT = DllStructCreate("dword vkCode;dword scanCode;dword flags;dword time;ptr dwExtraInfo", $lParam) Local $vkCode = DllStructGetData($KBDLLHOOKSTRUCT, "vkCode") Switch $wParam Case $WM_KEYUP, $WM_SYSKEYUP MapRemove($mKeys, $vkCode) $iKeys -= 1 if Not $iKeys then onChange() Case $WM_KEYDOWN, $WM_SYSKEYDOWN if not $mKeys[$vkCode] then $iKeys += 1 $mKeys[$vkCode] = 1 EndIf EndSwitch EndIf Return _WinAPI_CallNextHookEx($hHookKeyboard, $nCode, $wParam, $lParam) EndFunc ;==>_KeyProc Link to comment Share on other sites More sharing options...
Nine Posted December 27, 2023 Share Posted December 27, 2023 Why not hook on $WH_KEYBOARD instead ? Since it is your GUI app, it should work as you want to. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
VAN0 Posted December 27, 2023 Author Share Posted December 27, 2023 I don't think the issue here is the type of events I'm using...$WH_KEYBOARD would be hooked globally as well Link to comment Share on other sites More sharing options...
Nine Posted December 27, 2023 Share Posted December 27, 2023 nope “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
VAN0 Posted December 27, 2023 Author Share Posted December 27, 2023 I get no events received at all when using $WH_KEYBOARD Link to comment Share on other sites More sharing options...
Nine Posted December 27, 2023 Share Posted December 27, 2023 (edited) Of course, like I told you before : 16 minutes ago, Nine said: Since it is your GUI app, it should work as you want to. You need to hook on your GUI, not globally. Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD, DllCallbackGetPtr($hStub), 0, _WinAPI_GetCurrentThreadId()) Edited December 27, 2023 by Nine VAN0 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
VAN0 Posted December 27, 2023 Author Share Posted December 27, 2023 (edited) Except the control is not made with GUICtrlCreate*() hence any GUI*onEvent doesn't work in this particular case. [EDIT] Well, that's more than just "use $WH_KEYBOARD" ... Thanks, now I got to figure out why it's just exiting when event fired.. Edited December 27, 2023 by VAN0 Link to comment Share on other sites More sharing options...
VAN0 Posted December 27, 2023 Author Share Posted December 27, 2023 (edited) 32 minutes ago, Nine said: Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD, DllCallbackGetPtr($hStub), 0, _WinAPI_GetCurrentThreadId()) Assuming this meant to be $hHookKeyboard = _WinAPI_SetWindowsHookEx($WH_KEYBOARD, DllCallbackGetPtr($pStub_KeyProc), 0, _WinAPI_GetCurrentThreadId()) Then it simply crashing my script when I press key: Quote !>14:14:54 AutoIt3.exe ended.rc:-1073741819 +>14:14:54 AutoIt3Wrapper Finished. !>Exit code 3221225477 Time: 3.575 because _KeyProc() receives different type of data and must be modified accordingly. Edited December 27, 2023 by VAN0 Link to comment Share on other sites More sharing options...
Nine Posted December 27, 2023 Share Posted December 27, 2023 Yes it is not the same data. See here for more details. lparam has flags while wparam has vkey “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Andreik Posted December 27, 2023 Share Posted December 27, 2023 Why not simply like this: func onChange() If _WinAPI_GetFocus() <> $hInput Then Return ConsoleWrite("onChange: " & SendMessage($hInput, $HKM_GETHOTKEY) & @CRLF) EndFunc When the words fail... music speaks. Link to comment Share on other sites More sharing options...
VAN0 Posted December 27, 2023 Author Share Posted December 27, 2023 13 minutes ago, Andreik said: Why not simply like this: Because 4 hours ago, VAN0 said: I know I can check what window is in focus, but I'd like if possible don't get any notifications if they are not coming from my GUI Link to comment Share on other sites More sharing options...
Andreik Posted December 27, 2023 Share Posted December 27, 2023 (edited) I can't follow that logic. Both hook types (WH_KEYBOARD_LL and WH_KEYBOARD) will eventually require some sort of processing so it's up to you how you filter these keyboard events. If you want to prevent onChange() being called at all move the focus checking in the hook procedure. Also it's not clear if you want to be notified about keyboard events related to hotkey control or any other control from your GUI. Does this meet your requirements? #Include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <EditConstants.au3> #include <WinAPI.au3> Opt("GUIOnEventMode", 1) Global Const $HKM_GETHOTKEY = $WM_USER + 2 Global $hGui = GUICreate("test", 220, 50) GUISetOnEvent($GUI_EVENT_CLOSE, "onClose") Global $hInput = _WinAPI_CreateWindowEx (0, "msctls_hotkey32", "", BitOR($WS_CHILD, $WS_VISIBLE), 10, 10, 200, 24, $hGui) GUISetState() GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") While True Sleep(10) WEnd Func onClose() Exit EndFunc Func onChange() ConsoleWrite("onChange: " & SendMessage($hInput, $HKM_GETHOTKEY) & @CRLF) EndFunc Func SendMessage($hWnd, $Msg, $wParam = 0, $lParam = 0) Return DllCall('user32.dll', 'int', 'SendMessage', 'hwnd', $hWnd, 'int', $Msg, 'int', $wParam, 'int', $lParam)[0] EndFunc Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) If $lParam = $hInput And _WinAPI_HiWord($wParam) = $EN_CHANGE Then onChange() Return $GUI_RUNDEFMSG EndFunc Edited December 27, 2023 by Andreik When the words fail... music speaks. Link to comment Share on other sites More sharing options...
VAN0 Posted December 28, 2023 Author Share Posted December 28, 2023 No, it doesn't because the "onChange" fires while user is still holding the keys. This means I'm not able clear the field if the keys are not valid until user RELEASED ALL the keys. Anyway, I got this working with $WH_KEYBOARD expandcollapse popup#Include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <WinAPI.au3> Opt("GUIOnEventMode", 1) OnAutoItExitRegister("onExit") Global $hHookKeyboard, $pStub_KeyProc Global Const $HKM_GETHOTKEY = $WM_USER + 2 Global $iKeys = 0 global $hGui = GUICreate("test", 220, 50) GUISetOnEvent($GUI_EVENT_CLOSE, "onClose") global $hInput = _WinAPI_CreateWindowEx (0, "msctls_hotkey32", "", BitOR($WS_CHILD, $WS_VISIBLE), 10, 10, 200, 24, $hGui) GUISetState() $pStub_KeyProc = DllCallbackRegister("_KeyProc", "int", "int;ptr;ptr") $hHookKeyboard = _WinAPI_SetWindowsHookEx($WH_KEYBOARD, DllCallbackGetPtr($pStub_KeyProc), 0, _WinAPI_GetCurrentThreadId()) While 1 Sleep(10) WEnd func onChange() ConsoleWrite("onChange: " & SendMessage($hInput, $HKM_GETHOTKEY) & @CRLF) EndFunc func onClose() exit EndFunc Func onExit() _WinAPI_DestroyWindow($hInput) DllCallbackFree($pStub_KeyProc) _WinAPI_UnhookWindowsHookEx($hHookKeyboard) EndFunc Func SendMessage($hWnd, $Msg, $wParam = 0, $lParam = 0) Return DllCall('user32.dll', 'int', 'SendMessage', 'hwnd', $hWnd, 'int', $Msg, 'int', $wParam, 'int', $lParam)[0] EndFunc Func _KeyProc($nCode, $wParam, $lParam) If $nCode >= 0 Then Local $prevState = BitShift(BitAND($lParam, 0x40000000), 30) Local $isUp = BitShift(BitAND($lParam, 0x80000000), 31) ? 1 : 0 if $prevState == $isUp then if $isUp then $iKeys -= 1 if Not $iKeys then onChange() else $iKeys += 1 EndIf EndIf EndIf Return _WinAPI_CallNextHookEx($hHookKeyboard, $nCode, $wParam, $lParam) EndFunc ;==>_KeyProc Link to comment Share on other sites More sharing options...
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