cancel
Showing results for 
Search instead for 
Did you mean: 

How to read the volume keys from a USB keyboard

Robmar
Senior III

I've read many posts here and on the web, even tried CoPilot, but I could not find how to get the USB controller to send data when the volume keys are pressed.

My Host keyboard driver works perfectly, but USBH_LL_GetURBState() is not returning with data for anything but "standard" key presses.

After many hours invested due to a total lack of documentation from STM, I found that the report descriptor of 146 bytes is read back by USBH_HID_GetHIDReportDescriptor() but the "consumer device" entry is not used.

But if STM had one support person publish a short guide it would save many developers many hours.

USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost)
{
  uint32_t x;
  HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;

  keybd_info.lctrl = 0U;
  keybd_info.lshift = 0U;
  keybd_info.lalt = 0U;
  keybd_info.lgui = 0U;
  keybd_info.rctrl = 0U;
  keybd_info.rshift = 0U;
  keybd_info.ralt = 0U;
  keybd_info.rgui = 0U;

  for (x = 0U; x < sizeof(keybd_report_data); x++)
  {
    keybd_report_data[x] = 0U;
    keybd_rx_report_buf[x] = 0U;
  }

  if (HID_Handle->length > (sizeof(keybd_report_data)))
  {
    HID_Handle->length = (uint16_t)(sizeof(keybd_report_data));
  }

  HID_Handle->pData = keybd_rx_report_buf;

  if ((HID_QUEUE_SIZE * sizeof(keybd_report_data)) > sizeof(phost->device.Data))
  {
    return USBH_FAIL;
  }
  else
  {
** in the line below, I think it needs to point to the report table 65 bytes in for the "consumer devices" usage:-
    USBH_HID_FifoInit(&HID_Handle->fifo, phost->device.Data, (uint16_t)(HID_QUEUE_SIZE * sizeof(keybd_report_data)));
  }

  return USBH_OK;
}

const char USB_CLASS_SPECIFIC_DESC[] = {
     //hid report descriptor for interface 1 (keyboard)
      0x05, 0x01, //usage page (generic desktop)   //52, 53
      0x09, 0x06, //usage (keyboard)   //54, 55
      0xA1, 0x01, //collection (application) //56, 57
      0x85, 0x01,  /*   Report ID1  */
      0x05, 0x07, //usage page (key codes)   //58, 59
      0x19, 0xE0, //usage min (224) //60, 61
      0x29, 0xE7, //usage max (231) //62, 63
      0x15, 0x00, //logical min (0) //64, 65
      0x25, 0x01, //logical max (1) //66, 67
      0x75, 0x01, //report size (1) //68, 69
      0x95, 0x08, //report count (8)   //70, 71
      0x81, 0x02, //input (data, variable, absolute) [modifier byte] //72, 73
      0x95, 0x01, //report count (1)   //74, 75
      0x75, 0x08, //report size (8)    //76, 77
      0x81, 0x01, //input (constant) [reserved byte]  //78, 79
      0x95, 0x05, //report count (5)   //80, 81
      0x75, 0x01, //report size (1)    //82, 83
      0x05, 0x08, //usage page (page# for leds) //84, 85
      0x19, 0x01, //usage min (1)   //86, 87
      0x29, 0x05, //usage max (5)   //88, 89
      0x91, 0x02, //output (data, var, abs) [led report] //90, 91
      0x95, 0x01, //report count (1)   //92, 93
      0x75, 0x03, //report size (3) //94, 95
      0x91, 0x01, //output (constant) [led report padding]  //96, 97
      0x95, 0x05, //report count (5)   //98, 99
      0x75, 0x08, //report size (8) //100, 101
      0x15, 0x00, //logical min (0) //102, 103
      0x25, 0x65, //logical max (101)  //104, 105
      0x05, 0x07, //usage page (key codes)   //106, 107
      0x19, 0x00, //usage min (0)   //108, 109
      0x29, 0x65, //usage max (101) //110, 111
      0x81, 0x00, //input (data, array)   //112, 113
      0xC0,        //end collection  //114
     
   //
      0x05, 0x0C,    /*      Usage Page (Consumer Devices)      */
      0x09, 0x01,    /*      Usage (Consumer Control)         */
      0xA1, 0x01,    /*      Collection (Application)         */
      0x85, 0x02,    /*      Report ID=2                     */
      0x05, 0x0C,    /*      Usage Page (Consumer Devices)      */
      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, 0xCD,    /*      Usage (Play / Pause)            */
      0x09, 0xE2,    /*      Usage (Mute)                  */
      0x09, 0xE9,    /*      Usage (Volume Up)               */
      0x09, 0xEA,    /*      Usage (Volume Down)               */
      0x81, 0x02,    /*      Input (Data, Variable, Absolute)   */
      0x95, 0x01,    /*      Report Count (1)               */
      0x81, 0x01,    /*      Input (Constant)               */
      0xC0,    

 

1 REPLY 1
Robmar
Senior III

The set idle call seems to be important to maintain dataflow, is this change going to be needed to get the volume key data to arrive?

case USBH_HID_REQ_SET_IDLE:
    // First Set_Idle for standard keyboard Report ID (0x00)
    classReqStatus = USBH_HID_SetIdle(phost, 0U, 0x00); // Send Set_Idle request
    if (classReqStatus == USBH_OK) {
        HID_Handle->ctl_state = USBH_HID_REQ_SET_IDLE_CONSUMER; // Move to next state
    } else if (classReqStatus == USBH_NOT_SUPPORTED) {
        HID_Handle->ctl_state = USBH_HID_REQ_SET_IDLE_CONSUMER; // Skip and continue
    }
    break;

case USBH_HID_REQ_SET_IDLE_CONSUMER:
    // Second Set_Idle for Consumer Control Report ID (e.g., 0x02)
    classReqStatus = USBH_HID_SetIdle(phost, 0U, 0x02);
    if (classReqStatus == USBH_OK) {
        HID_Handle->ctl_state = USBH_HID_REQ_SET_PROTOCOL; // Proceed to Set Protocol state
    } else if (classReqStatus == USBH_NOT_SUPPORTED) {
        HID_Handle->ctl_state = USBH_HID_REQ_SET_PROTOCOL; // Skip and continue
    }
    break;