Jump to content

Recommended Posts

Posted

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

 

Posted (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 by Nine
Posted (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 by VAN0
Posted (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 by VAN0
Posted
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

 

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

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

 

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
  • Recently Browsing   0 members

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