Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

AHKHID - An AHK implementation of the HID functions


  • Please log in to reply
449 replies to this topic
TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
The HID functions of the raw input model are only meant to be simpler methods of accessing the raw input data from all HID devices. That is their only purpose.
Actually communicating with an HID device is a much more complex task in which I have no experience at all, and which can't have a nice wrapper (because it is device specific).
The product page you linked says there are code examples to control the light. Try to find the code, and you'll see for yourself.

ManaUser
  • Members
  • 1121 posts
  • Last active: Mar 03 2011 09:08 PM
  • Joined: 24 May 2007
I see. I guess this HID stuff is more complicated than I imagined from looking at your script. And you can take that as a compliment. :)

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
I appreciate the compliment. :)

Faolin
  • Members
  • 8 posts
  • Last active: Apr 25 2011 11:01 PM
  • Joined: 14 May 2009

Don't hesitate to ask any other questions. :D


I got deviated for a few days, but I'm trying to pick this up again. I started modifying your code example posted here to suit my needs. I'm particularly confused by the NumGet function. Is there any place I can find the definition of this function? I'm not sure how to use it effectively. Also, do I need to convert all of my button values to decimal? Currently, I'm implementing this using the hex values I got from running the example 2 script.

Here's what I've got going on, so far:

/*!

Generally, 0 = OFF and 1 = ON

VALUE WITH ALL SWITCHES IN 0 (OFF/DOWN) POSITION = 00002008
ENSURE THAT ALL SWITCHES ARE IN THE OFF/DOWN POSITION PRIOR TO STARTING THE SCRIPT!

KNOB0 (OFF)					  +FFFFE000 (from KNOB1)
KNOB1 (L)		+00002000 (from KNOB0) or +FFFFC000 (from KNOB2)
KNOB2 (R)		+00004000 (from KNOB1) or +00007FFF (from KNOB3)
KNOB3 (BOTH/ALL)	+FFFF8001 (from KNOB2) or +FFFFFFFF (from KNOB4)
KNOB4 (START)		+00000001 (from KNOB3)
			
BAT0			+FFFF0000
BAT1			+00010000
			
ALT0			+FFFE0000
ALT1			+00020000
			
AVIONICS MASTER0	+FFFC0000
AVIONICS MASTER1	+00040000
			
FUEL PUMP0		+FFF80000
FUEL PUMP1		+00080000
			
DE-ICE0			+FFF00000
DE-ICE1			+00100000
			
PITOT HEAT0		+FFE00000
PITOT HEAT1		+00200000
			
COWL0			+FFC00000
COWL1			+00400000
			
PANEL0			+FF800000
PANEL1			+00800000
			
BEACON0			+FFFFFF00
BEACON1			+00000100
			
NAV0			+FFFFFE00
NAV1			+00000200
			
STROBE0			+FFFFFC00
STROBE1			+00000400
			
TAXI0			+FFFFF800
TAXI1			+00000800
			
LANDING0		+FFFFF000
LANDING1		+00001000
			
LANDING GEAR0 (DOWN)	+00000004
LANDING GEAR1 (UP)	+FFFFFFFC

*/

;Must be in auto-execute section if I want to use the constants
#Include %A_ScriptDir%\AHKHID.ahk

;Create GUI to receive messages
Gui, +LastFound
hGui := WinExist()

;Intercept WM_INPUT messages
WM_INPUT := 0xFF
OnMessage(WM_INPUT, "InputMsg")

;Initialize the default running value with all switches in 0 position (must be manually enforced on the hardware).
rValue := 0x00002008 ;is this correct?? do I need to convert to decimal?

;Register Saitek Switch Panel (along with other devices) with RIDEV_PAGEONLY and RIDEV_INPUTSINK (so that data is received even in the background)
r := HID_Register(0, 1, GuiHandle, RIDEV_PAGEONLY + RIDEV_INPUTSINK)

;exclude all extraneous devices listed from example 1 (joystick/mouse/keyboard etc)
e1 := HID_Register(0, 2, GuiHandle, RIDEV_EXCLUDE)
e2 := HID_Register(0, 4, GuiHandle, RIDEV_EXCLUDE)
e3 := HID_Register(0, 6, GuiHandle, RIDEV_EXCLUDE)
e4 := HID_Register(0, 7, GuiHandle, RIDEV_EXCLUDE)

;Prefix loop
Loop {
    Sleep 1000
    If WinActive("DCS: Black Shark")
        sPrefix := "DCSBS"
    Else sPrefix := "Default"
}

Return

InputMsg(wParam, lParam) {
    Local devh, iKey, sLabel
   
    Critical
   
    ;Get handle of device
    devh := HID_GetInputInfo(lParam, II_DEVHANDLE)
   
    ;Check for error
    If (devh <> -1) ;Check that it is my Saitek Pro Flight Switch Panel
        And (HID_GetDevInfo(devh, DI_DEVTYPE, True) = RIM_TYPEHID)
        And (HID_GetDevInfo(devh, DI_HID_VENDORID, True) = 1699)
        And (HID_GetDevInfo(devh, DI_HID_PRODUCTID, True) = 3431)
        And (HID_GetDevInfo(devh, DI_HID_VERSIONNUMBER, True) = 272) {
       
        ;Get data
        iKey := HID_GetInputData(lParam, uData)
       
        ;Check for error
        If (iKey <> -1) {
           
            ;Get keycode (located at the 6th byte)
            iKey := NumGet(uData, 5, "UChar") ;??????????

	    iDiff := iKey - rValue ;I probably need to fix my arithmetic here.  The intention is for this to equal the value that the latest switch added to the running total.  e.g. if I flipped to BAT1, it would add 0x00010000 to the 

running value total.  Then, I would want this value to equal 00010000.  This all may need to be converted to decimal anyway...
            rValue = iKey ;replace the running value with the last value given by the device
           
            ;Call the appropriate sub if it exists
            sLabel := sPrefix "_" iDiff
            If IsLabel(sLabel)
                Gosub, %sLabel%
        }
    }
}
Default_FFFFE000: ;KNOB0 from KNOB1
    SendInput 1
Return

Default_00002000: ;KNOB1 from KNOB0
    SendInput 2
Return

Default_FFFFC000: ;KNOB1 from KNOB2
    SendInput 2
Return

Default_00004000: ;KNOB2 from KNOB1
    SendInput 3
Return

Default_00007FFF: ;KNOB2 from KNOB3
    SendInput 3
Return

Default_FFFF8001: ;KNOB3 from KNOB2
    SendInput 4
Return

Default_FFFFFFFF: ;KNOB3 from KNOB4
    SendInput 4
Return

Default_00000001: ;KNOB4 from KNOB3
    SendInput 5
Return

Default_FFFF0000: ;BAT0
    SendInput 6
Return

Default_00010000: ;BAT1
    SendInput 6
Return

Default_FFFE0000: ;ALT0
    SendInput 7
Return

Default_00020000: ;ALT1
    SendInput 7
Return

;etc...

I stuck some of my direct questions in the comments there. Also, does anyone know if there's an easy way to debug this by viewing some of the numbers being spit out by these function calls? I'm not sure of the best way to display output for debug purposes.

Thanks!

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

I'm particularly confused by the NumGet function. Is there any place I can find the definition of this function? I'm not sure how to use it effectively.

NumGet is a function that allows you to retrieve a binary number stored in a variable. If you look at the tutorial I presented (2nd post of this thread), and look at the values I found at step 3, you'll notice that the 6th byte of the raw data coming in is the only info I need to discriminate between the buttons. That is why, in the script I have in Step 4, I use NumGet(uData, 5, "UChar"), to retrieve the 6th byte of the data. Therefore, this is obviously device specific. In your case, you need to decide what part of the data returned in uData is important. If all of it is relevant, then you don't need NumGet to extract a part of it.

Also, do I need to convert all of my button values to decimal? Currently, I'm implementing this using the hex values I got from running the example 2 script.

Yes. Although Example 2 returns the data in hex format for readability, manipulating the values in the script will be in decimal by default. You can use SetFormat to change that default. This might be what you want in your case (since you're working with such big numbers).

Here's what I've got going on, so far:

[Answering the questions I found in the script]
[*:1bhqqtt1] Yes. You can assign hex numbers using the := operator.
[*:1bhqqtt1] You've got UsagePage and Usage mixed. You need to register UsagePage 1, not 0. Therefore, your registration part should look like this:
;Register Saitek Switch Panel (along with other devices) with RIDEV_PAGEONLY and RIDEV_INPUTSINK (so that data is received even in the background)
r := HID_Register(1, 0, GuiHandle, RIDEV_PAGEONLY | RIDEV_INPUTSINK) [color=red];Although equivalent in this case, use the bitwise-or operator (the pipe symbol |) when combining flags.[/color]

;exclude all extraneous devices listed from example 1 (joystick/mouse/keyboard etc)
e1 := HID_Register(1, 2, GuiHandle, RIDEV_EXCLUDE)
e2 := HID_Register(1, 4, GuiHandle, RIDEV_EXCLUDE)
e3 := HID_Register(1, 6, GuiHandle, RIDEV_EXCLUDE)
e4 := HID_Register(1, 7, GuiHandle, RIDEV_EXCLUDE)
[*:1bhqqtt1] Also, the only reason I keep the return value of HID_Register() is to check if the registration was successful. I didn't set the right example in my tutorial script :twisted:, but unless you don't actually check the return value for error (ie. check if it equals -1), then there's no point in keeping it.
[*:1bhqqtt1] You're using = instead of := when you're replacing the running value with the last value.

Also, does anyone know if there's an easy way to debug this by viewing some of the numbers being spit out by these function calls?

I use OutputDebug along with DebugView. Great way of monitoring variables without using MsgBoxes and Pauses everywhere!

What you might want to do at first, is to disable the label calling part and simply make the InputMsg() function OutputDebug the iDiff it found, just so you see if it is what you expected. Once you've got it fine-tuned, you can implement the label calling to finally assign subroutines to each event.

Hope this helps!

Faolin
  • Members
  • 8 posts
  • Last active: Apr 25 2011 11:01 PM
  • Joined: 14 May 2009

Hope this helps!


That helped tons. I knew I had seen a function reference before... somehow I lost track of where it was =)

Here's what I'm running now (I'd love to take your advice most fully, but I'm still feeling a bit limited by my lack of comfort in this scripting language so far... so I'm sticking with some of the easier methods I'm comfortable with at this point):

/*!

Generally, 0 = OFF and 1 = ON

VALUE WITH ALL SWITCHES IN 0 (OFF/DOWN) POSITION = 0x00002008 or 8200 in decimal
ENSURE THAT ALL SWITCHES ARE IN THE OFF/DOWN POSITION PRIOR TO STARTING THE SCRIPT!

KNOB0 (OFF)			    -8192		+FFFFE000 (from KNOB1)
KNOB1 (L)		+8192	or  -16384		+00002000 (from KNOB0) or +FFFFC000 (from KNOB2)
KNOB2 (R)		+16384	or  +32767		+00004000 (from KNOB1) or +00007FFF (from KNOB3)
KNOB3 (BOTH/ALL)	-32767	or  -1			+FFFF8001 (from KNOB2) or +FFFFFFFF (from KNOB4)
KNOB4 (START)		+1				+00000001 (from KNOB3)
			
BAT0			-65536		+FFFF0000
BAT1			+65536		+00010000
			
ALT0			-131072		+FFFE0000
ALT1			+131072		+00020000
			
AVIONICS MASTER0	-262144		+FFFC0000
AVIONICS MASTER1	+262144		+00040000
			
FUEL PUMP0		-524288		+FFF80000
FUEL PUMP1		+524288		+00080000
			
DE-ICE0			-1048576	+FFF00000
DE-ICE1			+1048576	+00100000
			
PITOT HEAT0		-2097152	+FFE00000
PITOT HEAT1		+2097152	+00200000
			
COWL0			-4194304	+FFC00000
COWL1			+4194304	+00400000
			
PANEL0			-8388608	+FF800000
PANEL1			+8388608	+00800000
			
BEACON0			-256		+FFFFFF00
BEACON1			+256		+00000100
			
NAV0			-512		+FFFFFE00
NAV1			+512		+00000200
			
STROBE0			-1024		+FFFFFC00
STROBE1			+1024		+00000400
			
TAXI0			-2048		+FFFFF800
TAXI1			+2048		+00000800
			
LANDING0		-4096		+FFFFF000
LANDING1		+4096		+00001000
			
LANDING GEAR0 (DOWN)	+4		+00000004
LANDING GEAR1 (UP)	-4		+FFFFFFFC

*/

;Must be in auto-execute section if I want to use the constants
#Include %A_ScriptDir%\AHKHID.ahk

;Create GUI to receive messages
Gui, +LastFound
hGui := WinExist()

;Intercept WM_INPUT messages
WM_INPUT := 0xFF
OnMessage(WM_INPUT, "InputMsg")

;Initialize the default running value with all switches in 0 position (must be manually enforced on the hardware).
rValue := 8200

MsgBox rValue first is %rValue%.

;Register Saitek Switch Panel (along with other devices) with RIDEV_PAGEONLY and RIDEV_INPUTSINK (so that data is received even in the background)
HID_Register(1, 0, GuiHandle, RIDEV_PAGEONLY | RIDEV_INPUTSINK)

;exclude all extraneous devices listed from example 1 (joystick/mouse/keyboard etc)
HID_Register(1, 2, GuiHandle, RIDEV_EXCLUDE)
HID_Register(1, 4, GuiHandle, RIDEV_EXCLUDE)
HID_Register(1, 6, GuiHandle, RIDEV_EXCLUDE)
HID_Register(1, 7, GuiHandle, RIDEV_EXCLUDE)

;Prefix loop
Loop {
    Sleep 1000
    If WinActive("DCS: Black Shark")
        sPrefix := "DCSBS"
    Else sPrefix := "Default"
}

Return

InputMsg(wParam, lParam) {
    Local devh, iKey, sLabel
   
    Critical
   
    ;Get handle of device
    devh := HID_GetInputInfo(lParam, II_DEVHANDLE)
   
    ;Check for error
    If (devh <> -1) ;Check that it is my Saitek Pro Flight Switch Panel
        And (HID_GetDevInfo(devh, DI_DEVTYPE, True) = RIM_TYPEHID)
        And (HID_GetDevInfo(devh, DI_HID_VENDORID, True) = 1699)
        And (HID_GetDevInfo(devh, DI_HID_PRODUCTID, True) = 3431)
        And (HID_GetDevInfo(devh, DI_HID_VERSIONNUMBER, True) = 272) {
       
        ;Get data
        iKey := HID_GetInputData(lParam, uData)

	MsgBox rValue is %rValue%.  

	MsgBox iKey from HID_GetInputData is %iKey%.  
       
        ;Check for error
        If (iKey <> -1) {
           
            ;Get keycode (located at the 6th byte)
            iKey := NumGet(uData, 0, "Int")

		MsgBox iKey from NumGet is %iKey%.  

	    iDiff := iKey - rValue ;Ascertain the the difference in the running value given by the last keystroke.  This difference is unique for each button's position.

		MsgBox iDiff is %iDiff%.  
	    rValue := iKey ;replace the running value with the last value given by the device

		MsgBox new rValue is %rValue%.  
           
            ;Call the appropriate sub if it exists
            sLabel := sPrefix "_" iDiff

		MsgBox sLabel is %sLabel%.  
            If IsLabel(sLabel)
                Gosub, %sLabel%
        }
    }
}
Default_-8192: ;KNOB0 from KNOB1
    SendInput 1 
Return

Default_8192: ;KNOB1 from KNOB0
    SendInput 2 
Return

Default_-16384: ;KNOB1 from KNOB2
    SendInput 3 
Return

Default_16384: ;KNOB2 from KNOB1
    SendInput 4 
Return

Default_32767: ;KNOB2 from KNOB3
    SendInput 5 
Return

Default_-32767: ;KNOB3 from KNOB2
    SendInput 6 
Return

Default_-1: ;KNOB3 from KNOB4
    SendInput 7 
Return

Default_1: ;KNOB4 from KNOB3
    SendInput 8 
Return

Default_-65536: ;BAT0
    SendInput 9 
Return

Default_65536: ;BAT1
    SendInput 10 
Return

Default_-131072: ;ALT0
    SendInput 11 
Return

Default_131072: ;ALT1
    SendInput 12 
Return

;etc...

The very first msgbox succeeds and spits out the simple rValue just below where I assigned it in the beginning. None of the other msgboxes pop up, though, so it's failing to get any input at that point.

And now here's what pops up in the AHK script window when I go to run this (partial capture in relevant area). I believe it's failing to register the devices in the first call to HID_Register =((( Not sure why this would work in example 2 but not here....

(I wrapped the following in code tags for lack of anything better-- obviously it's not actually code)

062: Gui,+LastFound
063: hGui := WinExist()
066: WM_INPUT := 0xFF
067: OnMessage(WM_INPUT, "InputMsg")  
070: rValue := 8200
072: MsgBox,rValue first is %rValue%. (1.56)
075: HID_Register(1, 0, GuiHandle, RIDEV_PAGEONLY | RIDEV_INPUTSINK)  
405: RIDEV_REMOVE  := 0x00000001, RIDEV_EXCLUDE := 0x00000010  
408: if Not (UsagePage || Usage || Handle || Flags)  
423: VarSetCapacity(uDev, 12)  
426: bNull := (Flags & RIDEV_REMOVE) || (Flags & RIDEV_EXCLUDE)
428: NumPut(UsagePage,           uDev, 0, "UShort")  
429: NumPut(Usage,               uDev, 2, "UShort")  
430: NumPut(Flags,               uDev, 4)  
431: NumPut(bNull ? 0 : Handle,  uDev, 8)  
434: r := DllCall("RegisterRawInputDevices", "UInt", &uDev, "UInt", 1, "UInt", 12)
437: if Not r  
438: ErrorLevel = RegisterRawInputDevices call failed.
Return value: %r%
ErrorLevel: %ErrorLevel%
Line: %A_LineNumber%
Last Error: %A_LastError%
439: Return,-1
078: HID_Register(1, 2, GuiHandle, RIDEV_EXCLUDE)  
405: RIDEV_REMOVE  := 0x00000001, RIDEV_EXCLUDE := 0x00000010  
408: if Not (UsagePage || Usage || Handle || Flags)  
423: VarSetCapacity(uDev, 12)  
426: bNull := (Flags & RIDEV_REMOVE) || (Flags & RIDEV_EXCLUDE)
428: NumPut(UsagePage,           uDev, 0, "UShort")  
429: NumPut(Usage,               uDev, 2, "UShort")  
430: NumPut(Flags,               uDev, 4)  
431: NumPut(bNull ? 0 : Handle,  uDev, 8)  
434: r := DllCall("RegisterRawInputDevices", "UInt", &uDev, "UInt", 1, "UInt", 12)
437: if Not r  
441: }
443: Return,0

edit: I looked at the log a bit more and did a capture on the ErrorLevel and here's what I got (also I finally figured out how to use DebugView properly =)

[5912] ErrorLevel is RegisterRawInputDevices call failed.
[5912] Return value: 0
[5912] ErrorLevel: 0
[5912] Line: 438
[5912] Last Error: 87.

Not sure if that helps at all...

edit 2: On a hunch, I decided to test the code using decimal 288 value as the flags parameter for HID_Register. That didn't work. I also tried using the hex value 0x00000120. Then I tried removing RIDEV_INPUTSINK (since RIDEV_PAGEONLY is more important to get anything working) and indeed it did register correctly. Only downside is I could only see my debugs when the script window was in the foreground. I can use this to debug my logic for interpreting the keystrokes, but I'm still at a loss as to how I can use the RIDEV_INPUTSINK flag in conjunction. I tried using + instead of the | and that didn't help either. On a sidenote, the working registration with only RIDEV_PAGEONLY takes a good 15 seconds or so to happen. Not sure why that's so slow. Any ideas?

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
It took me a while, but I understand now why the registration is failing. You're using GuiHandle (not sure where you found it) instead of hGui to register your TLCs. Your code should look like this (I added some error handling, so that we'll know right away if something goes wrong):

;Register Saitek Switch Panel (along with other devices) with RIDEV_PAGEONLY and RIDEV_INPUTSINK (so that data is received even in the background)
If (HID_Register(1, 0, hGui, RIDEV_PAGEONLY | RIDEV_INPUTSINK) = -1) {
    MsgBox %ErrorLevel%
    ExitApp
}

;exclude all extraneous devices listed from example 1 (joystick/mouse/keyboard etc)
If (HID_Register(1, 2, hGui, RIDEV_EXCLUDE) = -1) {
    MsgBox %ErrorLevel%
    ExitApp
}

If (HID_Register(1, 4, hGui, RIDEV_EXCLUDE) = -1) {
    MsgBox %ErrorLevel%
    ExitApp
}

If (HID_Register(1, 6, hGui, RIDEV_EXCLUDE) = -1) {
    MsgBox %ErrorLevel%
    ExitApp
}

If (HID_Register(1, 7, hGui, RIDEV_EXCLUDE) = -1) {
    MsgBox %ErrorLevel%
    ExitApp
}

If you now know how to use DebugView, I recommend using it. Especially in those parts where you're using MsgBox in the InputMsg() function (not good).

kenny782
  • Members
  • 11 posts
  • Last active: Sep 01 2010 12:43 AM
  • Joined: 18 May 2009
I've been looking for some tools like your three examples for the last 2 days, thank you! lol

The best part is I was looking for them to deal with my MCE remote too :D

I've been beating my head against the wall trying to differentiate between my keyboard and remote for the last few days.

Question:
What I'm trying to do is slightly different
I want to read the keys being hit on my keyboard but ignore anything coming from the remote.


I've only used AutoHotKey once before but I'm sure I can put it together.

But I'd really appreciate it if you could throw together a quick section of code to show me how to read the device source/keyboard key rather than the remote button.

I can see from your example how to do one or the other but I'm not sure how to use both the keyboard and remotes usage page.
Telling them apart should be a simple thing from what the example 2 output showed me.

Thanks in advance,

Kenny

Faolin
  • Members
  • 8 posts
  • Last active: Apr 25 2011 11:01 PM
  • Joined: 14 May 2009

You're using GuiHandle (not sure where you found it) instead of hGui to register your TLCs.


That was leftover from my attempts at modifying your example 2 to auto-register/exclude my devices upon hitting the CALL button (one of my first attempts at getting anything working). It didn't work, so rather than fussing with that I just moved onto this script working off of your later example. Unfortunately that one line followed me. The original line from example 2 looked like this:

;Add for registration
        r := HID_AddRegister(iUsPg, iUs, GuiHandle, iFlag)

Looks like I bastardized it a good bit because I don't quite understand what that parameter does =) I can't wait to get home to check this now!

Once I verify it's all working properly, I'll have to look at some of the GUI guides in order to build a nice GUI whereby I can assign keystrokes to the toggle switches on-the-fly. Then Saitek can eat their hearts out for selling such a tunnel-visioned device... lol

Thanks a bunch! You've saved me oodles of hassle.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

I can't wait to get home to check this now! Once I verify it's all working properly, I'll have to look at some of the GUI guides in order to build a nice GUI whereby I can assign keystrokes to the toggle switches on-the-fly. Then Saitek can eat their hearts out for selling such a tunnel-visioned device... lol Thanks a bunch! You've saved me oodles of hassle.

No problem! Let me know if it works out!

Question:

I don't exactly understand what you want. Do you simply not want the remote to send keyboard keys? If that's all you want, you don't need AHKHID for that. All you need is to uninstall the keyboard driver loaded by your remote. I showed the procedure a few posts ago. Here it is:

You can make the remote stop generating those keyboard presses by doing the following steps:
1. Go to Device Manager
2. Expand the "Keyboards" tree
3. You should find a device (ie. your remote registered as a keyboard) other than your usual keyboard there. To make sure it is indeed your remote, you can compare the name you found in Example 1 with the name you'll find when you right-click>Properties>Details on the keyboard item in Device Manager.
4. Once you found the keyboard entry associated to your Kensington Presentation remote, right-click the item and select Uninstall

Let me know if you meant something else. :)
Edit: to get to Device Manager, go to Start>Run>type "devmgmt.msc" and press OK.

kenny782
  • Members
  • 11 posts
  • Last active: Sep 01 2010 12:43 AM
  • Joined: 18 May 2009
I'm not quite that slow :) lol

No I just want to be able to identify the source of each keystroke.

For anything hit on the keyboard itself I want the script to call an application.
And if F3 is hit on the keyboard I want to call a different application.

If I register 1/6 I can't tell between the remote and the keyboard
If I register the others for the remote instead I can't see the keyboard events

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

I'm not quite that slow :) lol

Haha, there's nothing slow about uninstalling a keyboard device associated with a remote. Even I only figured that out a while ago. :)

No I just want to be able to identify the source of each keystroke.

When you say "identify the source", from where are you talking about? From a hotkey which could be fired both from the keyboard and the remote, or from a script using AHKHID?

If it's the latter, it is extremely easy since you simply don't have to register the keyboard, and therefore any input you receive will be from the remote.
If it's the former, well, it's a little more complicated. I showed here two possible (untested) solutions. See if they work for you.

To tell you the truth, I'm still not too sure if this is what you meant. You said:

I want to read the keys being hit on my keyboard but ignore anything coming from the remote.

Well, you don't need AHKHID for that. If the problem is that (for example) the Up arrow on your keyboard and and the Up key on your remote both trigger the Up hotkey you have set up, then you can solve the problem (ie. make the Up key on your remote not do anything) by uninstalling the keyboard device associated with the remote like I showed you in the other post. Is this what you meant?

kenny782
  • Members
  • 11 posts
  • Last active: Sep 01 2010 12:43 AM
  • Joined: 18 May 2009
hmm maybe this will help, i haven't mentioned it explicitly.
I want my remote to work normally.

That why I want to know if my remote or keyboard sent the event.
1) If I hit the up key on my keyboard I call the application.
2) If i hit the up key on my remote I don't call the application.

The problem is when I call 1/6 I see the up key but i can't tell the difference between the remote and the keyboard.

Faolin
  • Members
  • 8 posts
  • Last active: Apr 25 2011 11:01 PM
  • Joined: 14 May 2009

The problem is when I call 1/6 I see the up key but i can't tell the difference between the remote and the keyboard.


Sounds to me like you're hitting a button on different devices but seeing the same data being sent to the PC? Can't you handle that, as TheGood pointed out, by filtering your input logic on a particular device's parameters? TheGood posted an example before:

InputMsg(wParam, lParam) {
    Local devh, iKey, sLabel
   
    Critical
   
    ;Get handle of device
    devh := HID_GetInputInfo(lParam, II_DEVHANDLE)
   
    ;Check for error
    If (devh <> -1) ;Check that it is my HP remote
        And (HID_GetDevInfo(devh, DI_DEVTYPE, True) = RIM_TYPEHID)
        And (HID_GetDevInfo(devh, DI_HID_VENDORID, True) = 1118)
        And (HID_GetDevInfo(devh, DI_HID_PRODUCTID, True) = 109)
        And (HID_GetDevInfo(devh, DI_HID_VERSIONNUMBER, True) = 272) {
       
        ;Get data
        iKey := HID_GetInputData(lParam, uData)
       
        ;Check for error
        If (iKey <> -1) {
           
            ;Get keycode (located at the 6th byte)
            iKey := NumGet(uData, 5, "UChar")
           
            ;Call the appropriate sub if it exists
            sLabel := sPrefix "_" iKey
            If IsLabel(sLabel)
                Gosub, %sLabel%
        }
    }
}

Using example 1, you should be able to ascertain the VENDOR ID, PRODUCT ID, and VERSION NUMBER of your device and then plug in those values to code like above in order to ignore input from other devices.

Even if you wanted to use both devices in the same script, you could just copy/paste this snippet so it appears once in your code for each device you want to filter... thus calling different subs per device, even if the output value being read is the same for each.

kenny782
  • Members
  • 11 posts
  • Last active: Sep 01 2010 12:43 AM
  • Joined: 18 May 2009
It looks like windows is returning the keyboard output first when you register 1/6

Here is the output from the remote and the keyboard
1 := HID_GetDevInfo(devh, DI_DEVTYPE, True)
       2 := HID_GetDevInfo(devh, DI_HID_VENDORID, True)
       3 := HID_GetDevInfo(devh, DI_HID_PRODUCTID, True)
       4 := HID_GetDevInfo(devh, DI_HID_VERSIONNUMBER, True)
       5 := HID_GetDevInfo(devh, DI_HID_USAGEPAGE, True)
       6 := HID_GetDevInfo(devh, DI_HID_USAGE, True)
       ; 7 = vkcode
       8 := HID_GetDevInfo(devh, DI_KBD_NUMBEROFKEYSTOTAL, True)

       MsgBox %1%     %2%     %3%     %4%     %6%     %7%     %iKey%     %5%

;REMOTE    1  -  7  -  0  -  1  -  12  -  0  -  39  -  101
;KEYBOARD  1  -  7  -  0  -  1  -  12  -  0  -  39  -  101

I tried registering the others before 1/6 but the same thing happened