C USB HID多点触控串行报告
我正在创建一个Arduino设备,它连接到Windows计算机并模拟计算机上的触摸屏。屏幕不属于Arduino,而是Arduino通过USB将HID触摸信息中继到Windows 10计算机 我做的第一件事是传递绝对鼠标事件,而不是数字化仪事件。这对我很管用。但是,由于我的设备支持多点触摸,我希望使用多点触摸隐藏消息,而不是绝对鼠标。作为概念的证明,我从只传递一个手指的数据开始。(我计划在这项工作开始后再增加手指)。我采用SerialReport方法,因为它似乎是最容易实现的:C USB HID多点触控串行报告,c,windows,arduino,usb,hid,C,Windows,Arduino,Usb,Hid,我正在创建一个Arduino设备,它连接到Windows计算机并模拟计算机上的触摸屏。屏幕不属于Arduino,而是Arduino通过USB将HID触摸信息中继到Windows 10计算机 我做的第一件事是传递绝对鼠标事件,而不是数字化仪事件。这对我很管用。但是,由于我的设备支持多点触摸,我希望使用多点触摸隐藏消息,而不是绝对鼠标。作为概念的证明,我从只传递一个手指的数据开始。(我计划在这项工作开始后再增加手指)。我采用SerialReport方法,因为它似乎是最容易实现的: 我发现了很
#define REPORTID_MTOUCH 1
static const uint8_t _hidSerialMultiTouchDescriptor[] PROGMEM = {
// https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/sample-report-descriptor--serial-reporting-mode-
// Linked from: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/selecting-packet-reporting-modes-in-multitouch-drivers
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x04, // USAGE (Touch Screen)
0xa1, 0x01, // COLLECTION (Application)
0x85, REPORTID_MTOUCH, // REPORT_ID (Touch)
0x09, 0x22, // USAGE (Finger)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x42, // USAGE (Tip Switch)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)
0x09, 0x32, // USAGE (In Range)
0x09, 0x47, // USAGE (Confidence)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x0a, // REPORT_COUNT (10)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desk..
0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x65, 0x00, // UNIT (None)
0x09, 0x30, // USAGE (X)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x31, // USAGE (Y)
0x46, 0x00, 0x00, // PHYSICAL_MAXIMUM (0)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x0d, // USAGE PAGE (Digitizers)
0x09, 0x48, // USAGE (Width)
0x09, 0x49, // USAGE (Height)
0x95, 0x01, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)
0x09, 0x51, // USAGE (Contact Identifier)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x02, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x55, // USAGE(Maximum Count)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x08, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
这是我对上述信息的实现:
typedef union {
struct{
uint8_t TipSwitchLsb4Bits_InRange_Confidence_Empty2Bits;
uint8_t Padding8_10Minus2;
int16_t xAxis;
int16_t yAxis;
int16_t width;
int16_t height;
int16_t ContactId;
uint8_t MaximumCount;
};
} HID_SerialTouchReport;
void reportTouch(unsigned int x, unsigned int y) {
HID_SerialTouchReport report;
report.TipSwitchLsb4Bits_InRange_Confidence_Empty2Bits = 0xff;
report.xAxis = x;
report.yAxis = y;
report.width = 4;
report.height = 4;
report.ContactId = 0;
report.MaximumCount = 1;
HID().SendReport(REPORTID_MTOUCH, &report, sizeof(report));
}
...
static HIDSubDescriptor node(_hidSerialMultiTouchDescriptor, sizeof(_hidSerialMultiTouchDescriptor));
HID().AppendDescriptor(&node);
...
//Move the pointer diagonally across the screen:
for(unsigned int x=0; x<32767; x+=1000) {
reportTouch(x, x);
delay(50);
}
typedef联合{
结构{
单位8位TIPSwitchLSB4位在量程内,单位2位为空;
uint8_t填充8_10分钟2;
int16_t xAxis;
int16_t yAxis;
内部宽度;
内部高度;
int16_t ContactId;
uint8_t最大计数;
};
}HID_报告;
void reportTouch(无符号整数x,无符号整数y){
HID_报告;
report.TipSwitchLsb4Bits\u InRange\u Confidence\u Empty2Bits=0xff;
report.xAxis=x;
report.yAxis=y;
报告宽度=4;
报告高度=4;
report.ContactId=0;
report.MaximumCount=1;
HID().SendReport(REPORTID_MTOUCH和report,sizeof(report));
}
...
静态HIDSubDescriptor节点(_hidSerialMultiTouchDescriptor,sizeof(_hidSerialMultiTouchDescriptor));
HID().AppendDescriptor(&node);
...
//在屏幕上沿对角线方向移动指针:
对于(unsigned int x=0;x很难确定,但HID报告描述符似乎与您的HID_SerialTouchReport结构不匹配。以下是我解码描述符的方式:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 0D (GLOBAL) USAGE_PAGE 0x000D Digitizer Device Page
09 04 (LOCAL) USAGE 0x000D0004 Touch Screen (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x000D0004: Page=Digitizer Device Page, Usage=Touch Screen, Type=CA)
85 01 (GLOBAL) REPORT_ID 0x01 (1)
09 22 (LOCAL) USAGE 0x000D0022 Finger (CL=Logical Collection)
A1 00 (MAIN) COLLECTION 0x00000000 Physical (Usage=0x000D0022: Page=Digitizer Device Page, Usage=Finger, Type=CL) <-- Warning: USAGE type should be CP (Physical)
09 42 (LOCAL) USAGE 0x000D0042 Tip Switch (MC=Momentary Control)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
81 02 (MAIN) INPUT 0x00000002 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
81 03 (MAIN) INPUT 0x00000003 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 32 (LOCAL) USAGE 0x000D0032 In Range (MC=Momentary Control)
09 47 (LOCAL) USAGE 0x000D0047 Confidence (DV=Dynamic Value)
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
81 02 (MAIN) INPUT 0x00000002 (2 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 0A (GLOBAL) REPORT_COUNT 0x0A (10) Number of fields
81 03 (MAIN) INPUT 0x00000003 (10 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
26 FF7F (GLOBAL) LOGICAL_MAXIMUM 0x7FFF (32767)
75 10 (GLOBAL) REPORT_SIZE 0x10 (16) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
65 00 (GLOBAL) UNIT 0x00000000 No unit (0=None) <-- Redundant: UNIT is already 0x00000000
09 30 (LOCAL) USAGE 0x00010030 X (DV=Dynamic Value)
81 02 (MAIN) INPUT 0x00000002 (1 field x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 31 (LOCAL) USAGE 0x00010031 Y (DV=Dynamic Value)
46 0000 (GLOBAL) PHYSICAL_MAXIMUM 0x0000 (0) <-- Redundant: PHYSICAL_MAXIMUM is already 0 <-- Info: Consider replacing 46 0000 with 44
81 02 (MAIN) INPUT 0x00000002 (1 field x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 0D (GLOBAL) USAGE_PAGE 0x000D Digitizer Device Page
09 48 (LOCAL) USAGE 0x000D0048 Width (DV=Dynamic Value)
09 49 (LOCAL) USAGE 0x000D0049 Height (DV=Dynamic Value)
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
81 02 (MAIN) INPUT 0x00000002 (1 field x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
81 03 (MAIN) INPUT 0x00000003 (1 field x 16 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 51 (LOCAL) USAGE 0x000D0051 Contact Identifier (DV=Dynamic Value)
75 10 (GLOBAL) REPORT_SIZE 0x10 (16) Number of bits per field <-- Redundant: REPORT_SIZE is already 16
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
81 02 (MAIN) INPUT 0x00000002 (2 fields x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 55 (LOCAL) USAGE 0x000D0055 Contact Count Maximum (SV=Static Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 08 (GLOBAL) LOGICAL_MAXIMUM 0x08 (8)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
B1 02 (MAIN) FEATURE 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Digitizer Device Page featureReport 01 (Device <-> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: TouchScreen Finger
uint8_t DIG_TouchScreenFingerContactCountMaximum; // Usage 0x000D0055: Contact Count Maximum, Value = 0 to 8
} featureReport01_t;
//--------------------------------------------------------------------------------
// Digitizer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: TouchScreen Finger
uint8_t DIG_TouchScreenFingerTipSwitch : 1; // Usage 0x000D0042: Tip Switch, Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t DIG_TouchScreenFingerInRange : 1; // Usage 0x000D0032: In Range, Value = 0 to 1
uint8_t DIG_TouchScreenFingerConfidence : 1; // Usage 0x000D0047: Confidence, 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 : 1; // Pad
uint8_t : 1; // Pad
uint16_t GD_TouchScreenFingerX; // Usage 0x00010030: X, Value = 0 to 32767
uint16_t GD_TouchScreenFingerY; // Usage 0x00010031: Y, Value = 0 to 32767
uint16_t DIG_TouchScreenFingerWidth; // Usage 0x000D0048: Width, Value = 0 to 32767
// Usage 0x000D0049 Height (DV=Dynamic Value) Value = 0 to 32767 <-- Ignored: REPORT_COUNT (1) is too small
uint16_t pad_8; // Pad
uint16_t DIG_TouchScreenFingerContactIdentifier[2]; // Usage 0x000D0051: Contact Identifier, Value = 0 to 32767
} inputReport01_t;
maximumcount似乎是“Contact Count Maximum”用法,即同时按下的最大手指数,是功能报告的一部分(可从设备发送或接收)。报表描述符指示它可以同时按下0个手指和8个手指之间的值。0x09、0x48、//使用率(宽度)0x09、0x49、//使用率(高度)0x95、0x01、//报表计数(2)…应该是:0x09、0x48、//用法(宽度)0x09、0x49、//用法(高度)0x95、0x02、//报告计数(2)(很抱歉缩进)
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 0D (GLOBAL) USAGE_PAGE 0x000D Digitizer Device Page
09 04 (LOCAL) USAGE 0x000D0004 Touch Screen (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x000D0004: Page=Digitizer Device Page, Usage=Touch Screen, Type=CA)
85 01 (GLOBAL) REPORT_ID 0x01 (1)
09 22 (LOCAL) USAGE 0x000D0022 Finger (CL=Logical Collection)
A1 00 (MAIN) COLLECTION 0x00000000 Physical (Usage=0x000D0022: Page=Digitizer Device Page, Usage=Finger, Type=CL) <-- Warning: USAGE type should be CP (Physical)
09 42 (LOCAL) USAGE 0x000D0042 Tip Switch (MC=Momentary Control)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
81 02 (MAIN) INPUT 0x00000002 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
81 03 (MAIN) INPUT 0x00000003 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 32 (LOCAL) USAGE 0x000D0032 In Range (MC=Momentary Control)
09 47 (LOCAL) USAGE 0x000D0047 Confidence (DV=Dynamic Value)
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
81 02 (MAIN) INPUT 0x00000002 (2 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 0A (GLOBAL) REPORT_COUNT 0x0A (10) Number of fields
81 03 (MAIN) INPUT 0x00000003 (10 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
26 FF7F (GLOBAL) LOGICAL_MAXIMUM 0x7FFF (32767)
75 10 (GLOBAL) REPORT_SIZE 0x10 (16) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
09 30 (LOCAL) USAGE 0x00010030 X (DV=Dynamic Value)
81 02 (MAIN) INPUT 0x00000002 (1 field x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 31 (LOCAL) USAGE 0x00010031 Y (DV=Dynamic Value)
81 02 (MAIN) INPUT 0x00000002 (1 field x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 0D (GLOBAL) USAGE_PAGE 0x000D Digitizer Device Page
09 48 (LOCAL) USAGE 0x000D0048 Width (DV=Dynamic Value)
09 49 (LOCAL) USAGE 0x000D0049 Height (DV=Dynamic Value)
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
81 02 (MAIN) INPUT 0x00000002 (2 fields x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 51 (LOCAL) USAGE 0x000D0051 Contact Identifier (DV=Dynamic Value)
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
81 02 (MAIN) INPUT 0x00000002 (1 field x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 55 (LOCAL) USAGE 0x000D0055 Contact Count Maximum (SV=Static Value)
25 08 (GLOBAL) LOGICAL_MAXIMUM 0x08 (8)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
B1 02 (MAIN) FEATURE 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Digitizer Device Page featureReport 01 (Device <-> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: TouchScreen Finger
uint8_t DIG_TouchScreenFingerContactCountMaximum; // Usage 0x000D0055: Contact Count Maximum, Value = 0 to 8
} featureReport01_t;
//--------------------------------------------------------------------------------
// Digitizer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: TouchScreen Finger
uint8_t DIG_TouchScreenFingerTipSwitch : 1; // Usage 0x000D0042: Tip Switch, Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t DIG_TouchScreenFingerInRange : 1; // Usage 0x000D0032: In Range, Value = 0 to 1
uint8_t DIG_TouchScreenFingerConfidence : 1; // Usage 0x000D0047: Confidence, 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 : 1; // Pad
uint8_t : 1; // Pad
uint16_t GD_TouchScreenFingerX; // Usage 0x00010030: X, Value = 0 to 32767
uint16_t GD_TouchScreenFingerY; // Usage 0x00010031: Y, Value = 0 to 32767
uint16_t DIG_TouchScreenFingerWidth; // Usage 0x000D0048: Width, Value = 0 to 32767
uint16_t DIG_TouchScreenFingerHeight; // Usage 0x000D0049: Height, Value = 0 to 32767
uint16_t DIG_TouchScreenFingerContactIdentifier; // Usage 0x000D0051: Contact Identifier, Value = 0 to 32767
} inputReport01_t;
// var is like:
uint8_t my_value1;
uint8_t my_value2;
// ary is like:
uint8_t my_value[2];