MrB wrote:
I never worked with RegisterRawInputDevices or GetRawInputData commands. Could you post an example for me?
I hastily put this together when I was trying to detect my mouse's wheel tilt. It should show input from keyboards, mice or raw devices. You'll still need Micha's script to find the Usage and UsagePage (except for the keyboard and mouse, which I think are consistently 6,1 / 2,1.)
Code:
#NoEnv
; Disable this line if you're running from an editor that catches StdOut
; (like PSPad or SciTE.)
DllCall("AllocConsole")
DetectHiddenWindows, On
Process, Exist
hwnd := WinExist("ahk_class AutoHotkey ahk_pid " ErrorLevel)
DetectHiddenWindows, Off
OnMessage(0xFF, "WM_INPUT")
; 6, 1 = keyboard
; 2, 1 = mouse
Usage = 6
UsagePage = 1
VarSetCapacity(dev, 12, 0)
NumPut(UsagePage, dev, 0, "UShort")
NumPut(Usage, dev, 2, "UShort")
NumPut(0x100, dev, 4) ; dwFlags = RIDEV_INPUTSINK (don't require foreground)
NumPut(hwnd, dev, 8)
ret := DllCall("RegisterRawInputDevices"
, "uint", &dev ; pRawInputDevices (pointer to an array of RAWINPUTDEVICE)
, "uint", 1 ; uiNumDevices
, "uint", 12) ; cbSize (size of a RAWINPUTDEVICE structure)
if (ErrorLevel or !ret) {
MsgBox, RegisterRawInputDevices failed.
ExitApp
}
return
WM_INPUT(wParam, lParam)
{
Critical
; foreground := ! (wParam & 0xFF)
; Get required buffer size.
DllCall("GetRawInputData", "uint", lParam, "uint", 0x10000003
, "uint", 0, "uint*", size, "uint", 16)
VarSetCapacity(raw, size, 0)
; Get raw input data from handle (lParam)
ret := DllCall("GetRawInputData", "uint", lParam, "uint", 0x10000003
, "uint", &raw, "uint*", size, "uint", 16, "int")
if (ErrorLevel or ret = -1) {
StdOut("GetRawInputData -- Error " ErrorLevel " LA " A_LastError)
return
}
type := NumGet(raw)
; #define RIM_TYPEMOUSE 0
; #define RIM_TYPEKEYBOARD 1
; #define RIM_TYPEHID 2
hDevice := NumGet(raw, 8)
if type = 1 ; RIM_TYPEKEYBOARD
{
SetFormat, INTEGER, H
sc := NumGet(raw, 16, "UShort")
flags := NumGet(raw, 18, "UShort")
vk := NumGet(raw, 22, "UShort")
msg := NumGet(raw, 24, "UInt") ; WM_KEYDOWN, WM_SYSKEYDOWN, etc.
vk_a := SubStr(vk, 3)
sc_a := SubStr(sc, 3)
StringUpper, vk_a, vk_a
StringUpper, sc_a, sc_a
if (StrLen(vk_a)<2)
vk_a = 0%vk_a%
sc_a := ((flags & 2) ? "1" : "0") . (StrLen(sc_a)<2 ? "0" : "") . sc_a
act := (flags & 1) ? "up" : "dn"
StdOut(vk_a " " sc_a " " act " msg: " msg " flags: " flags " dev: " hDevice)
}
else if type = 2 ; RIM_TYPEHID
{
SetFormat, INTEGER, H
count := NumGet(raw, 20) ; dwCount
if count > 1
StdOut("dev: " hDevice)
n = 0
Loop, %count%
{
size := NumGet(raw, 16) ; dwSizeHid
VarSetCapacity(hex, size*3)
Loop, %size%
{
char := SubStr(NumGet(raw, 24+n+A_Index-1, "UChar"), 3)
StringUpper, char, char
if (StrLen(char) < 2)
char = 0%char%
hex = %hex% %char%
}
n += size
if !size
hex = "--"
StdOut((count=1 ? "dev: " hDevice " -- " : "") hex)
}
}
else if type = 0 ; RIM_TYPEMOUSE
{
lastX := NumGet(raw, 28, "int")
lastY := NumGet(raw, 32, "int")
delta := NumGet(raw, 22, "Short") ; usButtonData
SetFormat, INTEGER, H
flags := NumGet(raw, 16, "UShort") ; usFlags
btnfl := NumGet(raw, 20, "UShort") ; usButtonFlags
StdOut("dev: " hDevice " flags: " flags " x" lastX " y" lastY " btnfl: " btnfl " delta: " delta)
}
}
StdOut( text )
{
static hStdOut=-1
if (hStdOut = -1)
{
hStdOut := DllCall("GetStdHandle", "UInt", -11) ; -11=STD_OUTPUT_HANDLE
if ErrorLevel
return -1
}
text .= "`n"
ret := DllCall("WriteFile"
, "UInt", hStdOut ; hFile
, "UInt", &text ; lpBuffer
, "UInt", StrLen(text) ; nNumberOfCharsToWrite
, "UIntP", bytesWritten ; lpNumberOfCharsWritten
, "UInt", 0) ; lpOverlapped
return bytesWritten
}
It turns out the mouse hook supports "WM_MOUSEHWHEEL" (Vista-only), so I didn't use WM_INPUT. Actually, WM_INPUT can't seem to pick up the wheel tilt on Windows XP (I'm on Vista.) It shows mouse messages, but all the "tilt" messages are empty...
Quote:
Right, but only to some extend since many special keys cannot be detected by autohotkey. And is a standard really important?
Yes - raw HID data is sent as a blob of binary data. For instance, one of the devices associated with my mouse sends "03 00 00 E2 00" for mute, "03 00 00 E9 00" for volume up, but "03 BC 01 E9 00" if I was already holding the chat button. It's not a simple "pressed/released this button" message, so adding generic support for it to AutoHotkey would be difficult.
Can you give me an example of a "special key"? My keyboard has no keys that AutoHotkey doesn't pick up (except for a Function lock key which can't be picked up via WM_INPUT either.)
When a keyboard is registered for raw input, the WM_INPUT messages contain the scancode (aka MakeCode) and vk code of the key. This lead me to believe the keyboard hook should be able to pick up everything that WM_INPUT picks up for a keyboard device. With your "special keys", does WM_INPUT show a MakeCode/scancode? If so, are you sure the keyboard hook doesn't pick it up?
I wrote:
How should HID support should work for such devices?
Perhaps more importantly, how would you identify a button on the device, or the device itself?
Quote:
Quote:
It isn't possible (via registered input/HID support) to prevent the keystrokes from a specific keyboard from being sent to the active window.
Then I do not understand why you always have to select the HID device to listen to...
You've lost me... how is that related? Windows doesn't send the WM_INPUT messages by default, since applications generally don't need them. That is why you "have to select the HID device to listen to." WM_INPUT doesn't allow you to block the input messages from the system, but it does allow you to determine which device sent the message.