为何带17个按键的游戏手柄HID描述符无法正常工作?
HID游戏手柄报告描述符修改后连接异常排查
我当前使用的HID报告描述符如下:
static unsigned char hid_report_descriptor[] __attribute__ ((aligned(64))) = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x05, // Usage (Game Pad) 0xA1, 0x01, // Collection (Application) 0xA1, 0x00, // Collection (Physical) 0x85, 0x01, // Report ID (1) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (0x01) 0x29, 0x10, // Usage Maximum (0x10) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x95, 0x10, // Report Count (16) 0x75, 0x01, // Report Size (1) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x09, 0x32, // Usage (Z) 0x09, 0x33, // Usage (Rx) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x75, 0x08, // Report Size (8) 0x95, 0x04, // Report Count (4) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xC0, // End Collection };
对应的结构体定义为:
struct GamepadReport { uint8_t report_id; uint16_t buttons; int8_t left_x; int8_t left_y; int8_t right_x; int8_t right_y; } __attribute__((packed));
我想添加一个类似Xbox控制器Home键的额外按键,原本以为只要将描述符中的0x29, 0x10(Usage Maximum)改为0x29, 0x11,同时把0x95, 0x10(Report Count)改为0x95, 0x11即可,但修改后自定义控制器出现连接异常,求排查原因。
问题原因与解决方法
- 核心问题:HID报告长度未对齐
HID设备的输入/输出报告总位数必须是8的整数倍(即总长度为整数字节)。原描述符中按钮部分是16位(正好2字节),修改为17位后,总位数无法被8整除,主机解析报告时会判定设备格式无效,直接拒绝连接。同时对应的结构体仍用uint16_t buttons,也会导致数据错位,进一步加剧解析错误。 - 修正步骤:
- 调整报告描述符:将按钮的
Report Count从0x95, 0x11改为0x95, 0x18(24位,3字节),保留0x29, 0x11作为Usage Maximum。这样既包含了需要的17个按钮,剩余7位作为保留位,满足字节对齐要求。修改后的按钮段描述符如下:0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (0x01) 0x29, 0x11, // Usage Maximum (0x11) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x95, 0x18, // Report Count (24) 0x75, 0x01, // Report Size (1) 0x81, 0x02, // Input (Data,Var,Abs,...) - 更新对应结构体:将
uint16_t buttons替换为uint32_t buttons(或3个连续的uint8_t),确保结构体的字节长度与描述符定义的报告长度匹配。修改后的结构体示例:struct GamepadReport { uint8_t report_id; uint32_t buttons; // 用32位容纳24位按钮数据,高位空闲 int8_t left_x; int8_t left_y; int8_t right_x; int8_t right_y; } __attribute__((packed)); - 验证报告总长度:修改后的报告总长度为1(report_id)+3(buttons)+4(轴数据)=8字节,对应描述符中总位数:18 +24 +48=8+24+32=64位,正好是8字节,符合HID规范要求。
- 调整报告描述符:将按钮的
内容的提问来源于stack exchange,提问作者Carlos Santos
相关产品推荐
相关产品推荐

