最近在做USB touchpad,发现touchpad和touchscreen有些区别,而且不同的操作系统也有些差异,下面以windows系统进行说明:
根据微软文档(https://docs.microsoft.com/zh-cn/windows-hardware/design/component-guidelines/windows-precision-touchpad-required-hid-top-level-collections),一台 Windows 精确式触摸板设备应公开 3 个必需的顶级集合;Windows 精确式触摸板、鼠标和配置。 还可以实现可选(建议)的固件更新集合。实际测试时发现不要鼠标集合时,触控按钮是有效的,但光标无法移动。
微软给了touchpad的报告标识符示例(https://docs.microsoft.com/zh-cn/windows-hardware/design/component-guidelines/windows-precision-touchpad-sample-report-descriptors),但需要执行定义report id(不重复,不为0即可)
//TOUCH PAD input TLC
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x05, // USAGE (Touch Pad)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORTID_TOUCHPAD, // REPORT_ID (Touch pad)
0x09, 0x22, // USAGE (Finger)
0xa1, 0x02, // COLLECTION (Logical)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x09, 0x47, // USAGE (Confidence)
0x09, 0x42, // USAGE (Tip switch)
0x95, 0x02, // REPORT_COUNT (2)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x02, // REPORT_SIZE (2)
0x25, 0x02, // LOGICAL_MAXIMUM (2)
0x09, 0x51, // USAGE (Contact Identifier)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desk..
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x0f, // LOGICAL_MAXIMUM (4095)
0x75, 0x10, // REPORT_SIZE (16)
0x55, 0x0e, // UNIT_EXPONENT (-2)
0x65, 0x13, // UNIT(Inch,EngLinear)
0x09, 0x30, // USAGE (X)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0x90, 0x01, // PHYSICAL_MAXIMUM (400)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x46, 0x13, 0x01, // PHYSICAL_MAXIMUM (275)
0x09, 0x31, // USAGE (Y)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x55, 0x0C, // UNIT_EXPONENT (-4)
0x66, 0x01, 0x10, // UNIT (Seconds)
0x47, 0xff, 0xff, 0x00, 0x00, // PHYSICAL_MAXIMUM (65535)
0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x56, // USAGE (Scan Time)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x54, // USAGE (Contact count)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x09, 0x01, // USAGE_(Button 1)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x07, // REPORT_COUNT (7)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x0d, // USAGE_PAGE (Digitizer)
0x85, REPORTID_MAX_COUNT, // REPORT_ID (Feature)
0x09, 0x55, // USAGE (Contact Count Maximum)
0x09, 0x59, // USAGE (Pad TYpe)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x02, // REPORT_COUNT (2)
0x25, 0x0f, // LOGICAL_MAXIMUM (15)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined)
0x85, REPORTID_PTPHQA, // REPORT_ID (PTPHQA)
0x09, 0xC5, // USAGE (Vendor Usage 0xC5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (0xff)
0x75, 0x08, // REPORT_SIZE (8)
0x96, 0x00, 0x01, // REPORT_COUNT (0x100 (256))
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0xc0, // END_COLLECTION
//CONFIG TLC
0x05, 0x0d, // USAGE_PAGE (Digitizer)
0x09, 0x0E, // USAGE (Configuration)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORTID_FEATURE, // REPORT_ID (Feature)
0x09, 0x22, // USAGE (Finger)
0xa1, 0x02, // COLLECTION (logical)
0x09, 0x52, // USAGE (Input Mode)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x0a, // LOGICAL_MAXIMUM (10)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0xb1, 0x02, // FEATURE (Data,Var,Abs
0xc0, // END_COLLECTION
0x09, 0x22, // USAGE (Finger)
0xa1, 0x00, // COLLECTION (physical)
0x85, REPORTID_FUNCTION_SWITCH, // REPORT_ID (Feature)
0x09, 0x57, // USAGE(Surface switch)
0x09, 0x58, // USAGE(Button switch)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT (2)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
//MOUSE TLC
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORTID_MOUSE, // REPORT_ID (Mouse)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x02, // USAGE_MAXIMUM (Button 2)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x02, // REPORT_COUNT (2)
0x25, 0x0a, // LOGICAL_MAXIMUM (10)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0, //END_COLLECTION
此描述符对应的报文数据结构如下:
typedef struct{
uint8_t confidence:1;
uint8_t tip:1;
uint8_t contact_id:2;
uint8_t padding0:4;
uint16_t x;
uint16_t y;
uint16_t scan_time;
uint8_t contact_count;
uint8_t button1:1
uint8_t padding1:7;
}toupad_report_t;
typedef struct{
uint8_t button1:1;
uint8_t button2:1;
uint8_t padding0:6
uint16_t x;
uint16_t y;
}mouse_report_t;
注意事项:
1.由于有多个report, 对应报文回复时需要在第0字节添加对应的report ID
2.需要回应REPORTID_MAX_COUNT对应的get_report请求,否则后续发送touchpad数据系统无反应,但mouse数据有反应,返回get report时第一个字节为REPORTID_MAX_COUNT的report ID, 后面为报告描述符里的结构,这里按照如下结构返回,测试时实际返回(0x11)
0x05, 0x0d, // USAGE_PAGE (Digitizer)
0x85, REPORTID_MAX_COUNT, // REPORT_ID (Feature)
0x09, 0x55, // USAGE (Contact Count Maximum)
0x09, 0x59, // USAGE (Pad TYpe)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x02, // REPORT_COUNT (2)
0x25, 0x0f, // LOGICAL_MAXIMUM (15)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
typedef struct{
uint8_t cout_max: 4;
uint8_t pad_type: 4; /* ref Universal Serial Bus HID Usage Tables: When set, the touchpad is non-depressible(pressure-pad); when clear, the touchpad is depressible (click-pad) */
}