Jump to content

(HID) Human Interface Device Communications in XP


Recommended Posts

Hello all,

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

Link to comment
Share on other sites

  • Replies 75
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

#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.

:)

RawInput.au3

Edited by Authenticity
Link to comment
Share on other sites

Is it possible to prevent certain keystrokes from getting through like I did using this keyboard hook.

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

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

I have a remote for media center and my regular keyboard.

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.

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Actually to make things easier I don't really need to block anything.

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

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Sorry for long delay, after a little of debugging I find the tiny miny problem that drove me crazy ;] because of the rush to get it to work I've passed one parameter to the _GetRawInputDevices() ByRef which should be then pass as uint* and got the same annoying error back which telling me Invalid Flags and this stuff....

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.

Link to comment
Share on other sites

sorry? hey I'm just happy to be getting the help :)

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.

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Here, tell me if you can see an output message when using your remote keyboard, I believe you will but who knows:

#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
Link to comment
Share on other sites

Nothing, I tried adding a msgbox to the begin of OnInput and it never comes up.

So it looks like that function is never getting called

Kenny

Edited by ken82m

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Sorry just saw your edit here's the output:

\\?\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

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Usually it is the first one. Can you explain what do you mean by nothing? The WM_INPUT is never called from both the connected and the remote keyboard?

Edit: Sorry, I've corrected the RawInput.au3 library but didn't upload the corrected one. In a minute. ;] Uploaded.

Edited by Authenticity
Link to comment
Share on other sites

Yeah, but it's being called now with the new UDF you uploaded. Here are the results

Output from right arrow on keyboard

256

39

257

39

Output from right arrow on remote

256

39

257

39

Edited by ken82m

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

So I guess 256 = key down , 257 = key up.

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

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

I found this on MSDN, it deals with HID remotes and RawInput.

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

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Yes, the first example on the page enumerates all the raw input devices on your machine (which is enumerate-able) and return the device type and the device handle. See what is the handles using the _ArrayDisplay() and compare to which one $ilParam in $WM_INPUT message is belong. You can build the array to contain only those devices of type keyboard $RIM_TYPEKEYBOARD. Example:

#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. ;]

Link to comment
Share on other sites

Well i tried but I give up, too many inputs I guess lol

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 :)

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Read the last complete code with the $WM_INPUT handler and extract the handle of the device sending the input using:

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
Link to comment
Share on other sites

Yeah as soon as I got to this in your post my it kicked my brain over.

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!

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

I guess it's a lost cause, I outputted everything I could find.

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

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

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

  • Recently Browsing   0 members

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