VAN0 Posted January 2 Share Posted January 2 Hello. Spoiler I'm on a journey to create a GUI hotkey input control that would work with all possible combinations supported by HotKeySet() Available UDFs that use msctls_hotkey32 are not good enough, they don't support Win key and other combinations. I'm using WM_KEYBOARD event to track key presses, where on keydown I store pressed key in a map and remove it on keyup event. Spoiler expandcollapse popup#include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <EditConstants.au3> #include <WinAPI.au3> Opt("GUIOnEventMode", 1) OnAutoItExitRegister("onExit") Global $hGui = GUICreate("test", 200, 50) GUISetOnEvent($GUI_EVENT_CLOSE, "onClose") Global $gEdit = GUICtrlCreateEdit("", -1, -1, -1, -1, $ES_READONLY) GUISetState() Global $pStub_KeyProc = DllCallbackRegister("_KeyProc", "int", "int;ptr;ptr") Global $hHookKeyboard = _WinAPI_SetWindowsHookEx($WH_KEYBOARD, DllCallbackGetPtr($pStub_KeyProc), 0, _WinAPI_GetCurrentThreadId()) While 1 Sleep(10) WEnd Func _KeyProc($nCode, $wParam, $lParam) Local Static $mKeys[], $mData[] local static $bIsUpPrev, $bIsUp, $iCount, $iCode, $bExtended, $iReserved, $bAlt, $aKeys, $sOut, $sEdit, $key If $nCode >= 0 Then ; https://learn.microsoft.com/en-us/windows/win32/winmsg/keyboardproc#lparam-in $bExtended = BitAND($lParam, 0x1000000) ? 1 : 0 ;24 $iCode = BitShift(BitAND($lParam, 0xFF0000), 16) ;16-23 $bIsUpPrev = BitAND($lParam, 0x40000000) ? 1 : 0 ;30 $bIsUp = BitAND($lParam, 0x80000000) ? 1 : 0 ;31 $key = $iCode & "|" & $bExtended If $bIsUpPrev == $bIsUp Then ;ignore repeated events If $bIsUp Then MapRemove($mKeys, $key) Else $mData.wParam = $wParam $mData.lParam = $lParam $mKeys[$key] = $mData EndIf $aKeys = MapKeys($mKeys) $sOut = "" $sEdit = "" For $key In $aKeys $data = $mKeys[$key] $iCount = BitAND($data.lParam, 0xFFFF) ;0-15 $iCode = BitShift(BitAND($data.lParam, 0xFF0000), 16) ;16-23 $bExtended = BitAND($data.lParam, 0x1000000) ? 1 : 0 ;24 $iReserved = BitShift(BitAND($data.lParam, 0x1E000000), 25) ;25-28 $bAlt = BitAND($data.lParam, 0x20000000) ? 1 : 0 ;29 $sOut &= ($sOut ? " + " : "") & "code[" & $iCode & "] ext[" & $bExtended & "] reserved[" & $iReserved & "] alt[" & $bAlt & "] count[" & $iCount & "] wParam[" & $wParam & "] lParam[" & $lParam & "]" $sEdit &= ($sEdit ? " + " : "") & Number($data.wParam) & "[" & $bExtended & "]" Next GUICtrlSetData($gEdit, $sEdit) ConsoleWrite($sOut & @CRLF) EndIf EndIf Return _WinAPI_CallNextHookEx($hHookKeyboard, $nCode, $wParam, $lParam) EndFunc ;==>_KeyProc Func onClose() Exit EndFunc ;==>onClose Func onExit() DllCallbackFree($pStub_KeyProc) _WinAPI_UnhookWindowsHookEx($hHookKeyboard) EndFunc ;==>onExit It works, but with 2 issues: When pressed Shift + Num nn and then first release Shift and then Num nn, It doesn't properly clears the map When GUI looses focus while a key is down and then the key released, the script doesn't receive keyup event, hence doesn't clear the map #1 - can't figure this one out #2 - I could think only of 2 options: track key presses globally not just for the GUI (undesirable, potentially can be considered as keylogger) Spoiler expandcollapse popup#include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <EditConstants.au3> #include <WinAPI.au3> Opt("GUIOnEventMode", 1) OnAutoItExitRegister("onExit") Global $hGui = GUICreate("test", 200, 50) Global $gEdit = GUICtrlCreateEdit("", -1, -1, -1, -1, $ES_READONLY) Global $hEdit = GUICtrlGetHandle($gEdit) GUISetOnEvent($GUI_EVENT_CLOSE, "onClose") GUISetState() Global $pStub_KeyProc = DllCallbackRegister("_KeyProc", "int", "int;ptr;ptr") Global $hHookKeyboard = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($pStub_KeyProc), _WinAPI_GetModuleHandle(0), 0) While 1 Sleep(10) WEnd Func _KeyProc($nCode, $wParam, $lParam) Local Static $mKeys[], $mKey[] Local Static $tStruct, $key, $prev, $cur If Not $nCode Then ; https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-kbdllhookstruct $tStruct = DllStructCreate("dword vkCode;dword scanCode;dword flags;dword time;ptr dwExtraInfo", $lParam) $mKey.vkCode = DllStructGetData($tStruct, "vkCode") $mKey.scanCode = DllStructGetData($tStruct, "scanCode") $mKey.flags = DllStructGetData($tStruct, "flags") $mKey.time = DllStructGetData($tStruct, "time") $mKey.dwExtraInfo = DllStructGetData($tStruct, "dwExtraInfo") Switch $wParam Case $WM_KEYUP, $WM_SYSKEYUP MapRemove($mKeys, $mKey.scanCode) Case $WM_KEYDOWN, $WM_SYSKEYDOWN If ControlGetHandle($hGui, "", ControlGetFocus($hGui)) == $hEdit Then $mKeys[$mKey.scanCode] = $mKey EndIf EndSwitch Local $aKeys = MapKeys($mKeys) Local $sOut = "" Local $sEdit = "" For $key In $aKeys $mKey = $mKeys[$key] $sOut &= ($sOut ? " + " : "") & "scanCode[" & $mKey.scanCode & "] vkCode[" & $mKey.vkCode & "] flags[" & $mKey.flags & "] time[" & $mKey.time & "] dwExtraInfo[" & Number($mKey.dwExtraInfo) & "]" $sEdit &= ($sEdit ? " + " : "") & $mKey.scanCode & "[" & $mKey.flags & "]" Next $cur = $mKey.scanCode & "|" & $mKey.flags ;prevent repeat If $prev <> $cur Then $prev = $cur GUICtrlSetData($gEdit, $sEdit) ConsoleWrite($sOut & @CRLF) EndIf EndIf Return _WinAPI_CallNextHookEx($hHookKeyboard, $nCode, $wParam, $lParam) EndFunc ;==>_KeyProc Func onClose() Exit EndFunc ;==>onClose Func onExit() DllCallbackFree($pStub_KeyProc) _WinAPI_UnhookWindowsHookEx($hHookKeyboard) EndFunc ;==>onExit get a list of pressed keys on demand. I only know GetKeyboardState method, but it doesn't work with Shift + Num nn keys, so it's bust: Spoiler expandcollapse popup#include <GUIConstantsEx.au3> #include <EditConstants.au3> Opt("GUIOnEventMode", 1) OnAutoItExitRegister("onExit") Global $hUser32 = DllOpen("user32.dll") Global $hGui = GUICreate("test", 200, 50) Global $gEdit = GUICtrlCreateEdit("", -1, -1, -1, -1, $ES_READONLY) GUISetOnEvent($GUI_EVENT_CLOSE, "onClose") GUISetState() Local $sPrev While 1 $sResult = _WhatPressed() If $sPrev <> $sResult Then $sPrev = $sResult GUICtrlSetData($gEdit, $sResult) EndIf Sleep(10) WEnd Func _WhatPressed() Local Static $tOut = DllStructCreate("byte[256]") Local Static $iState DllCall($hUser32, "int", "GetKeyboardState", "ptr", DllStructGetPtr($tOut)) Local $sResult = "" For $i = 1 To 256 $iState = DllStructGetData($tOut, 1, $i) If BitAND($iState, 128) Then $sResult = $sResult & ($sResult ? " + " : "") & $i - 1 & "[" & $iState & "]" EndIf Next Return $sResult EndFunc ;==>_WhatPressed Func onClose() Exit EndFunc ;==>onClose Func onExit() DllClose($hUser32) EndFunc ;==>onExit Maybe someone could help me figure out how to fix these issues? Thank you Link to comment Share on other sites More sharing options...
Nine Posted January 2 Share Posted January 2 For #1 here my take on shift + num 0 (both are hardcoded but you will get the idea) : Func WH_KEYBOARD($iMsg, $wParam, $lParam) Local Static $bShiftDown = False If $iMsg Then Return _WinAPI_CallNextHookEx($hHook, $iMsg, $wParam, $lParam) Local $bUP = BitAND($lParam, 0x80000000) <> 0 Local $iScanCode = BitAND(_WinAPI_HiWord($lParam), 0x00FF) Local $bExt = BitAND($lParam, 0x01000000) <> 0 Local $bState = BitAND($lParam, 0x40000000) <> 0 If $wParam = 16 Then If $bUP Then $bShiftDown = False ConsoleWrite("shift up" & @CRLF) Else If Not $bShiftDown Then $bShiftDown = True ConsoleWrite("shift down" & @CRLF) EndIf EndIf EndIf If $wParam = 45 And Not $bUP Then $bShiftDown = True ConsoleWrite("shift down" & @CRLF) ConsoleWrite("shift is pressed on num 0" & @CRLF) EndIf ConsoleWrite( _ "Virtual Key = " & $wParam & @TAB & _ "Scan Code = " & $iScanCode & @TAB & _ "Is Up = " & $bUP & @TAB & _ "State = " & $bState & @TAB & _ "Is Ext = " & $bExt & @CRLF) Return _WinAPI_CallNextHookEx($hHook, $iMsg, $wParam, $lParam) EndFunc ;==>MyProc ps. as I said on another thread, rely on vkey to determine if shift is pressed or not with num keys. “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...
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