Jump to content

Catching WM_INPUT - hWnd not being set


Recommended Posts

I am working on some functionality to detect whether a standard keyboard was used for input in my UI or if a barcode scanner (that acts like a keyboard) was used. Instead of dealing with a scanner SDK, I decided I would read from the raw input to get device info and make a determination.

I discovered while testing with multiple UIs is that when the WM_INPUT message is received and the function called, the $hWnd param is always the same (apparently whatever handle I set the "hTarget" to in the RAWINPUTDEVICE struct).

Is this normal behavior??

Using the test code below, no matter what window you give input to the $hWnd param never changes.

#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <WinAPISys.au3>

$Form1 = GUICreate("Form 1", 300, 300, -1, 10)
ConsoleWrite("$Form1 = " & $Form1 & @CRLF)
$Edit1 = GUICtrlCreateEdit("", 0, 0, 300, 300)
GUISetState(@SW_SHOW, $Form1)

$Form2 = GUICreate("Form 2", 300, 300, -1, 350)
ConsoleWrite("$Form2 = " & $Form2 & @CRLF)
$Edit2 = GUICtrlCreateEdit("", 0, 0, 300, 300)
GUISetState(@SW_SHOW, $Form2)

GUIRegisterMsg($WM_INPUT, "WM_INPUT")          ; https://msdn.microsoft.com/en-us/library/ms645590(v=vs.85).aspx

$tRID = DllStructCreate($tagRAWINPUTDEVICE)    ; https://msdn.microsoft.com/en-us/library/ms645565(v=vs.85).aspx
DllStructSetData($tRID, "UsagePage", 1)
DllStructSetData($tRID, "Usage", 6)
DllStructSetData($tRID, "Flags", 0)
DllStructSetData($tRID, "hTarget", $Form1)     ; According to the struct def, if hTarget=NULL then it should follow keyboard focus. - nope :(

$pRID = DllStructGetPtr($tRID)
_WinAPI_RegisterRawInputDevices($pRID)         ; https://msdn.microsoft.com/en-us/library/ms645600(v=vs.85).aspx

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func WM_INPUT($hWnd, $iMsg, $wParam, $lParam)
  ConsoleWrite("hWnd = " & $hWnd & " | Title = " & WinGetTitle($hWnd) & @CRLF)
  ConsoleWrite("Active Window = " & WinGetTitle("[ACTIVE]") & @CRLF)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_INPUT

 

Link to comment
Share on other sites

IErrors, Yes, this is normal behaviour. $hWnd param of the WM_INPUT message reflects the window handle the message is send to. As mikell has already explained. Your WM_INPUT message handler should look like this:

Func WM_INPUT($hWnd, $iMsg, $wParam, $lParam)
  If $hWnd = WinGetHandle("[ACTIVE]") Then
    ConsoleWrite("hWnd = " & $hWnd & " | Title = " & WinGetTitle($hWnd) & @CRLF)
    ConsoleWrite("Active Window = " & WinGetTitle("[ACTIVE]") & @CRLF)
  EndIf
  Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_INPUT

 

GUIRegisterMsg is able to catch messages which are send to a GUI. If you set the value of hTarget parameter to null, the WM_INPUT messages are send directly to the control which has the keybord focus. In this case either $Edit1 or $Edit2. To catch these messages you have to use subclassing in this way:

#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <WinAPIShellEx.au3>
#include <WinAPISys.au3>

$Form1 = GUICreate("Form 1", 300, 300, -1, 10)
ConsoleWrite("$Form1 = " & $Form1 & @CRLF)
$Edit1 = GUICtrlCreateEdit("", 0, 0, 300, 300)
$hEdit1 = GUICtrlGetHandle( $Edit1 )
GUISetState(@SW_SHOW, $Form1)

$pEdit1Callback = DllCallbackGetPtr( DllCallbackRegister( "Edit1Callback", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) )
_WinAPI_SetWindowSubclass( $hEdit1, $pEdit1Callback, 9999, 0 )

$Form2 = GUICreate("Form 2", 300, 300, -1, 350)
ConsoleWrite("$Form2 = " & $Form2 & @CRLF)
$Edit2 = GUICtrlCreateEdit("", 0, 0, 300, 300)
$hEdit2 = GUICtrlGetHandle( $Edit2 )
GUISetState(@SW_SHOW, $Form2)

$pEdit2Callback = DllCallbackGetPtr( DllCallbackRegister( "Edit2Callback", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) )
_WinAPI_SetWindowSubclass( $hEdit2, $pEdit2Callback, 9998, 0 )

GUIRegisterMsg($WM_INPUT, "WM_INPUT")          ; https://msdn.microsoft.com/en-us/library/ms645590(v=vs.85).aspx

$tRID = DllStructCreate($tagRAWINPUTDEVICE)    ; https://msdn.microsoft.com/en-us/library/ms645565(v=vs.85).aspx
DllStructSetData($tRID, "UsagePage", 1)
DllStructSetData($tRID, "Usage", 6)
DllStructSetData($tRID, "Flags", 0)
;DllStructSetData($tRID, "hTarget", $Form1)     ; According to the struct def, if hTarget=NULL then it should follow keyboard focus. - nope :(
DllStructSetData($tRID, "hTarget", 0)          ; It indeed does follow keyboard focus

$pRID = DllStructGetPtr($tRID)
_WinAPI_RegisterRawInputDevices($pRID)         ; https://msdn.microsoft.com/en-us/library/ms645600(v=vs.85).aspx

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

_WinAPI_RemoveWindowSubclass( $Edit1, $pEdit1Callback, 9999 )
_WinAPI_RemoveWindowSubclass( $Edit2, $pEdit2Callback, 9998 )

Func WM_INPUT($hWnd, $iMsg, $wParam, $lParam)
  If $hWnd = WinGetHandle("[ACTIVE]") Then
    ConsoleWrite("hWnd = " & $hWnd & " | Title = " & WinGetTitle($hWnd) & @CRLF)
    ConsoleWrite("Active Window = " & WinGetTitle("[ACTIVE]") & @CRLF)
  EndIf
  Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_INPUT

Func Edit1Callback( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData )
  Switch $iMsg
    Case $WM_INPUT
      ConsoleWrite("Edit1Callback" & @CRLF)
      ConsoleWrite("    hWnd = " & $hWnd & " | Title = " & WinGetTitle($hWnd) & @CRLF)
      ConsoleWrite("    Active Window = " & WinGetTitle("[ACTIVE]") & @CRLF)
  EndSwitch

  ; Call next function in subclass chain
  Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0]
  #forceref $iSubclassId, $pData
EndFunc

Func Edit2Callback( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData )
  Switch $iMsg
    Case $WM_INPUT
      ConsoleWrite("Edit2Callback" & @CRLF)
      ConsoleWrite("    hWnd = " & $hWnd & " | Title = " & WinGetTitle($hWnd) & @CRLF)
      ConsoleWrite("    Active Window = " & WinGetTitle("[ACTIVE]") & @CRLF)
  EndSwitch

  ; Call next function in subclass chain
  Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0]
  #forceref $iSubclassId, $pData
EndFunc

 

Link to comment
Share on other sites

Thank you both Mikell & LarsJ!

I figured it had to do with the registered hTarget, but I wanted to make sure I wasn't doing it wrong.

I was able to get the active window and control handle in the message handler of my actual code - although very fumbly.

I hadn't thought of creating individual callbacks for each control - This is a great! Thank you for demonstrating the correct way of doing this.

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

×
×
  • Create New...