From 253bb3d7b2fe12637aeba44ece3259f582d71c0d Mon Sep 17 00:00:00 2001 From: weilking Date: Wed, 24 Sep 2025 11:12:16 +0200 Subject: [PATCH 1/6] Handle report_count > len of usages. temp fix --- hid_parser/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hid_parser/__init__.py b/hid_parser/__init__.py index 448d46f..70ef8df 100644 --- a/hid_parser/__init__.py +++ b/hid_parser/__init__.py @@ -788,8 +788,7 @@ def _append_items( if len(usages) > report_count: report_count = len(usages) else: - missing_usage_count = report_count - len(usages) - usages += [] * missing_usage_count + usages.append(usages[0]) for usage in usages: item = VariableItem( From f9c67a3087e5d369ba5c5ed5ff10fa67802ada82 Mon Sep 17 00:00:00 2001 From: weilking Date: Wed, 24 Sep 2025 11:20:01 +0200 Subject: [PATCH 2/6] Fill missing usage with first usage in list, when report count > usage number Cover the scenario, where only one usage, but has two report count Usage Report Count 2 --- hid_parser/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hid_parser/__init__.py b/hid_parser/__init__.py index 70ef8df..ca1c7df 100644 --- a/hid_parser/__init__.py +++ b/hid_parser/__init__.py @@ -788,7 +788,8 @@ def _append_items( if len(usages) > report_count: report_count = len(usages) else: - usages.append(usages[0]) + for i in range(report_count - len(usages)): + usages.append(usages[0]) for usage in usages: item = VariableItem( From 7f19ead708162f8420bd8d484ef3de9cc6a4fb81 Mon Sep 17 00:00:00 2001 From: weilking Date: Wed, 24 Sep 2025 16:02:20 +0200 Subject: [PATCH 3/6] Add windows touch digitizer example --- tests/test_parse.py | 255 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/tests/test_parse.py b/tests/test_parse.py index ae44ef6..1dd43d2 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -159,6 +159,260 @@ 0xc0, # End Collection 233 ] +windows_touch_rdesc = [ + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x04, # Usage (Touch Screen) + 0xA1, 0x01, # Collection (Application) + 0x85, 0x01, # Report ID (1) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x35, 0x00, # Physical Minimum (0) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x56, # Usage (0x56) + 0x27, 0xFF, 0xFF, 0xFF, 0x7F, # Logical Maximum (2147483646) + 0x45, 0x00, # Physical Maximum (0) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x20, # Report Size (32) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x54, # Usage (0x54) + 0x25, 0x7F, # Logical Maximum (127) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x85, 0x0A, # Report ID (10) + 0x09, 0x55, # Usage (0x55) + 0x25, 0x0A, # Logical Maximum (10) + 0xB1, 0x02, # Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x96, 0xF8, 0x07, # Report Count (2040) + 0xB1, 0x03, # Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x44, # Report ID (68) + 0x06, 0x00, 0xFF, # Usage Page (Vendor Defined 0xFF00) + 0x09, 0xC5, # Usage (0xC5) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x08, # Report Size (8) + 0x96, 0x00, 0x01, # Report Count (256) + 0xB1, 0x02, # Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC1, 0x00, # End Collection +] + # fmt: on @@ -167,6 +421,7 @@ [ simple_mouse_rdesc, linux_hidpp_rdesc, + windows_touch_rdesc, ], ) def test_parse(rdesc): From 4c1949cfec16153ae59fec59fb313d599eac7ce2 Mon Sep 17 00:00:00 2001 From: Wei Jing Date: Wed, 24 Sep 2025 22:52:25 +0200 Subject: [PATCH 4/6] 1. Update test cases for touch digitizer. 2 add usage data for digitizer --- hid_parser/__init__.py | 4 +- hid_parser/data.py | 63 ++++++++- tests/test_parse.py | 76 ++++++++++ tests/test_print.py | 256 ++++++++++++++++++++++++++++++++++ tests/windows-touch-print.txt | 251 +++++++++++++++++++++++++++++++++ 5 files changed, 647 insertions(+), 3 deletions(-) create mode 100644 tests/windows-touch-print.txt diff --git a/hid_parser/__init__.py b/hid_parser/__init__.py index ca1c7df..fe4b690 100644 --- a/hid_parser/__init__.py +++ b/hid_parser/__init__.py @@ -783,9 +783,9 @@ def _append_items( self._append_item(offset_list, pool, report_id, item) else: if len(usages) != report_count: - error_str = f'Expecting {report_count} usages but got {len(usages)}' - warnings.warn(HIDComplianceWarning(error_str), stacklevel=2) if len(usages) > report_count: + error_str = f'Expecting {report_count} usages but got {len(usages)}' + warnings.warn(HIDComplianceWarning(error_str), stacklevel=2) report_count = len(usages) else: for i in range(report_count - len(usages)): diff --git a/hid_parser/data.py b/hid_parser/data.py index 232f390..4a5a397 100644 --- a/hid_parser/data.py +++ b/hid_parser/data.py @@ -1069,6 +1069,67 @@ class PowerDevice(UsagePage): ISERIALNUMBER = 0xFF, 'iSerialNumber', UsageTypes.SV +class Digitizer(UsagePage): + UNDEFINED = 0x00, 'Undefined' + DIGITIZER = 0x01, 'Digitizer', UsageTypes.CA + PEN = 0x02, 'Pen', UsageTypes.CA + LIGHT_PEN = 0x03, 'Light Pen', UsageTypes.CA + TOUCH_SCREEN = 0x04, 'Touch Screen', UsageTypes.CA + TOUCH_PAD = 0x05, 'Touch Pad', UsageTypes.CA + WHITE_BOARD = 0x06, 'White Board', UsageTypes.CA + COORDINATE_MEASURING_MACHINE = 0x07, 'Coordinate Measuring Machine', UsageTypes.CA + D3_DIGITIZER = 0x08, '3D Digitizer', UsageTypes.CA + STEREO_PLOTTER = 0x09, 'Stereo Plotter', UsageTypes.CA + ARTICULATION_DEVICE = 0x0A, 'Articulation Device', UsageTypes.CA + ARMATURE = 0x0B, 'Armature', UsageTypes.CA + MULTIPOINT_DIGITIZER = 0x0C, 'Multiple Point Digitizer', UsageTypes.CA + FREE_SPACE_WANDERER = 0x0D, 'Free Space Wanderer', UsageTypes.CA + STYLUS = 0x20, 'Stylus', UsageTypes.CL + PUCK = 0x21, 'Puck', UsageTypes.CL + FINGER = 0x22, 'Finger', UsageTypes.CL + TIP_PRESSURE = 0x30, 'Tip Pressure', UsageTypes.DV + BARREL_PRESSURE = 0x31, 'Barrel Pressure', UsageTypes.DV + IN_RANGE = 0x32, 'In Range', UsageTypes.MC + TOUCH = 0x33, 'Touch', UsageTypes.MC + UNTOUCH = 0x34, 'Untouch', UsageTypes.MC + TAP = 0x35, 'Tap', UsageTypes.MC + QUALITY = 0x36, 'Quality', UsageTypes.DV + DATA_VALID = 0x37, 'Data Valid', UsageTypes.MC + TRANSDUCER_INDEX = 0x38, 'Transducer Index', UsageTypes.DV + TABLET_FUNCTION_KEYS = 0x39, 'Tablet Function Keys', UsageTypes.CL + PROGRAM_CHANGE_KEYS = 0x3A, 'Program Change Keys', UsageTypes.CL + BATTERY_STRENGTH = 0x3B, 'Battery Strength', UsageTypes.DV + INVERT = 0x3C, 'Invert', UsageTypes.MC + X_TILT = 0x3D, 'X Tilt', UsageTypes.DV + Y_TILT = 0x3E, 'Y Tilt', UsageTypes.DV + AZIMUTH = 0x3F, 'Azimuth', UsageTypes.DV + ALTITUDE = 0x40, 'Altitude', UsageTypes.DV + TWIST = 0x41, 'Twist', UsageTypes.DV + TIP_SWITCH = 0x42, 'Tip Switch', UsageTypes.MC + SECONDARY_TIP_SWITCH = 0x43, 'Secondary Tip Switch', UsageTypes.MC + BARREL_SWITCH = 0x44, 'Barrel Switch', UsageTypes.MC + ERASER = 0x45, 'Eraser', UsageTypes.MC + TABLET_PICK = 0x46, 'Tablet Pick', UsageTypes.MC + TOUCH_VALID = 0x47, 'Touch Valid', UsageTypes.MC + WIDTH = 0x48, 'Width', UsageTypes.DV + HEIGHT = 0x49, 'Height', UsageTypes.DV + CONTACT_ID = 0x51, 'Contact Identifier', UsageTypes.DV + DEVICE_MODE = 0x52, 'Device Mode', UsageTypes.DV + DEVICE_IDENTIFIER = 0x53, 'Device Identifier', UsageTypes.DV + CONTACT_COUNT = 0x54, 'Contact Count', UsageTypes.DV + CONTACT_COUNT_MAX = 0x55, 'Contact Count Maximum', UsageTypes.SV + SCAN_TIME = 0x56, 'Scan Time', UsageTypes.DV + SURFACE_SWITCH = 0x57, 'Surface Switch', UsageTypes.MC + BUTTON_SWITCH = 0x58, 'Button Switch', UsageTypes.MC + PAD_TYPE = 0x59, 'Pad Type', UsageTypes.SF + SECONDARY_BARREL_SWITCH = 0x5A, 'Secondary Barrel Switch', UsageTypes.MC + TRANSDUCER_SERIAL_NUMBER = 0x5B, 'Transducer Serial Number', UsageTypes.SV + PREFERRED_COLOR = 0x5C, 'Preferred Color', UsageTypes.CL + PREFERRED_COLOR_IS_LOCKED = 0x5D, 'Preferred Color is Locked', UsageTypes.OOC + PREFERRED_LINE_WIDTH = 0x5E, 'Preferred Line Width', UsageTypes.DV + PREFERRED_LINE_WIDTH_IS_LOCKED = 0x5F, 'Preferred Line Width is Locked', UsageTypes.OOC + SUPPORTED_COLORS = 0x60, 'Supported Colors', UsageTypes.NARY + class FIDO(UsagePage): U2F_AUTHENTICATOR_DEVICEM = 0x01, 'U2F Authenticator Device' INPUT_REPORT_DATA = 0x20, 'Input Report Data' @@ -1088,7 +1149,7 @@ class UsagePages(_Data[UsagePage]): ORDINAL_PAGE = 0x0A, 'Ordinal' TELEPHONY_PAGE = 0x0B, 'Telephony' CONSUMER_PAGE = 0x0C, 'Consumer', Consumer - DIGITIZER_PAGE = 0x0D, 'Digitizer' + DIGITIZER_PAGE = 0x0D, 'Digitizer', Digitizer HAPTICS_PAGE = 0x0E, 'Haptics' PID_PAGE = 0x0F, 'PID' UNICODE_PAGE = 0x10, 'Unicode' diff --git a/tests/test_parse.py b/tests/test_parse.py index 1dd43d2..c39b6d4 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -541,6 +541,82 @@ def test_linux_hidpp_items(): offset += 8 +def test_windows_touch_items(): + rdesc = hid_parser.ReportDescriptor(windows_touch_rdesc) + + assert rdesc.input_report_ids == [1] + assert rdesc.output_report_ids == [] + assert rdesc.feature_report_ids == [10, 68] + + items = rdesc.get_input_items(1) + + assert len(items) == 52 + + # First finger contact + assert isinstance(items[0], hid_parser.VariableItem) + assert int(items[0].offset) == 0 + assert int(items[0].size) == 1 + assert items[0].usage == hid_parser.Usage( + hid_parser.data.UsagePages.DIGITIZER_PAGE, hid_parser.data.Digitizer.TIP_SWITCH + ) + + assert isinstance(items[1], hid_parser.PaddingItem) + assert int(items[1].offset) == 1 + assert int(items[1].size) == 1 + + assert isinstance(items[2], hid_parser.VariableItem) + assert int(items[2].offset) == 2 + assert int(items[2].size) == 5 + assert items[2].usage == hid_parser.Usage( + hid_parser.data.UsagePages.DIGITIZER_PAGE, hid_parser.data.Digitizer.CONTACT_ID + ) + + assert isinstance(items[3], hid_parser.VariableItem) + assert int(items[3].offset) == 7 + assert int(items[3].size) == 1 + assert items[3].usage == hid_parser.Usage( + hid_parser.data.UsagePages.DIGITIZER_PAGE, hid_parser.data.Digitizer.TOUCH_VALID + ) + + assert isinstance(items[4], hid_parser.VariableItem) + assert int(items[4].offset) == 8 + assert int(items[4].size) == 8 + assert items[4].usage == hid_parser.Usage( + hid_parser.data.UsagePages.DIGITIZER_PAGE, hid_parser.data.Digitizer.WIDTH + ) + + assert isinstance(items[5], hid_parser.VariableItem) + assert int(items[5].offset) == 16 + assert int(items[5].size) == 8 + assert items[5].usage == hid_parser.Usage( + hid_parser.data.UsagePages.DIGITIZER_PAGE, hid_parser.data.Digitizer.HEIGHT + ) + + assert isinstance(items[6], hid_parser.VariableItem) + assert int(items[6].offset) == 24 + assert int(items[6].size) == 16 + assert items[6].usage == hid_parser.Usage( + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, hid_parser.data.GenericDesktopControls.X + ) + + assert isinstance(items[7], hid_parser.VariableItem) + assert int(items[7].offset) == 40 + assert int(items[7].size) == 16 + assert items[7].usage == hid_parser.Usage( + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, hid_parser.data.GenericDesktopControls.X + ) + + assert isinstance(items[8], hid_parser.VariableItem) + assert int(items[8].offset) == 56 + assert int(items[8].size) == 16 + assert items[8].usage == hid_parser.Usage( + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, hid_parser.data.GenericDesktopControls.Y + ) + + # The pattern repeats for 4 more fingers (items 8-39) + assert len(items[9:]) == 43 + + @hypothesis.given(st.lists(st.integers(), max_size=4096)) @hypothesis.example(simple_mouse_rdesc) @hypothesis.example(linux_hidpp_rdesc) diff --git a/tests/test_print.py b/tests/test_print.py index 374250d..184457b 100644 --- a/tests/test_print.py +++ b/tests/test_print.py @@ -160,6 +160,261 @@ 0xc0, # End Collection 233 ] + +windows_touch_rdesc = [ + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x04, # Usage (Touch Screen) + 0xA1, 0x01, # Collection (Application) + 0x85, 0x01, # Report ID (1) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x35, 0x00, # Physical Minimum (0) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x22, # Usage (Finger) + 0xA1, 0x02, # Collection (Logical) + 0x09, 0x42, # Usage (Tip Switch) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x01, # Report Size (1) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x51, # Usage (0x51) + 0x25, 0x3F, # Logical Maximum (63) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x05, # Report Size (5) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x47, # Usage (0x47) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x48, # Usage (0x48) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0xFF, # Physical Maximum (-1) + 0x65, 0x11, # Unit (System: SI Linear, Length: Centimeter) + 0x55, 0x0F, # Unit Exponent (-1) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x49, # Usage (0x49) + 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) + 0x26, 0xA4, 0x10, # Logical Maximum (4260) + 0x46, 0x24, 0x01, # Physical Maximum (292) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x31, # Usage (Y) + 0x26, 0x04, 0x0B, # Logical Maximum (2820) + 0x45, 0xC2, # Physical Maximum (-62) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC1, 0x00, # End Collection + 0x05, 0x0D, # Usage Page (Digitizer) + 0x09, 0x56, # Usage (0x56) + 0x27, 0xFF, 0xFF, 0xFF, 0x7F, # Logical Maximum (2147483646) + 0x45, 0x00, # Physical Maximum (0) + 0x65, 0x00, # Unit (None) + 0x55, 0x00, # Unit Exponent (0) + 0x75, 0x20, # Report Size (32) + 0x95, 0x01, # Report Count (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x54, # Usage (0x54) + 0x25, 0x7F, # Logical Maximum (127) + 0x75, 0x08, # Report Size (8) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x85, 0x0A, # Report ID (10) + 0x09, 0x55, # Usage (0x55) + 0x25, 0x0A, # Logical Maximum (10) + 0xB1, 0x02, # Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x25, 0x01, # Logical Maximum (1) + 0x45, 0x01, # Physical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x96, 0xF8, 0x07, # Report Count (2040) + 0xB1, 0x03, # Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x44, # Report ID (68) + 0x06, 0x00, 0xFF, # Usage Page (Vendor Defined 0xFF00) + 0x09, 0xC5, # Usage (0xC5) + 0x25, 0xFF, # Logical Maximum (-1) + 0x45, 0x00, # Physical Maximum (0) + 0x75, 0x08, # Report Size (8) + 0x96, 0x00, 0x01, # Report Count (256) + 0xB1, 0x02, # Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC1, 0x00, # End Collection +] + # fmt: on @@ -168,6 +423,7 @@ [ (simple_mouse_rdesc, 'simple-mouse-print.txt'), (linux_hidpp_rdesc, 'linux-hidpp-print.txt'), + (windows_touch_rdesc, 'windows-touch-print.txt'), ], ) def test_print(rdesc_raw, file): diff --git a/tests/windows-touch-print.txt b/tests/windows-touch-print.txt new file mode 100644 index 0000000..11a42aa --- /dev/null +++ b/tests/windows-touch-print.txt @@ -0,0 +1,251 @@ +Usage Page (Digitizer) +Usage (Touch Screen) +Collection (Application) + Report ID (0x01) + Usage (Finger) + Collection (Logical) + Usage (Tip Switch) + Logical Minimum (0) + Logical Maximum (1) + Physical Minimum (0) + Physical Maximum (1) + Unit (0x0000) + Unit Exponent (0x0000) + Report Size (1) + Report Count (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Input (Constant, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Contact Identifier) + Logical Maximum (63) + Physical Maximum (0) + Report Size (5) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Touch Valid) + Logical Maximum (1) + Physical Maximum (1) + Report Size (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Width) + Logical Maximum (-1) + Physical Maximum (-1) + Unit (0x0011) + Unit Exponent (0x000f) + Report Size (8) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Height) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage Page (Generic Desktop Controls) + Usage (X) + Logical Maximum (4260) + Physical Maximum (292) + Report Size (16) + Report Count (2) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Y) + Logical Maximum (2820) + Physical Maximum (-62) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + End Collection + Usage Page (Digitizer) + Usage (Finger) + Collection (Logical) + Usage (Tip Switch) + Logical Maximum (1) + Physical Maximum (1) + Unit (0x0000) + Unit Exponent (0x0000) + Report Size (1) + Report Count (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Input (Constant, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Contact Identifier) + Logical Maximum (63) + Physical Maximum (0) + Report Size (5) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Touch Valid) + Logical Maximum (1) + Physical Maximum (1) + Report Size (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Width) + Logical Maximum (-1) + Physical Maximum (-1) + Unit (0x0011) + Unit Exponent (0x000f) + Report Size (8) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Height) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage Page (Generic Desktop Controls) + Usage (X) + Logical Maximum (4260) + Physical Maximum (292) + Report Size (16) + Report Count (2) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Y) + Logical Maximum (2820) + Physical Maximum (-62) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + End Collection + Usage Page (Digitizer) + Usage (Finger) + Collection (Logical) + Usage (Tip Switch) + Logical Maximum (1) + Physical Maximum (1) + Unit (0x0000) + Unit Exponent (0x0000) + Report Size (1) + Report Count (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Input (Constant, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Contact Identifier) + Logical Maximum (63) + Physical Maximum (0) + Report Size (5) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Touch Valid) + Logical Maximum (1) + Physical Maximum (1) + Report Size (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Width) + Logical Maximum (-1) + Physical Maximum (-1) + Unit (0x0011) + Unit Exponent (0x000f) + Report Size (8) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Height) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage Page (Generic Desktop Controls) + Usage (X) + Logical Maximum (4260) + Physical Maximum (292) + Report Size (16) + Report Count (2) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Y) + Logical Maximum (2820) + Physical Maximum (-62) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + End Collection + Usage Page (Digitizer) + Usage (Finger) + Collection (Logical) + Usage (Tip Switch) + Logical Maximum (1) + Physical Maximum (1) + Unit (0x0000) + Unit Exponent (0x0000) + Report Size (1) + Report Count (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Input (Constant, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Contact Identifier) + Logical Maximum (63) + Physical Maximum (0) + Report Size (5) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Touch Valid) + Logical Maximum (1) + Physical Maximum (1) + Report Size (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Width) + Logical Maximum (-1) + Physical Maximum (-1) + Unit (0x0011) + Unit Exponent (0x000f) + Report Size (8) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Height) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage Page (Generic Desktop Controls) + Usage (X) + Logical Maximum (4260) + Physical Maximum (292) + Report Size (16) + Report Count (2) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Y) + Logical Maximum (2820) + Physical Maximum (-62) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + End Collection + Usage Page (Digitizer) + Usage (Finger) + Collection (Logical) + Usage (Tip Switch) + Logical Maximum (1) + Physical Maximum (1) + Unit (0x0000) + Unit Exponent (0x0000) + Report Size (1) + Report Count (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Input (Constant, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Contact Identifier) + Logical Maximum (63) + Physical Maximum (0) + Report Size (5) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Touch Valid) + Logical Maximum (1) + Physical Maximum (1) + Report Size (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Width) + Logical Maximum (-1) + Physical Maximum (-1) + Unit (0x0011) + Unit Exponent (0x000f) + Report Size (8) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Height) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage Page (Generic Desktop Controls) + Usage (X) + Logical Maximum (4260) + Physical Maximum (292) + Report Size (16) + Report Count (2) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Y) + Logical Maximum (2820) + Physical Maximum (-62) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + End Collection + Usage Page (Digitizer) + Usage (Scan Time) + Logical Maximum (2147483647) + Physical Maximum (0) + Unit (0x0000) + Unit Exponent (0x0000) + Report Size (32) + Report Count (1) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Usage (Contact Count) + Logical Maximum (127) + Report Size (8) + Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Report ID (0x0a) + Usage (Contact Count Maximum) + Logical Maximum (10) + Feature (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Logical Maximum (1) + Physical Maximum (1) + Report Size (1) + Report Count (2040) + Feature (Constant, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) + Report ID (0x44) + Usage Page (Vendor Page) + Usage (0x00c5) + Logical Maximum (-1) + Physical Maximum (0) + Report Size (8) + Report Count (256) + Feature (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null position, Bit Field) +End Collection From 342fd05ead20661be508577d2248b835d773fe6e Mon Sep 17 00:00:00 2001 From: Wei Jing Date: Wed, 24 Sep 2025 23:26:19 +0200 Subject: [PATCH 5/6] handle double C and T report of X, Y in windows digitizer --- hid_parser/__init__.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/hid_parser/__init__.py b/hid_parser/__init__.py index fe4b690..7e621e9 100644 --- a/hid_parser/__init__.py +++ b/hid_parser/__init__.py @@ -784,12 +784,34 @@ def _append_items( else: if len(usages) != report_count: if len(usages) > report_count: - error_str = f'Expecting {report_count} usages but got {len(usages)}' - warnings.warn(HIDComplianceWarning(error_str), stacklevel=2) - report_count = len(usages) + warnings.warn( + HIDComplianceWarning( + f'Report count ({report_count}) is less than number of usages ({len(usages)}), \ + truncating usages.' + ) + , stacklevel=2 + ) + usages = usages[:report_count] else: - for i in range(report_count - len(usages)): - usages.append(usages[0]) + x_usage = Usage( + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, + hid_parser.data.GenericDesktopControls.X + ) + y_usage = Usage( + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, + hid_parser.data.GenericDesktopControls.Y + ) + if report_count > len(usages) and usages and usages[0] in (x_usage, y_usage): + pad_usage = usages[0] + for _ in range(report_count - len(usages)): + usages.append(pad_usage) + else: + missing_usage_count = report_count - len(usages) + usages += [] * missing_usage_count + warning_message = f'Report count ({report_count}) is greater than number of \ + usages ({len(usages)}), share the unused usage count to next usage' + warnings.warn(HIDComplianceWarning(warning_message), stacklevel=2) + for usage in usages: item = VariableItem( From 8d5b6bbda9ae384b925df2028ec377ca2e45bd57 Mon Sep 17 00:00:00 2001 From: Wei Jing Date: Wed, 24 Sep 2025 23:42:01 +0200 Subject: [PATCH 6/6] code fix --- hid_parser/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hid_parser/__init__.py b/hid_parser/__init__.py index 7e621e9..f71101c 100644 --- a/hid_parser/__init__.py +++ b/hid_parser/__init__.py @@ -794,11 +794,11 @@ def _append_items( usages = usages[:report_count] else: x_usage = Usage( - hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, hid_parser.data.GenericDesktopControls.X ) y_usage = Usage( - hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, + hid_parser.data.UsagePages.GENERIC_DESKTOP_CONTROLS_PAGE, hid_parser.data.GenericDesktopControls.Y ) if report_count > len(usages) and usages and usages[0] in (x_usage, y_usage): @@ -811,7 +811,6 @@ def _append_items( warning_message = f'Report count ({report_count}) is greater than number of \ usages ({len(usages)}), share the unused usage count to next usage' warnings.warn(HIDComplianceWarning(warning_message), stacklevel=2) - for usage in usages: item = VariableItem(