(HID) Human Interface Device Communications in XP
#1
Posted 16 May 2009 - 02:24 AM
I have a 3dConnexion SpaceNavigator for my WindowsXP SP3 system. It's installed as a HID compliant device (ID: HID\VID_046D&PID_C626).
I'd like to write an AutoIt program that will read from this device (or possibly others) to programmatically control other things. Has someone written a function to talk to HID devices yet? I was thinking 'MSDN -> User Input/Raw Input' might be a good starting point, but I'm not good with translating C#/VB code to AutoIt.
Any help would be greatly appreciated.
Thanks,
-Trystian
#2
Posted 16 May 2009 - 11:17 AM
#include <Array.au3> #include <Array.au3> #include "RawInput.au3" #include <WinAPI.au3> ; For _WinAPI_GetLastError() and _WinAPI_GetLastErrorMessage() functions. Dim $tRIDL, $pRIDL, $iRIDL Dim $tBuff, $pBuff, $tszBuff, $pszBuff Dim $iRet, $iNumDevices = 0, $iSize = 0 Dim $tagRIDL = '' Dim $aDevices[1][2] $tRIDL = DllStructCreate($tagRAWINPUTDEVICELIST) $iRIDL = DllStructGetSize($tRIDL) Dim $iRet = _GetRawInputDeviceList(0, $iNumDevices, $iRIDL) If Not @error And $iNumDevices > 0 Then ReDim $aDevices[$iNumDevices][2] For $i = 1 To $iNumDevices $tagRIDL &= StringRegExpReplace($tagRAWINPUTDEVICELIST, '(\w+);', '${1}' & $i & ';') Next $tBuff = DllStructCreate($tagRIDL) $pBuff = DllStructGetPtr($tBuff) $iRet = _GetRawInputDeviceList($pBuff, $iNumDevices, $iRIDL) For $i = 1 To $iNumDevices $aDevices[$i-1][0] = DllStructGetData($tBuff, 'hDevice' & $i) $aDevices[$i-1][1] = DllStructGetData($tBuff, 'dwType' & $i) Next _ArrayDisplay($aDevices) For $i = 0 To $iNumDevices-1 $iRet = _GetRawInputDeviceInfo($aDevices[$i][0], $RIDI_DEVICENAME, '', $iSize) If $iSize > 0 Then $tszBuff = DllStructCreate('wchar[' & $iSize & ']') $pszBuff = DllStructGetPtr($tszBuff) $iRet = _GetRawInputDeviceInfo($aDevices[$i][0], $RIDI_DEVICENAME, $pszBuff, $iSize) ConsoleWrite(DllStructGetData($tszBuff, 1) & @LF) EndIf Next $tszBuff = 0 $tBuff = 0 EndIf
There are still a few things to workout with the error codes and when a function should set @error macro at all but anyway I hope you get the idea and the structures things. When you see something like $tagRAWINPUT_* the asterisk means that there are three -same size- structure for each raw input device, because of the union thing in structures but it could be worse if it was a 50-100 lines or so for one giant commented structure section which might make it more confusing.
Maybe you'll come up with something more handy because I have no use for this functions as I have only a mouse and a keyboard and SendInput would sufficient.
Edit: Corrected the array built using StringRegExpReplace...
Edit2: Corrected _RegisterRawInputDevices().
Edit3: Corrected _GetRawInputDeviceInfo() function description when used with flag $RIDI_DEVICEINFO.
Edit4: Corrected _GetRawInputData() returned error value to be meaningful.
Attached Files
Edited by Authenticity, 24 May 2009 - 06:25 PM.
#3
Posted 17 May 2009 - 07:32 PM
I'm trying to find a way to do this and determine the device sending the keystroke.
Thanks,
Kenny
#include <WinAPI.au3> Global $sHexKeys, $sMouse, $sString, $hHookKeyboard, $pStub_KeyProc HotKeySet("{F3}", "ExitNow");0x72 $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 ExitNow() Exit EndFunc Func OnAutoITExit() DllCallbackFree($pStub_KeyProc) _WinAPI_UnhookWindowsHookEx($hHookKeyboard) EndFunc Func _KeyProc($nCode, $wParam, $lParam) If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hHookKeyboard, $nCode, $wParam, $lParam) Local $KBDLLHOOKSTRUCT = DllStructCreate("dword vkCode;dword scanCode;dword flags;dword time;ptr dwExtraInfo", $lParam) Local $vkCode = DllStructGetData($KBDLLHOOKSTRUCT, "vkCode") If $vkCode <> 0x72 Then Return 1 _WinAPI_CallNextHookEx($hHookKeyboard, $nCode, $wParam, $lParam) EndFunc
#4
Posted 17 May 2009 - 08:33 PM
#5
Posted 17 May 2009 - 08:35 PM
both send keyboard events and windows see's them as a keyboard.
so if I disable codes on one device it disabled the other.
I'm trying to get it setup so that my remote still works.
#6
Posted 17 May 2009 - 09:04 PM
I can just set a key is hit on my actual keyboard I perform an event EXCEPT when it is F3
In this case the event will be locking the computer
F3 will be a hotkey to enable the keyboard
So I really just need an example to pickup the device ID and key using a dll callback or something
Kenny
Edited by ken82m, 17 May 2009 - 09:15 PM.
#7
Posted 17 May 2009 - 09:57 PM
Give me I few minutes I'll post the code to get $WM_INPUT from your desired device but because I have no other devices other than mouse and keyboard I have nothing to test it with so I need you to help me. ;] Again, sorry for the long wait.
#8
Posted 17 May 2009 - 10:21 PM
You must be getting sick of me and my keyboard hooks lol
This is actually something completely different.
The one you helped me with the other day worked perfect.
#9
Posted 17 May 2009 - 10:32 PM
#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseUpx=n #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <RawInput.au3> #include <WinAPI.au3> HotKeySet('{ESC}', '_EXIT') Global $tRID_KD, $pRID_KD, $iRID_KD Global $tRIH, $iRIH Global $iNumDevices Global $hGUI $hGUI = GUICreate('Test', 100, 100) GUIRegisterMsg($WM_INPUT, 'OnInput') $tRID_KD = DllStructCreate($tagRAWINPUTDEVICE) $pRID_KD = DllStructGetPtr($tRID_KD) $iRID_KD = DllStructGetSize($tRID_KD) $tRIH = DllStructCreate($tagRAWINPUTHEADER) $iRIH = DllStructGetSize($tRIH) $iNumDevices = 1 DllStructSetData($tRID_KD, 'usUsagePage', 0x01) DllStructSetData($tRID_KD, 'usUsage', 0x06) DllStructSetData($tRID_KD, 'dwFlags', BitOR($RIDEV_NOLEGACY, $RIDEV_INPUTSINK)) DllStructSetData($tRID_KD, 'hwndTarget', $hGUI) _RegisterRawInputDevices($pRID_KD, $iNumDevices, $iRID_KD) While 1 Sleep(20) WEnd GUIDelete() Func OnInput($hwnd, $iMsg, $iwParam, $ilParam) Local $tRI_KD, $pRI_KD, $iRI_KB Local $iSize $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD) $pRI_KD = DllStructGetPtr($tRI_KD) $iRI_KB = DllStructGetSize($tRI_KD) _GetRawInputData($ilParam, $RID_INPUT, $pRI_KD, $iRI_KB, $iRIH) If Not @error Then ConsoleWrite(DllStructGetData($tRI_KD, 'Message') & @LF) ConsoleWrite(DllStructGetData($tRI_KD, 'VKey') & @LF) EndIf $tRI_KD = 0 Return 'GUI_RUNDEFMSG' EndFunc Func _EXIT() GUIDelete() Exit EndFunc
Edit: Also, can you run the previous script and post the output?
Edited by Authenticity, 17 May 2009 - 10:47 PM.
#10
Posted 17 May 2009 - 11:13 PM
So it looks like that function is never getting called
Kenny
Edited by ken82m, 17 May 2009 - 11:13 PM.
#11
Posted 17 May 2009 - 11:20 PM
\\?\HID#SaitekHotKeys#2&150b6877&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} \\?\HID#HpqRemHidDevice&Col02#5&2f051232&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} \\?\HID#HpqRemHidDevice&Col01#5&2f051232&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} \\?\Root#RDP_KBD#0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} \\?\HID#SaitekKeyboard#2&1d46170d&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} \\?\HID#HpqRemHidDevice&Col03#5&2f051232&0&0002#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} \\?\ACPI#PNP0303#4&ef0d0fe&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} \\?\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd} \\?\HID#SaitekMouse#2&7fd572c&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd} \\?\ACPI#SYN0138#4&ef0d0fe&0#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
It should be one of the two "HpqRemHidDevice" but I'm not sure which one.
Kenny
#12
Posted 17 May 2009 - 11:30 PM
Edit:
Edited by Authenticity, 17 May 2009 - 11:36 PM.
#13
Posted 17 May 2009 - 11:46 PM
Output from right arrow on keyboard
256
39
257
39
Output from right arrow on remote
256
39
257
39
Edited by ken82m, 17 May 2009 - 11:55 PM.
#14
Posted 18 May 2009 - 01:09 AM
So that will give me the key info I need.
I tried changing " $iNumDevices = 1 " to another number.
I figured that was how I specified the device to check?
1 is the only option that returns any output, and it returns both devices.
hmm, Is there any other info that can be returned that might help?
Thanks,
Kenny
#15
Posted 18 May 2009 - 01:15 AM
It has some sample code to download.
http://msdn.microsoft.com/en-us/library/ms...tdevices_topic5
EDIT: This part looked interesting
rid[0].usUsagePage = 0xFFBC; // adds HID remote control rid[0].usUsage = 0x88; rid[0].dwFlags = RIDEV_INPUTSINK; rid[0].hwndTarget = this.Handle; rid[1].usUsagePage = 0x0C; // adds HID remote control rid[1].usUsage = 0x01; rid[0].dwFlags = RIDEV_INPUTSINK; rid[0].hwndTarget = this.Handle; rid[2].usUsagePage = 0x0C; // adds HID remote control rid[2].usUsage = 0x80; rid[0].dwFlags = RIDEV_INPUTSINK; rid[0].hwndTarget = this.Handle;
Edited by ken82m, 18 May 2009 - 01:17 AM.
#16
Posted 18 May 2009 - 01:28 AM
#include <Array.au3> #include <RawInput.au3> Dim $tRIDL, $iRIDL Dim $tBuff, $pBuff Dim $iNumDevices, $iSize Dim $tagRIDL Dim $aKBDevices[1] = [0] $tRIDL = DllStructCreate($tagRAWINPUTDEVICELIST) $iRIDL = DllStructGetSize($tRIDL) _GetRawInputDeviceList(0, $iNumDevices, $iRIDL) If Not @error And $iNumDevices > 0 Then $tagRIDL = '' For $i = 0 To $iNumDevices-1 $tagRIDL &= StringRegExpReplace($tagRAWINPUTDEVICELIST, '(\w+);', '${1}' & $i & ';') Next $tBuff = DllStructCreate($tagRIDL) $pBuff = DllStructGetPtr($tBuff) _GetRawInputDeviceList($pBuff, $iNumDevices, $iRIDL) If Not @error Then For $i = 0 To $iNumDevices-1 If DllStructGetData($tBuff, 'dwType' & $i) = $RIM_TYPEKEYBOARD Then $aKBDevices[0] += 1 ReDim $aKBDevices[$aKBDevices[0]+1] $aKBDevices[$aKBDevices[0]] = DllStructGetData($tBuff, 'hDevice' & $i) EndIf Next EndIf _ArrayDisplay($aKBDevices) EndIf
Then compare them to the $ilParam, I might be wrong so in case $ilParam is just a handle to $tagRAWINPUT_* then you can check the handle of the $tagRAWINPUTHEADER of the $tagRAWINPUT_KEYBOARD structure in $WM_INPUT handler. A little bit of reading. ;]
#17
Posted 18 May 2009 - 03:38 AM
This is my output in the array of devices.
[0]|4
[1]|0x00010045
[2]|0x00010043
[3]|0x00010041
[4]|0x000B003F
I've been playing around with trying to read that info from $lparam with no success.
I've does a good job getting some 0's lol
Can i have a hint lol
#18
Posted 18 May 2009 - 03:56 AM
Func OnInput($hwnd, $iMsg, $iwParam, $ilParam) Local $tRI_KD, $pRI_KD, $iRI_KB Local $iSize $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD) $pRI_KD = DllStructGetPtr($tRI_KD) $iRI_KB = DllStructGetSize($tRI_KD) _GetRawInputData($ilParam, $RID_INPUT, $pRI_KD, $iRI_KB, $iRIH) If Not @error Then ConsoleWrite(DllStructGetData($tRI_KD, 'Message') & @LF) ConsoleWrite(DllStructGetData($tRI_KD, 'VKey') & @LF) ConsoleWrite(DllStructGetData($tRI_KD, 'hDevice') & @LF) EndIf $tRI_KD = 0 Return 'GUI_RUNDEFMSG' EndFunc
$tagRAWINPUTHEADER is a member struct of the $tagRAWINPUT_* structs. See which handle match to the keyboard and which to the remote and compare them using the array. You can then ignore the remote and process only the keyboard inputs.
Edit: Here, if you still don't have or whatever: ;]
_DefRawInputProc ("$paRawInput, $iInputs, $iSizeHeader[, $hDll = 'user32.dll']") Calls the default raw input procedure to provide default processing for any raw input messages that an (required: #include <RawInput.au3>) _GetRawInputBuffer ("$pData, ByRef $iSize, $iSizeHeader[, $hDll = 'user32.dll']") Does a buffered read of the raw input data. (required: #include <RawInput.au3>) _GetRawInputData ("$hRawInput, $iCommand, $pData, ByRef $iSize, $iSizeHeader[, $hDll = 'user32.dll']") Gets the raw input from the specified device. (required: #include <RawInput.au3>) _GetRawInputDeviceInfo ("$hDevice, $iCommand, $pData, ByRef $iSize[, $hDll = 'user32.dll']") Gets information about the raw input device. (required: #include <RawInput.au3>) _GetRawInputDeviceList ("$pRawInputDeviceList, ByRef $iNumDevices, $iSize[, $hDll = 'user32.dll']") Enumerates the raw input devices attached to the system. (required: #include <RawInput.au3>) _GetRegisteredRawInputDevices ("$pRawInputDevices, ByRef $iNumDevices, $iSize[, $hDll = 'user32.dll']") Gets the information about the raw input devices for the current application. (required: #include <RawInput.au3>) _RegisterRawInputDevices ("$pRawInputDevices, ByRef $iNumDevices, $iSize[, $hDll = 'user32.dll']") Registers the devices that supply the raw input data. (required: #include <RawInput.au3>)
.. add to au3.user.calltips.api
Edited by Authenticity, 18 May 2009 - 04:03 AM.
#19
Posted 18 May 2009 - 04:30 AM
ConsoleWrite(DllStructGetData($tRI_KD, 'hDevice') & @LF)
I finally understand how these tags now. I had always scratched 'em up to one of those mysteries lol
Reading all the comments in that UDF don't give me a headache anymore lol
Thanks alot for all the time you put in on this!
#20
Posted 18 May 2009 - 05:16 AM
So much for that one I guess.
And to think Microsoft built this damn remote.
Source-
ConsoleWrite(DllStructGetData($tRI_KD, 'Message') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'VKey') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'hDevice') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'dwType') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'MakeCode') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'Flags') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'Reserved') & @CR)
ConsoleWrite(DllStructGetData($tRI_KD, 'ExtraInformation') & @CR & @CR)
Keyboard
256
39
0x000B003F
1
77
2
0
0
257
39
0x000B003F
1
77
3
0
0
Remote
256
39
0x000B003F
1
77
2
0
0
257
39
0x000B003F
1
77
3
0
0
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users





