Jump to content

Get WH_KEYBOARD_LL events only in GUI window (or even specific GUI control)?


VAN0
 Share

Recommended Posts

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.

 

#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

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 by Nine
Link to comment
Share on other sites

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 by VAN0
Link to comment
Share on other sites

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 by VAN0
Link to comment
Share on other sites

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 by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

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

#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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...