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

问题描述 投票:0回答:1

我有一个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,

问题是,in the provided demo code;发送报告的代码是这样的:

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));
}

这适用于发送击键;当我在源代码中跟踪该调用时,它会进入to this function;

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;我也知道为什么(如果人们想知道); The spec mentions;

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

...略...

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

所以在调用更改协议之后;该报告被加载到hid_report_input_value_handle。所以到现在为止,一切都很清楚。

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

对于键盘键作为keydown事件:

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

对于消费者控制(播放/暂停)作为keydown事件:

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

这是正确的吗?任何指导都会受到欢迎,BLE对我来说是个新问题。

bluetooth-lowenergy hid bluetooth-gatt
1个回答
0
投票

对于键盘HID描述符,假设它代表以下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;

...然后我希望send函数看起来像:

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));

这相当于传统的“密钥向上”通知。

© www.soinside.com 2019 - 2024. All rights reserved.