Author Topic: How ELSE can I write to USB HID keyboard device?  (Read 14183 times)

grantb5

  • Member
  • ***
  • Posts: 34
How ELSE can I write to USB HID keyboard device?
« on: June 11, 2013, 12:04:22 pm »
I have a keyboard emulator device that I need to send data to "in the background".  I have lots of endpoints to play with if I need them: currently I'm using EP1 IN for standard key data report and EP2 IN for consumer control key report. The device also receives the LED status from the host on EP0.  I'm need help choosing a technique for the data-back-to-the-device part.

Previously I have used Feature Reports on EP0 to send data to the device. Please see below for my HID report descriptors. My problem with the existing technique is that I cannot get it to work on Win8 consistently. It's fine all the way back to XP... I've been using it for years, but this Win8 thing is defeating me.  Anyway, Jan recommended making the Feature Report (the part commented out) a Top Level Collection, but I have not been able to come up with an HID report that doesn't fail on enumeration ("Your device did not install correctly").  An example of a device with two top level collections sharing an endpoint would be awesome.

So failing that, what ELSE can I do?  Can I use another endpoint as vendor defined HID?  I'm thinking that anything I create using WriteFile from the PC end is going to fail because Windows controls the HID keyboard device. On the PC-side I'm using application level Win32 API.



Code: [Select]
// Standard keys report and LED status.
code char HidReport_DescriptorKB1[] =
{
  0x05, 0x01,       // usage page (generic desktop)
  0x09, 0x06,       // usage (keyboard)
  0xA1, 0x01,       // collection (application)

  0x05, 0x07,       // usage page( key codes)  - Modifier Keys
  0x19, 0xE0,       // usage minimum (224)
  0x29, 0xE7,       // usage maximum (231)
  0x15, 0x00,       // logical minimum (0)
  0x25, 0x01,       // logical maximum (1)
  0x75, 0x01,       // report size (1 bit)
  0x95, 0x08,       // report count (8 bytes)
  0x81, 0x02,       // input report (data, variable, absolute) - Modifier bytes

  0x95, 0x01,       // report count (1 byte) - A zero byte
  0x75, 0x08,       // report size (8 bits)
  0x81, 0x01,       // input report (constant) - Input Report padding.

  0x95, 0x06,       // report count (6) - 6 bytes of key data
  0x75, 0x08,       // report size (8)
  0x15, 0x00,       // logical minimum (0)
  0x26, 0x93, 0x00, // logical maximum (147).  Added F14-F24
  0x05, 0x07,       // usage page (key codes)
  0x19, 0x00,       // usage minimum (0)                         
  0x2A, 0x93, 0x00, // usage maximum (147)     Added F1-F24     LANG4 
  0x81, 0x00,       // input report (data, array) - Keyboard report


  0x95, 0x05,       // report count (5) - The LED status
  0x75, 0x01,       // report size (1)
  0x05, 0x08,       // usage page (LEDs)
  0x19, 0x01,       // usage minimum (1)
  0x29, 0x05,       // usage maximum (5)
  0x91, 0x02,       // output report (data, variable, absolute) - LED report
 
  0x95, 0x01,       // report count (1)
  0x75, 0x03,       // report size (3)
  0x91, 0x01,       // output report (constant) - LED padding


//  0x09, 0x03,       // Usage (vendor defined) - Feature report that is killing me on Win8.
//  0x75, 0x08,       // Report size (8 bits)
//  0x95, 0x05,       // Report count (5 fields)
//  0xB1, 0x02,       // NEW Feature Report (Data, Variable, Absolute)


  0xC0              // end collection
};

// "Multimedia" keys.
code char HidReport_DescriptorKB2[] =
{
  0x05, 0x0C,       // usage page (Consumer Page)
  0x09, 0x01,       // usage (Consumer Control)
  0xA1, 0x01,       // collection (application)

  0x85, 0x01,       // REPORT_ID (1)

  0x19, 0x00,       // USAGE_MINIMUM (Unassigned)
  0x2A, 0x3C, 0x02, // USAGE_MAXIMUM (AC Format)
  0x15, 0x00,       // LOGICAL_MINIMUM (0)
  0x26, 0x3C, 0x02, // LOGICAL_MAXIMUM (572)
  0x95, 0x01,       // REPORT_COUNT (1)
  0x75, 0x10,       // REPORT_SIZE (16)
  0x81, 0x00,       // NEW INPUT REPORT (Data,Array,Absolute)

  0xC0              // end collection
};

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How ELSE can I write to USB HID keyboard device?
« Reply #1 on: June 11, 2013, 03:21:47 pm »
It's true that you can only address a Feature report to an interface, not a collection within an interface. I hadn't thought of that.

But you should be able to add a second, vendor-defined HID interface and use that to transfer Feature, Input, and Output reports as needed. I have example code for vendor-defined HIDs here:

www.Lvr.com/hidpage.htm

android

  • Member
  • ***
  • Posts: 5
Re: How ELSE can I write to USB HID keyboard device?
« Reply #2 on: October 10, 2013, 03:42:17 am »
@grantb5 Sorry to dredge this old post up, but I just stumbled on it...

I uncommented your problematic feature report...

Quote
//  0x09, 0x03,       // Usage (vendor defined) - Feature report that is killing me on Win8.
//  0x75, 0x08,       // Report size (8 bits)
//  0x95, 0x05,       // Report count (5 fields)
//  0xB1, 0x02,       // NEW Feature Report (Data, Variable, Absolute)

...and ran it through a HID report descriptor decoder that I'm writing just for fun and it appears that although your comment says '(vendor defined)' the current usage page is in fact the LED usage page...

05 01        (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page
09 06        (LOCAL)  USAGE              0x00010006 Keyboard (Application Collection)
A1 01        (MAIN)   COLLECTION         0x01 Application
05 07          (GLOBAL) USAGE_PAGE         0x0007 Keyboard/Keypad Page
19 E0          (LOCAL)  USAGE_MINIMUM      0x000700E0  Keyboard Left Control (Dynamic Value)
29 E7          (LOCAL)  USAGE_MAXIMUM      0x000700E7  Keyboard Right GUI (Dynamic Value)
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0)
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
95 08          (GLOBAL) REPORT_COUNT       0x08 (8) Number of fields
81 02          (MAIN)   INPUT              0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
81 01          (MAIN)   INPUT              0x00000001 (1 field x 8 bits) 1=Constant 0=Array 0=Absolute
95 06          (GLOBAL) REPORT_COUNT       0x06 (6) Number of fields
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0)
26 9300        (GLOBAL) LOGICAL_MAXIMUM    0x0093 (147)
05 07          (GLOBAL) USAGE_PAGE         0x0007 Keyboard/Keypad Page
19 00          (LOCAL)  USAGE_MINIMUM      0x00070000  ()
2A 9300        (LOCAL)  USAGE_MAXIMUM      0x00070093  Keyboard LANG4 (Selector)
81 00          (MAIN)   INPUT              0x00000000 (6 fields x 8 bits) 0=Data 0=Array 0=Absolute
95 05          (GLOBAL) REPORT_COUNT       0x05 (5) Number of fields
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
05 08          (GLOBAL) USAGE_PAGE         0x0008 LED Indicator Page
19 01          (LOCAL)  USAGE_MINIMUM      0x00080001 Num Lock (On/Off Control)
29 05          (LOCAL)  USAGE_MAXIMUM      0x00080005 Kana (On/Off Control)
91 02          (MAIN)   OUTPUT             0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
75 03          (GLOBAL) REPORT_SIZE        0x03 (3) Number of bits per field
91 01          (MAIN)   OUTPUT             0x00000001 (1 field x 3 bits) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 03          (LOCAL)  USAGE              0x00080003 Scroll Lock (On/Off Control)
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
95 05          (GLOBAL) REPORT_COUNT       0x05 (5) Number of fields
B1 02          (MAIN)   FEATURE            0x00000002 (5 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0           (MAIN)   END_COLLECTION
   

The resulting C-structure for the feature report would then be (assuming my code is ok):

//------------------------------------------------------------------------
// LED Indicator Page featureReport 0 (Device --> Host)
//------------------------------------------------------------------------

typedef struct
{
                                        // No REPORT ID byte
  uint8_t LED_ScrollLock[5];            // 0008 0003 Scroll Lock (On/Off Control) Value = 0 to 147
} featureReport;

 
I wonder whether that was what Windows 8 was objecting to? I certainly don't know what it means, but that's not saying much!

grantb5

  • Member
  • ***
  • Posts: 34
Re: How ELSE can I write to USB HID keyboard device?
« Reply #3 on: October 10, 2013, 11:54:55 am »
Hi,

Thanks for looking at this again/still. I made the following changes (not the LED part):

From:
 0x95, 0x06,       //   Report Count (6 bytes)
 0x75, 0x08,       //   Report Size (8 bits)
 0x15, 0x00,       //   Logical Minimum (0)
 0x25, 0x93,       //   Logical Maximum (147)  
 0x05, 0x07,       //   Usage Page (Key Codes)
 0x19, 0x00,       //   Usage Minimum (0)
 0x29, 0x93,       //   Usage Maximum (147)  
 0x81, 0x00,       //   Input (Data, Array) - Key data (6 bytes)

To:
  0x95, 0x06,       // report count (6)
  0x75, 0x08,       // report size (8)
  0x15, 0x00,       // logical minimum (0)
  0x26, 0x93, 0x00, // logical maximum (147).  
  0x05, 0x07,       // usage page (key codes)
  0x19, 0x00,       // usage minimum (0)                          
  0x2A, 0x93, 0x00, // usage maximum (147)  
  0x81, 0x00,       // input report (data, array) - Keyboard report

Which if memory serves was to switch to unsigned numbers. It's in testing now, so my preliminary tests were positive and we will see what a broader more in-depth test will show. I guess the stack is totally different in Win8 so there are some new interpretations to watch out for.  Having said that I have no idea why this particular change would manifest itself in the issues I saw.

I will look at your comments/suggestion when time allows.

Thanks,
GB
« Last Edit: October 10, 2013, 11:56:33 am by grantb5 »