在描述符中结合键盘和消费者控制



我有一个hid_discriptor,看起来像这样:

// from USB HID Specification 1.1, Appendix B.1
const uint8_t hid_descriptor_keyboard_boot_mode[] = {
    /*
       Keyboard
     */
    0x05, 0x01,                    // Usage Page (Generic Desktop)
    0x09, 0x06,                    // Usage (Keyboard)
    0xa1, 0x01,                    // Collection (Application)
    0x85,  0x01,                   // Report ID 1
    // Modifier byte
    0x75, 0x01,                    //   Report Size (1)
    0x95, 0x08,                    //   Report Count (8)
    0x05, 0x07,                    //   Usage Page (Key codes)
    0x19, 0xe0,                    //   Usage Minimum (Keyboard LeftControl)
    0x29, 0xe7,                    //   Usage Maxium (Keyboard Right GUI)
    0x15, 0x00,                    //   Logical Minimum (0)
    0x25, 0x01,                    //   Logical Maximum (1)
    0x81, 0x02,                    //   Input (Data, Variable, Absolute)
    // Reserved byte
    0x75, 0x01,                    //   Report Size (1)
    0x95, 0x08,                    //   Report Count (8)
    0x81, 0x03,                    //   Input (Constant, Variable, Absolute)
    // LED report + padding
    0x95, 0x05,                    //   Report Count (5)
    0x75, 0x01,                    //   Report Size (1)
    0x05, 0x08,                    //   Usage Page (LEDs)
    0x19, 0x01,                    //   Usage Minimum (Num Lock)
    0x29, 0x05,                    //   Usage Maxium (Kana)
    0x91, 0x02,                    //   Output (Data, Variable, Absolute)
    0x95, 0x01,                    //   Report Count (1)
    0x75, 0x03,                    //   Report Size (3)
    0x91, 0x03,                    //   Output (Constant, Variable, Absolute)
    // Keycodes
    0x95, 0x06,                    //   Report Count (6)
    0x75, 0x08,                    //   Report Size (8)
    0x15, 0x00,                    //   Logical Minimum (0)
    0x25, 0xff,                    //   Logical Maximum (1)
    0x05, 0x07,                    //   Usage Page (Key codes)
    0x19, 0x00,                    //   Usage Minimum (Reserved (no event indicated))
    0x29, 0xff,                    //   Usage Maxium (Reserved)
    0x81, 0x00,                    //   Input (Data, Array)
    0xc0,                          // End collection
};

适用于键盘代码;

但是,我也想在样本中添加消费者控制,因此我也可以向上/下发送音量。

    /*
       Consumer Control
     */
    0x05, 0x0C,                     // Usage Page (Consumer Devices)
    0x09, 0x01,                     // Usage (Consumer Control)
    0xA1, 0x01,                     // Collection (Application)
    0x85, 0x02,                     //      Report ID
    0x75, 0x09, 0x01,               //      Report Size
    0x95, 0x09, 0x01,               //     Report Count
    0x15, 0x00,                     //      Logical Minimum (0)
    0x26, 0xFF, 0x07,               //      Logical Maximum (2047)
    0x19, 0x00,                     //      Usage Minimum (0)
    0x2A, 0xFF, 0x07,               //      Usage Maximum (2047)
    0x81, 0x00,                     //      Input (Data, Ary, Abs)
    0xC0,

问题是,在提供的演示代码中;发送报告的代码是:

static void send_report(int modifier, int keycode){
    uint8_t report[] = { /* 0xa1, */ modifier, 0, 0, keycode, 0, 0, 0, 0, 0};
    hids_device_send_input_report(con_handle, report, sizeof(report));
}

这在发送击键方面起作用;当我在源代码中跟踪该调用时,它将转到此功能;

void hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
    hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
    if (!instance){
        log_error("no instance for handle 0x%02x", con_handle);
        return;
    }
    att_server_notify(con_handle, instance->hid_report_input_value_handle, report, report_len);
}

实际使用 instance->hid_report_input_value_handle而不是hid_descriptor_keyboard_boot_mode;我也知道为什么(以防人们想知道);规格提到;

HID子类1为引导设备定义了两个描述符。设备可能 将其他数据附加到这些引导报告中,但是键盘报告的前8个字节和鼠标报告的前3个字节必须符合启动报告描述符定义的格式,以便BIOS正确解释数据。/blockquote>

... snip ...

加载HID类驱动程序时,它将发布更改协议, 阅读启动接口的报告描述符后,从引导协议更改为报告协议。

因此,在调用更改协议之后;该报告已加载到hid_report_input_value_handle中。因此,到目前为止,一切都清楚了。

然后主要的问题出现了;如何将消费者控件发送到配对设备?这只是添加reportId的问题吗?例如

对于键盘键作为键盘事件:

uint8_t report[] = { 0x01, modifier, 0, 0, keycode, 0, 0, 0, 0, 0};
hids_device_send_input_report(con_handle, report, sizeof(report));

和用于消费者控制(播放/暂停)作为键盘事件:

uint8_t report[] = { 0x02, 0xCD, 0x00};
hids_device_send_input_report(con_handle, report, sizeof(report));

这是正确的吗?欢迎任何指导,BLE对我来说是新的。

键盘隐藏了描述符,鉴于它代表以下C结构:

//--------------------------------------------------------------------------------
// Keyboard/Keypad Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                     // Collection: CA:Keyboard
  uint8_t  KB_KeyboardKeyboardLeftControl : 1;       // Usage 0x000700E0: Keyboard Left Control, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftShift : 1;         // Usage 0x000700E1: Keyboard Left Shift, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftAlt : 1;           // Usage 0x000700E2: Keyboard Left Alt, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftGui : 1;           // Usage 0x000700E3: Keyboard Left GUI, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightControl : 1;      // Usage 0x000700E4: Keyboard Right Control, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightShift : 1;        // Usage 0x000700E5: Keyboard Right Shift, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightAlt : 1;          // Usage 0x000700E6: Keyboard Right Alt, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightGui : 1;          // Usage 0x000700E7: Keyboard Right GUI, Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  Keyboard[6];                              // Value = 0 to 255
} inputReport01_t;

...然后我希望发送功能看起来像:

uint8_t report[] = { 0x01, modifier, 0, keycode, 0, 0, 0, 0, 0}; // <-- i.e. one less byte
hids_device_send_input_report(con_handle, report, sizeof(report));

至于消费者设备报告,HID报告描述符似乎很不错。它应该是类似的(假设它与键盘报告描述符连接):

/*
   Consumer Control
 */
0x05, 0x0C,                     // Usage Page (Consumer Devices)
0x09, 0x01,                     // Usage (Consumer Control)
0xA1, 0x01,                     // Collection (Application)
0x85, 0x02,                     //      Report ID
0x75, 0x10,                     //      Report Size (16)
0x95, 0x01,                     //     Report Count (1)
0x26, 0xFF, 0x07,               //      Logical Maximum (2047)
0x19, 0x00,                     //      Usage Minimum (0)
0x2A, 0xFF, 0x07,               //      Usage Maximum (2047)
0x81, 0x00,                     //      Input (Data, Ary, Abs)
0xC0,

...代表以下C结构:

//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 0C        (GLOBAL) USAGE_PAGE         0x000C Consumer Device Page 
09 01        (LOCAL)  USAGE              0x000C0001 Consumer Control (Application Collection)  
A1 01        (MAIN)   COLLECTION         0x01 Application (Usage=0x000C0001: Page=Consumer Device Page, Usage=Consumer Control, Type=Application Collection)
85 02          (GLOBAL) REPORT_ID          0x02 (2)  
75 10          (GLOBAL) REPORT_SIZE        0x10 (16) Number of bits per field  
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields  
26 FF07        (GLOBAL) LOGICAL_MAXIMUM    0x07FF (2047)  
19 00          (LOCAL)  USAGE_MINIMUM      0x000C0000 Unassigned  <-- Info: Consider replacing 19 00 with 18
2A FF07        (LOCAL)  USAGE_MAXIMUM      0x000C07FF 
81 00          (MAIN)   INPUT              0x00000000 (1 field x 16 bits) 0=Data 0=Array 0=Absolute 
C0           (MAIN)   END_COLLECTION     Application 
*/
//--------------------------------------------------------------------------------
// Consumer Device Page inputReport 02 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x02 (2)
                                                     // Collection: CA:ConsumerControl
  uint16_t ConsumerControl;                          // Value = 0 to 2047
} inputReport02_t;

...在这种情况下,发送消费者设备请求的功能应无需修改即可工作:

uint8_t report[] = { 0x02, 0xCD, 0x00};
hids_device_send_input_report(con_handle, report, sizeof(report));

...发送播放/暂停请求。

不要忘记通过按照每次发送(在键盘的情况下)来表示"无键":

uint8_t report[] = { 0x01, modifier, 0, 0, 0, 0, 0, 0, 0}; // no keys pressed
hids_device_send_input_report(con_handle, report, sizeof(report));

这相当于传统的"密钥"通知。

最新更新