Oliv'

For a project, I need media keys (play, volume, mute, …) and a way to lock a computer under Windows (Windows+L keys). There is a lot of HID keyboard descriptors on the Internet, some are for keyboards + media but all contain at least one unused byte… Not a good thing for embedded systems with constraint memory. Why? The descriptor can be found in USB-IF example (Appendix B) and describe a boot compatible keyboard. So unless you need your keyboard in boot menus, this byte can be dropped. Also, the example defines 6 simultaneous keys, I decreased it to three as I don’t need more.

Consumer device profile allows a lot of actions, which can be found in HID usage tables document, in ยง15 consumer page. I selected some relevant to my application (media keys), but you can add more if required: just increase the report count and add the new key.
Note that each started byte must be padded with constant bits, so if your report count is not a multiple of 8, add a constant section.

How to use it?

Prepare an uint8_t table with a size matching the amount of data you have to send plus one for the descriptor (first byte). For media keys, each bit of the second byte will correspond to one key, LSB is the first in the descriptor. For a keyboard, the second byte is for modifiers, and the third, fourth, fifth are for keys.

Those examples are related to the following descriptor.

uint8_t bufferHID[5] = {0, 0, 0, 0, 0};
// Send media mute
bufferHID[0] = 2;      // Start with the report ID
bufferHID[1] = 0x20;   // Set mute bit to 1
USB_HID_SendReport(bufferHID, 2); // Only 2 bytes required : report ID + media keys byte.
// Send Windows+L
bufferHID[0] = 1;      // Start with the report ID
bufferHID[1] = 0x08;   // Set left GUI bit to 1 - Windows or Apple/Cmd key
bufferHID[2] = 0x0F;   // 'l' key
USB_HID_SendReport(bufferHID, 5); // 5 bytes required : report ID + keyboard[4]
delay(30);             // Leave some time for the USB stack
bufferHID[1] = 0;      // Release keys
bufferHID[2] = 0;
USB_HID_SendReport(bufferHID, 5); // Send released keys

Descriptor

  • Keyboard
  • Modifiers (MSB-LSB) : RIGHT_GUI-RIGHT_ALT-RIGHT_SHIFT-RIGHT_CTRL-LEFT_GUI-LEFT_ALT-LEFT_SHIFT-LEFT_CTRL
  • Media keys
  • Keys (MSB-LSB) : Next-Previous-Stop-Eject-Play/Pause-Mute-Vol inc-Vol dec

Descriptor

// 78 bytes
0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x06,        // Usage (Keyboard)
0xA1, 0x01,        // Collection (Application)
0x85, 0x01,        //   Report ID (1)
0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
0x75, 0x01,        //   Report Size (1)
0x95, 0x08,        //   Report Count (8)
0x19, 0xE0,        //   Usage Minimum (0xE0)
0x29, 0xE7,        //   Usage Maximum (0xE7)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x03,        //   Report Count (3)
0x75, 0x08,        //   Report Size (8)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x64,        //   Logical Maximum (100)
0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
0x19, 0x00,        //   Usage Minimum (0x00)
0x29, 0x65,        //   Usage Maximum (0x65)
0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x05, 0x0C,        // Usage Page (Consumer)
0x09, 0x01,        // Usage (Consumer Control)
0xA1, 0x01,        // Collection (Application)
0x85, 0x02,        //   Report ID (2)
0x05, 0x0C,        //   Usage Page (Consumer)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x75, 0x01,        //   Report Size (1)
0x95, 0x07,        //   Report Count (7)
0x09, 0xB5,        //   Usage (Scan Next Track)
0x09, 0xB6,        //   Usage (Scan Previous Track)
0x09, 0xB7,        //   Usage (Stop)
0x09, 0xB8,        //   Usage (Eject)
0x09, 0xCD,        //   Usage (Play/Pause)
0x09, 0xE2,        //   Usage (Mute)
0x09, 0xE9,        //   Usage (Volume Increment)
0x09, 0xEA,        //   Usage (Volume Decrement)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection

Helpful defines

// USB media codes
#define USB_HID_SCAN_NEXT 0x01
#define USB_HID_SCAN_PREV 0x02
#define USB_HID_STOP      0x04
#define USB_HID_EJECT     0x08
#define USB_HID_PAUSE     0x10
#define USB_HID_MUTE      0x20
#define USB_HID_VOL_UP    0x40
#define USB_HID_VOL_DEC   0x80

// USB keyboard codes
#define USB_HID_MODIFIER_LEFT_CTRL   0x01
#define USB_HID_MODIFIER_LEFT_SHIFT  0x02
#define USB_HID_MODIFIER_LEFT_ALT    0x04
#define USB_HID_MODIFIER_LEFT_GUI    0x08 // (Win/Apple/Meta)
#define USB_HID_MODIFIER_RIGHT_CTRL  0x10
#define USB_HID_MODIFIER_RIGHT_SHIFT 0x20
#define USB_HID_MODIFIER_RIGHT_ALT   0x40
#define USB_HID_MODIFIER_RIGHT_GUI   0x80
#define USB_HID_KEY_L     0x0F

Documentation

comments powered by Disqus