Sign in to follow this  
Followers 0
boogieoompa

USB HID translation

13 posts in this topic

I am trying to write a script that will interface a HID (human interface device) into my PC by translating its functions. For example if a user presses the upper right button the device sends "page up". My goal was to write a script that effectivly says "this input came from device x change page up to shift5". For the most part this code works but since a rather elaborate function needs to be run on every input often times you have to press the key 2-3 times for it to work. Any ideas on how to make this more effecient? At the moment I decided to use HotKeySets since I did not know another way of stopping input (aka stopping the HID from registering the key stroke)while a function ran.

This code is a VERY slightly modified version of one posted from Authenticity from this thread [link]http://www.autoitscript.com/forum/index.php?showtopic=95105[/link].

As always any help would be appreciated.

#include <RawInput.au3>
HotKeySet('{ESC}', '_EXIT')
HotKeySet("a", "USB_C")

Global $tRID_KD, $pRID_KD, $iRID_KD
Global $tRIH, $pRIH, $iRIH
Global $iNumDevices
Global $hGUI , $pData
Global $USB
Global $Paused

$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)
$pRIH = DllStructGetPtr($tRIH)
$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(100)
WEnd

Func USB_C()
    If $USB = 1 Then
        Send ( "t" )
        $USB = 0
    EndIf
EndFunc






Func OnInput($hwnd, $iMsg, $iwParam, $ilParam)
    Local $tRI_KD, $pRI_KD, $iRI_KB
    Local $tRIDI_HID, $pRIDI_HID, $iRIDI_HID
    Local $hDevice
   
    $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD)
    $pRI_KD = DllStructGetPtr($tRI_KD)
    $iRI_KB = DllStructGetSize($tRI_KD)
    
    $tRIDI_HID = DllStructCreate($tagRIDDEVICEINFO_HID)
    $pRIDI_HID = DllStructGetPtr($tRIDI_HID)
    $iRIDI_HID = DllStructGetSize($tRIDI_HID)
    DllStructSetData($tRIDI_HID, 'cbSize', $iRIDI_HID)

    _GetRawInputData($ilParam, $RID_INPUT, $pRI_KD, $iRI_KB, $iRIH)
    If Not @error Then
        $hDevice = DllStructGetData($tRI_KD, 'hDevice')
        ConsoleWrite($hDevice & @LF)
        ConsoleWrite(DllStructGetData($tRI_KD, 'VKey') & @LF)
        ConsoleWrite(DllStructGetData($tRI_KD, 'hDevice') & @LF)
        
        _GetRawInputDeviceInfo($hDevice, $RIDI_DEVICEINFO, $pRIDI_HID, $iRIDI_HID)
        If $hDevice = 0x00A501BB Then
           $USB = 1
        EndIf
    EndIf
   
    $tRI_KD = 0
    Return 'GUI_RUNDEFMSG'
EndFunc

Func _EXIT()
    GUIDelete()
    Exit
EndFunc

RawInput.au3

Share this post


Link to post
Share on other sites



Hmm, confused. Can you explain it a bit more? The WM_INPUT message should give your application enough information regarding the event and the state of the device. If you need to inform a window or a function to process this input without waiting to luckily hit the pull time of a global variable, if that is the case, either via a send message or a function call. Correct me where I'm wrong.

Share this post


Link to post
Share on other sites

I think my issue is considerably easier than most of the other posts regarding this topic. $WM_Input only seems to give me the size of the stream I do not know how to parse out the indivudal keystroke. The 2nd issue is chaning this input, the code I recieved so far seems to monitor the signal I do not know how to hold the input in my app before it reaches say notepad.

Effectivly from a simplistic perspective I am trying to have this HID that sends say a "J" to notepad instead send a "K". Currently the code I have does that but it does so in a very inefficient manner and I am sure by using the rawinput there is a way of fixing this but I cant seem to figure out how.

Share this post


Link to post
Share on other sites

You can do something like this, the hook procedure is called prior to the WM_INPUT handler in this case because you've register it with UsagePage and Usage of a generic keyboard.

#include <GUIConstantsEx.au3>
#include <RawInput.au3>
#include <WinAPI.au3>
HotKeySet('{ESC}', '_EXIT')

Global Const $RIM_USER = 0xE0

Global $tRID_KD, $pRID_KD, $iRID_KD
Global $tRIH, $iRIH
Global $iNumDevices
Global $hGUI

Global $hHook, $hFunc, $pFunc

$hGUI = GUICreate('Test', 100, 100)
$hFunc = DllCallbackRegister('_KeyboardHookProc', 'lresult', 'int;wparam;lparam')
$pFunc = DllCallbackGetPtr($hFunc)
$hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, $pFunc, _WinAPI_GetModuleHandle(0))

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


Func OnInput($hwnd, $iMsg, $iwParam, $ilParam)
    Local $tRI_KD, $pRI_KD, $iRI_KB
    Local $iSize
    
    
    Switch BitAND($iwParam, 0xFF)
        Case $RIM_INPUT,  $RIM_INPUTSINK
            $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('-WM_INPUT: hDevice => ' & DllStructGetData($tRI_KD, 'hDevice') & _
                             ', Msg => ' & DllStructGetData($tRI_KD, 'Message') & _
                             ', VKey => ' & DllStructGetData($tRI_KD, 'VKey') & @CRLF)
            EndIf
            
        Case $RIM_USER
            $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD, $ilParam)
            If DllStructGetData($tRI_KD, 'VKey') <> 27 Then ; Escape.
                ConsoleWrite('-WM_INPUT: hDevice => ' & DllStructGetData($tRI_KD, 'hDevice') & _
                             ', Msg => ' & DllStructGetData($tRI_KD, 'Message') & _
                             ', VKey => ' & DllStructGetData($tRI_KD, 'VKey') & @CRLF)
                Return True
            EndIf
            Return False
    EndSwitch
        
    Return $GUI_RUNDEFMSG
EndFunc


Func _KeyboardHookProc($iCode, $iwParam, $ilParam)
    Local $tRI_KD, $pRI_KD
    Local $tKBDLLHS
    Local $iMsg, $iVkCode
    
    If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
    
    $tKBDLLHS = DllStructCreate($tagKBDLLHOOKSTRUCT, $ilParam)
    $iMsg = $iwParam
    $iVkCode = DllStructGetData($tKBDLLHS, 'vkCode')
    
    $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD)
    $pRI_KD = DllStructGetPtr($tRI_KD)
        DllStructSetData($tRI_KD, 'hDevice', 0x12345678)
        DllStructSetData($tRI_KD, 'VKey', $iVkCode)
        DllStructSetData($tRI_KD, 'Message', $iMsg)
        
    If OnInput($hGUI, $WM_INPUT, $RIM_USER, $pRI_KD) Then Return 1
    
    ConsoleWrite('-_KeyboardHookProc: Message => ' & $iwParam & _
                 ', VKey => ' & $iVkCode & @CRLF)
                 
    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
EndFunc


Func _EXIT()
    GUIDelete()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hFunc)
    Exit
EndFunc

Replace the hDevice to you device value and play around with the devices events to achieve a unique way to tell one device to do something differently on a system level.

Share this post


Link to post
Share on other sites

Thanks I will try that and let you know how it goes. Might take me a day or two to figure it out however, thanks.

Share this post


Link to post
Share on other sites

Its weird I keep getting errors in the RawInput file on line 583 and 516 saying "Subscript used with non-Array variable." I dont wnat to change the file because I assume it was scripted correctly. Have you heard/seen that before?

Share this post


Link to post
Share on other sites

Are you using the last updated script? Also, if you get this error I can only assume that the last parameter is not 'user32.dll' or that it's not a valid handle to user32.dll required by these function. Anyway, I need to update the library to return @error and @extended instead.

Share this post


Link to post
Share on other sites

I downloaded the rawinput from the thread uploaded on May 24th. Didnt find one more recent than that. The script seems to be choking whenever $aRet is defined. $hDll is defined as user32.dll but it is not writing to $aRet as an array.

$aRet = DllCall($hDll, 'uint', 'GetRawInputData', 'hwnd', $hRawInput, 'uint', $iCommand, 'ptr', $pData, 'uint*', $iSize, 'uint', $iSizeHeader)

Share this post


Link to post
Share on other sites

Hi, can you post the relevant code that calls this function? No check is done within the function for parameters correctness so it's hard to point out the faulting parameter(s).

Share this post


Link to post
Share on other sites

WOW so many calls and references lol. So I figured out a little about the hook calls but I'm not sure how to set an I/O. I also identefied all of the identifiers of the USB device however I cannot make the hook proceedures work. I read the winapi documentation and couldnt figure it out. I played with numerous variables and I end up with several issues primarily around the input output variable. How do you write a hook command that simply states if you recieve "a" from device 0x0190016B than convert it to "b".

Thanks for all your help so far. Which I was more familar with this though I will say I've leared quite alot, I had no idea it would take so much effort.

#include <GUIConstantsEx.au3>
#include <RawInput.au3>
#include <WinAPI.au3>
HotKeySet('{ESC}', '_EXIT')

Global Const $RIM_USER = 0xE0

Global $tRID_KD, $pRID_KD, $iRID_KD
Global $tRIH, $iRIH
Global $iNumDevices
Global $hGUI

Global $hHook, $hFunc, $pFunc

$hGUI = GUICreate('Test', 100, 100)
$hFunc = DllCallbackRegister('_KeyboardHookProc', 'lresult', 'int;wparam;lparam')
$pFunc = DllCallbackGetPtr($hFunc)
$hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, $pFunc, _WinAPI_GetModuleHandle(0))

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


Func OnInput($hwnd, $iMsg, $iwParam, $ilParam)
    Local $tRI_KD, $pRI_KD, $iRI_KB
    Local $iSize
    
    
    Switch BitAND($iwParam, 0xFF)
        Case $RIM_INPUT,  $RIM_INPUTSINK
            $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('-WM_INPUT: hDevice => ' & DllStructGetData($tRI_KD, 'hDevice') & _
                             ', Msg => ' & DllStructGetData($tRI_KD, 'Message') & _
                             ', VKey => ' & DllStructGetData($tRI_KD, 'VKey') & @CRLF)
            EndIf
            
        Case $RIM_USER
            $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD, $ilParam)
            If DllStructGetData($tRI_KD, 'VKey') <> 27 Then ; Escape.
                ConsoleWrite('-WM_INPUT: hDevice => ' & DllStructGetData($tRI_KD, 'hDevice') & _
                             ', Msg => ' & DllStructGetData($tRI_KD, 'Message') & _
                             ', VKey => ' & DllStructGetData($tRI_KD, 'VKey') & @CRLF)
                Return True
            EndIf
            Return False
    EndSwitch
        
    Return $GUI_RUNDEFMSG
EndFunc


Func _KeyboardHookProc($iCode, $iwParam, $ilParam)
    Local $tRI_KD, $pRI_KD
    Local $tKBDLLHS
    Local $iMsg, $iVkCode
    
    If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
    
    $tKBDLLHS = DllStructCreate($tagKBDLLHOOKSTRUCT, $ilParam)
    $iMsg = $iwParam
    $iVkCode = DllStructGetData($tKBDLLHS, 'vkCode')
    
    $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD)
    $pRI_KD = DllStructGetPtr($tRI_KD)
        DllStructSetData($tRI_KD, 'hDevice', 0x0190016B)
        DllStructSetData($tRI_KD, 'VKey', $iVkCode)
        DllStructSetData($tRI_KD, 'Message', $iMsg)
        
    If OnInput($hGUI, $WM_INPUT, $RIM_USER, $pRI_KD) Then Return 1
    
    ConsoleWrite('-_KeyboardHookProc: Message => ' & $iwParam & _
                 ', VKey => ' & $iVkCode & @CRLF)
                 
    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
EndFunc


Func _EXIT()
    GUIDelete()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hFunc)
    Exit
EndFunc

Share this post


Link to post
Share on other sites

Heh, honestly, I see no use for this library in this case as the hook will always be notified about the event earlier than the handler. I can only suggest to use a lock hot-key that will instruct the keyboard hook to assume A state what a variable is true and B state when a variable is false, like assuming A state input to be from the generic keyboard while handling the B state of the HID in a different mode. If you find a way please post it in the HID topic, thanks >_<.

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Yeah that was my originial idea but it seemed to have a weird sporatic behavior. The code I posted at the begining of this post took a hotkey that went thru logic to see where the input was comming from however this was fairly inconsistant since many times I had to press the button 2-3 times for it to register. I figured a hook proceedure would be a bit more responsive. Thanks :-)

Edited by boogieoompa

Share this post


Link to post
Share on other sites

OK so this seemed to kind of work. For those who did not read the last thread my goal was to capture input from an HID device and remap it. In this case remaping "a" to "j" whenever the computer recieves an "a" from the HID. The problem at the moment is it is not accepting a from the keyboard since the send command is traping it again. Is there a more elequant way of performing this task or is there a way around the send loop?

Thanks

#include <RawInput.au3>
HotKeySet('{ESC}', '_EXIT')
HotKeySet("a", "FuncTrap")



Global $tRID_KD, $pRID_KD, $iRID_KD
Global $tRIH, $pRIH, $iRIH
Global $iNumDevices
Global $hGUI , $pData

$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)
$pRIH = DllStructGetPtr($tRIH)
$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

Func FuncTrap()

EndFunc

Func FuncSend()
    send("j")
EndFunc

Func FuncSend2()
    send("a")
EndFunc

Func OnInput($hwnd, $iMsg, $iwParam, $ilParam)
    Local $tRI_KD, $pRI_KD, $iRI_KB
    Local $tRIDI_HID, $pRIDI_HID, $iRIDI_HID
    Local $hDevice
   
    $tRI_KD = DllStructCreate($tagRAWINPUT_KEYBOARD)
    $pRI_KD = DllStructGetPtr($tRI_KD)
    $iRI_KB = DllStructGetSize($tRI_KD)
    
    $tRIDI_HID = DllStructCreate($tagRIDDEVICEINFO_HID)
    $pRIDI_HID = DllStructGetPtr($tRIDI_HID)
    $iRIDI_HID = DllStructGetSize($tRIDI_HID)
    DllStructSetData($tRIDI_HID, 'cbSize', $iRIDI_HID)



    _GetRawInputData($ilParam, $RID_INPUT, $pRI_KD, $iRI_KB, $iRIH)  
    If Not @error Then
        $hDevice = DllStructGetData($tRI_KD, 'hDevice')
        ConsoleWrite($hDevice & @LF)
        ConsoleWrite(DllStructGetData($tRI_KD, 'VKey') & @LF)
        ConsoleWrite(DllStructGetData($tRI_KD, 'hDevice') & @LF)
        
        _GetRawInputDeviceInfo($hDevice, $RIDI_DEVICEINFO, $pRIDI_HID, $iRIDI_HID)
If $hDevice = 0x0190016B Then
;   ClipPut ($hDevice&","& $RIDI_DEVICEINFO&","& $pRIDI_HID&","& $iRIDI_HID)
    FuncSend()
;   Msgbox(0,"Hoorah", DllStructGetData($tRI_KD, 'hDevice') )
Else
    FuncSend2()

EndIf

    EndIf
   
    $tRI_KD = 0
    Return 'GUI_RUNDEFMSG'
EndFunc

Func _EXIT()
    GUIDelete()
    Exit
EndFunc

Share this post


Link to post
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
Sign in to follow this  
Followers 0