Native HID support
Either you have to have the vendors software running wasting your system resources if you want to make use of the additional keys. Or you can use Michas dll which is quite dificult to set up and also requires additional resources.
That's why I propose a native HID support in autohotkey. Allthough I do not know ho difficult that is...
A more friendly script wrapper could be written. What kind of features/interface/usage would you expect? You still need to know the Usage and UsagePage of the device, which is where Micha's script comes in handy. (That could also be rewritten, but there's not much sense reinventing the wheel.)
From what I've seen, the only devices with data in a standard format are keyboards and mice, which are already supported via the keyboard/mouse hooks. Raw HID data has to be interpreted differently depending on the device.
For instance, my Logitech MX610 has one mouse device and one HID. All functions reported by the mouse device are supported by the mouse hook, except for the wheel tilt (horizontal scroll). Bytes 2 and 3 of the HID data seem to correspond to the e-mail (8A 01) and chat (BC 01) buttons, and byte 4 corresponds to volume up (E9), volume down (EA), and mute (E2). Button press and release can both be detected, as long as you only press one button from each group at a time (i.e. chat and volume work together, but chat and e-mail conflict.)
How should HID support should work for such devices? What would be easier if it were built into AutoHotkey?
Could this be done with HID support.
I suppose you could block all physical key events using a keyboard hook, and redirect input from a specific keyboard by using registered input...
That is interesting news. I never worked with RegisterRawInputDevices or GetRawInputData commands. Could you post an example for me?I recently discovered that Micha's dll is not actually required. RegisterRawInputDevices() registers the window to receive WM_INPUT messages, then the WM_INPUT handler uses GetRawInputData() and NumGet() to get the data of the message.
Right, but only to some extend since many special keys cannot be detected by autohotkey. And is a standard really important? As long as you can see each HID button in the key history, you can assign actions to them.the only devices with data in a standard format are keyboards and mice, which are already supported via the keyboard/mouse hooks
Simply put: So that there is as little difference to "normal" keys. Means: You have a command to enable HID support or even better, HID support is automatically enabled on all devices and you can manually disable it for some devices.How should HID support should work for such devices? What would be easier if it were built into AutoHotkey?
And of course: implement a key detection in the key history.
Do you know girder? There is a hid plugin. You turn it on, select the HID device to accept commands from and after these two steps, the user won't see a difference...
Then I do not understand why you always have to select the HID device to listen to...It isn't possible (via registered input/HID support) to prevent the keystrokes from a specific keyboard from being sent to the active window.
Again, I am knowbody to judge how difficult implementation would be. The girder example shows that its possible...
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.)I never worked with RegisterRawInputDevices or GetRawInputData commands. Could you post an example for me?
#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...
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.Right, but only to some extend since many special keys cannot be detected by autohotkey. And is a standard really important?
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?
Perhaps more importantly, how would you identify a button on the device, or the device itself?How should HID support should work for such devices?
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.Then I do not understand why you always have to select the HID device to listen to...It isn't possible (via registered input/HID support) to prevent the keystrokes from a specific keyboard from being sent to the active window.
You have to register a device so windows sends you the desired data but I have not found a way to block input for other applications. If 10 applications have registered a device, each will receive the data. HID devices are just not keys
Of course my dll is not needed at all. You can achive the same results with lots of dllcalls and NumGet-calls. The dll is just calling the api. I've written the dll, because I can wrap a lot of stuff inside the dll and exposing only the needed functions. But it can be done without a dll, that's true.
Integrating HID-devices into ahk: You can't use it with Windows 98 / 2000.
Perhaps Chris has to compile and test 2 versions. One with HID support and one for older systems without HID-Support. (If I'm the devloper I wouldn't like to do it)
Perhaps more and more people are using HID-devices, but how many ahk-users will do it? The autohotkey.exe will definitly grow in size and will need more space at runtime.
The data received is not like a key. The data is binary and could be 4000500640 or even AA3356BC45FE657664A4E5B65D456F456E54AA5004000EE00412AA.
So at the moment, you can use a dll or include a script with the functions.
Ciao
Micha
Thanks for the script. That is exactly why I started the discussion - as a lets say average user of autohotkey looking over your script I find it dificult to implement for myself. That's why I am calling for simple commands also the unexperienced user can use.
I am using am Logitech S 510 cordless keyboard. It has a F-Mode button that switches the layout of the F1-F12 keys from normal function to special ie programable funtions. Autohotkey does detect the normal F1-F12 but after the F Mode button is pressed (ie special functions activated) none of F1-F12 are recognized.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.)
With Michas skript or girder HID plugin these keys are detected and give scancodes like 4854564851 or 4854555555.
Sorry... perhaps I was unprecise or I misunderstood the concept. With girders HID plugin you have to select the device you are listening to. Thats why I assumed you get only messages from the device selected and that allows you to use different layouts with different devices.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.
@Micha
Isn't it rather the question how many ahk-users are not using it because it is difficult to use. Sorry, I don't want to put your efforts down at all - but you have to recognize that for a normal user it is quite a big step 1) to understand that HID support is needed, 2) get information on a possible solution in the forum, 3) locate your dll solution or lexikos script, 4) understand it and 5) implement it in your own ahk startup script.Perhaps more and more people are using HID-devices, but how many ahk-users will do it?
That isn't surprising. I wrote that script solely to determine what was possible with raw input via the script. It was never intended for any real use.looking over your script I find it dificult to implement for myself
Interesting. My Logitech EX110 (cheap cordless multimedia keyboard) has an F-lock key, but it can't be detected by registered input. When F-lock is off, my F1-F12 keys have the "extended flag" set. For instance, F1 is normally SC03B. With F-lock off, it's SC13B.I am using am Logitech S 510 cordless keyboard. It has a F-Mode button that switches the layout of the F1-F12 keys from normal function to special ie programable funtions. Autohotkey does detect the normal F1-F12 but after the F Mode button is pressed (ie special functions activated) none of F1-F12 are recognized.
4854564851 and 4854555555 are impossible scancodes, barring errors. MakeCode (aka scancode) is a USHORT - i.e. its entire range of values is 0 to 0xFFFF (65535).With Michas skript or girder HID plugin these keys are detected and give scancodes like 4854564851 or 4854555555.
Scancodes are normally between 0 and 0x7F (127). (AutoHotkey adds 0x100 if the extended key flag is set.) I suppose keys outside the normal range might be reported via WM_INPUT but not the keyboard hook.
The only way to register a keyboard for raw input is by registering Usage=6, UsagePage=1. This registers all keyboards. It is possible to determine which device a WM_INPUT message came from, though.Thats why I assumed you get only messages from the device selected and that allows you to use different layouts with different devices.
I've updated the script in my previous post to also output the flags of the WM_INPUT message, since they may be important. If the script can detect your "special" keys, please copy the output and post it here. You can normally copy text from a console window by right-clicking, clicking Select All, then right-clicking again. Strangely, the context menu doesn't seem to work with that script (for me?), but you can still access it via the window's system menu, and "Edit". After you've posted the output of your keys, I might try to write a more user-friendly script...
That's what I was thinking, but (raw) keyboard devices do report data in a consistent format. If raw input reports keys that the keyboard hook doesn't, it might be worth writing a more user-friendly script to catch them.The data received is not like a key. The data is binary and could be 4000500640 or even AA3356BC45FE657664A4E5B65D456F456E54AA5004000EE00412AA.
Lots?Of course my dll is not needed at all. You can achive the same results with lots of dllcalls and NumGet-calls.
There is one function on my mouse that I couldn't program without raw input: the chat button. I'm currently using:[*:1jl4aaex]Four NumPut() calls to prepare the structure for RegisterRawInputDevices().
[*:1jl4aaex]DllCall("RegisterRawInputDevices"...) once.
[*:1jl4aaex]GetRawInputData() twice (once to get the required buffer size, once to get the data) per WM_INPUT message.
[*:1jl4aaex]Four calls to NumGet() per WM_INPUT message.If I assumed that no other devices would ever be registered by the script (a fair assumption), I could remove the first GetRawInputData() and three of the NumGet() calls, since my device always sends the same amount and format of data. That would leave one DllCall and one NumGet() per WM_INPUT message.
So no, that isn't lots. :lol:
For me, your wrapper exposes more than the needed functions.I've written the dll, because I can wrap a lot of stuff inside the dll and exposing only the needed functions.
(Btw, I imagine writing the dll might've been easier, since you don't need to worry about offsets in structs, etc. as C++ has good struct support...)
I've changed the script-section when RAW-InputData is received. The old script had the following bug: The dllcall returned the raw data4854564851 and 4854555555 are impossible scancodes, barring errors. MakeCode (aka scancode) is a USHORT - i.e. its entire range of values is 0 to 0xFFFF (65535).
001020 (hex)
When displaying the value, each number was interpreted wrong by the script. The number was converted automatically. Binary 1 was converted to the numer one and was displayed as 49. Each number was converted to the corresponding ascii value (0=48 1=49 1=50 ...)
So the value 001020 gets translated into 00 00 49 00 51 00 which is wrong. I've changed the script to display the correct value 00 10 20 but it's possible i've missed the mouse and keyboard section. So the correct value for the number mentioned above is 00 06 08 00 02
I'll have a look at the script.
You're right, the dll-calls are almost equal to the windows api or my dll. If you know the device sending you the data (mouse, keyboard, raw) you do not have to call a lot of api-functions, but if you have registered all devices, you have to get infos about the type (1), the devicenumber (2).Lots? (dll calls)
It depends on the device type what struct you have to prepare and after another dll call you have to get the result out of that struct.
As I said, everything can be done within ahk (without a dll) but I (personally) found it easier to write a dll (which can be debugged) than using tons (ok, not sooo much) ExtractIntegers (NumGet wasn't part of ahk that time) and testing the script for hours :-)
I've written 3 or 4 dlls for autohotkey and I've missed to write functions to wrap the dllcall. I've heard it not the first time, that the /or the other dll is difficult to use.Isn't it rather the question how many ahk-users are not using it because it is difficult to use.
I see.... I have to spent more time to present it the right way.
After trying something new every time with every new dll, I was glad that it was working and I've started to work on new things. In the future I'll spent more time on the decoration of the dll calls :-)
Ciao
Micha
I would if I could. Running the script, I don't get output for the mentioned F Mode keys. (F1-F12 after pressing F Mode).If the script can detect your "special" keys, please copy the output and post it here.
What do I make out of this? I used this script http://www.autohotke...l&highlight=hid and got these codes 4854564851 and 4854555555. Did you mind me using the word scancodes or is there more behind these lines I don't understand?4854564851 and 4854555555 are impossible scancodes, barring errors. MakeCode (aka scancode) is a USHORT - i.e. its entire range of values is 0 to 0xFFFF (65535).
Scancodes are normally between 0 and 0x7F (127). (AutoHotkey adds 0x100 if the extended key flag is set.) I suppose keys outside the normal range might be reported via WM_INPUT but not the keyboard hook.
So it should be possible to have different devices with different key assignments - which is what Superfraggle was asking.It is possible to determine which device a WM_INPUT message came from, though.
Right, those aren't scancodes, since that script doesn't register a keyboard device. It registers Usage=1, UsagePage=12. On my system, the only device that uses those values is a device used by my mouse to report its extra buttons.I used this script http://www.autohotke...l&highlight=hid and got these codes 4854564851 and 4854555555.
The script you linked to makes a couple mistakes, including starting at offset=1 instead of offset=0, and concatenating decimal values with inconsistent lengths (e.g. 101, 9 and 8 become "101908".) Actually, the data it seems to be reporting for my mouse is totally off... even after fixing those issues. :?
Since the device is not a standard keyboard device, it comes back to this:
The data received is not like a key. The data is binary and could be 4000500640 or even AA3356BC45FE657664A4E5B65D456F456E54AA5004000EE00412AA.
Yes, but the keys would still be seen by the system (like ~hotkeys.)So it should be possible to have different devices with different key assignments - which is what Superfraggle was asking.
Which script is that? Your HID-device-support script? Actually, part of the reason I wrote my own script was that your script was reporting a different value for the last byte of data each time I started the script. The rest of the data was fine...I've changed the script-section when RAW-InputData is received.
Yes, I can see why. A while ago I wrote a script to convert C struct definitions to NumGet() calls, so using NumGet and NumPut wasn't difficult. (I wrote the script after making numerous mistakes interpreting DEVMODE.)As I said, everything can be done within ahk (without a dll) but I (personally) found it easier to write a dll (which can be debugged) than using tons (ok, not sooo much) ExtractIntegers (NumGet wasn't part of ahk that time) and testing the script for hours
Btw, you should get raw data output from your F keys if you change the Usage to 1 and UsagePage to 12 (in the script I posted), assuming you didn't change the Usage & UsagePage in that Keyboard Media Keys script.I would if I could. Running the script, I don't get output for the mentioned F Mode keys.
True. I get the follwing "raw data output" starting with F1 to F12Btw, you should get raw data output from your F keys if you change the Usage to 1 and UsagePage to 12 (in the script I posted), assuming you didn't change the Usage & UsagePage in that Keyboard Media Keys script.
dev: 7996371 -- 03 41 10 00 00 ;F1
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 42 10 00 00;F2
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 43 10 00 00;F3
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 44 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 45 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 46 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 47 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 48 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 49 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 4A 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 4B 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 7996371 -- 03 4C 10 00 00
dev: 7996371 -- 03 00 00 00 00
dev: 131177 -- 03 00 00 E9 00 - vol up dev: 131177 -- 03 00 00 EA 00 - vol down dev: 131177 -- 03 00 00 E2 00 - mute dev: 131177 -- 03 8A 01 00 00 - email dev: 131177 -- 03 BC 01 00 00 - chat dev: 131177 -- 03 00 00 00 00 - none (all released)Perhaps it's a Logitech design? I guess they add that pseudo-device to report hardware events that aren't supported by the standard devices.