#!/bin/env python3# SPDX-License-Identifier: GPL-2.0# -*- coding: utf-8 -*-## Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com># Copyright (c) 2017 Red Hat, Inc.# from . import basefrom hidtools.hut import HUTfrom hidtools.util import BusTypeimport enumimport libevdevimport loggingimport pytestimport sysimport time logger = logging.getLogger("hidtools.test.multitouch") KERNEL_MODULE = base.KernelModule("hid-multitouch", "hid_multitouch") def BIT(x): return 1 << x mt_quirks = { "NOT_SEEN_MEANS_UP": BIT(0), "SLOT_IS_CONTACTID": BIT(1), "CYPRESS": BIT(2), "SLOT_IS_CONTACTNUMBER": BIT(3), "ALWAYS_VALID": BIT(4), "VALID_IS_INRANGE": BIT(5), "VALID_IS_CONFIDENCE": BIT(6), "CONFIDENCE": BIT(7), "SLOT_IS_CONTACTID_MINUS_ONE": BIT(8), "NO_AREA": BIT(9), "IGNORE_DUPLICATES": BIT(10), "HOVERING": BIT(11), "CONTACT_CNT_ACCURATE": BIT(12), "FORCE_GET_FEATURE": BIT(13), "FIX_CONST_CONTACT_ID": BIT(14), "TOUCH_SIZE_SCALING": BIT(15), "STICKY_FINGERS": BIT(16), "ASUS_CUSTOM_UP": BIT(17), "WIN8_PTP_BUTTONS": BIT(18), "SEPARATE_APP_REPORT": BIT(19), "MT_QUIRK_FORCE_MULTI_INPUT": BIT(20),} class Data(object): pass class Touch(object): def __init__(self, id, x, y): self.contactid = id self.x = x self.y = y self.cx = x self.cy = y self.tipswitch = True self.confidence = True self.tippressure = 15 self.azimuth = 0 self.inrange = True self.width = 10 self.height = 10 class Pen(Touch): def __init__(self, x, y): super().__init__(0, x, y) self.barrel = False self.invert = False self.eraser = False self.x_tilt = False self.y_tilt = False self.twist = 0 class Digitizer(base.UHIDTestDevice): @classmethod def msCertificationBlob(cls, reportID): return f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID ({reportID}) Usage Page (0xff00) Usage (0xc5) Logical Minimum (0) Logical Maximum (255) Report Size (8) Report Count (256) Feature (Data,Var,Abs) End Collection """ def __init__( self, name, rdesc_str=None, rdesc=None, application="Touch Screen", physical="Finger", max_contacts=None, input_info=(BusType.USB, 1, 2), quirks=None, ): super().__init__(name, application, rdesc_str, rdesc, input_info) self.scantime = 0 self.quirks = quirks if max_contacts is None: self.max_contacts = sys.maxsize for features in self.parsed_rdesc.feature_reports.values(): for feature in features: if feature.usage_name in ["Contact Max"]: self.max_contacts = feature.logical_max for inputs in self.parsed_rdesc.input_reports.values(): for i in inputs: if ( i.usage_name in ["Contact Count"] and i.logical_max > 0 and self.max_contacts > i.logical_max ): self.max_contacts = i.logical_max if self.max_contacts == sys.maxsize: self.max_contacts = 1 else: self.max_contacts = max_contacts self.physical = physical self.cur_application = application for features in self.parsed_rdesc.feature_reports.values(): for feature in features: if feature.usage_name == "Inputmode": self.cur_application = "Mouse" self.fields = [] for r in self.parsed_rdesc.input_reports.values(): if r.application_name == self.application: physicals = [f.physical_name for f in r] if self.physical not in physicals and None not in physicals: continue self.fields = [f.usage_name for f in r] @property def touches_in_a_report(self): return self.fields.count("Contact Id") def event(self, slots, global_data=None, contact_count=None, incr_scantime=True): if incr_scantime: self.scantime += 1 rs = [] # make sure we have only the required number of available slots slots = slots[: self.max_contacts] if global_data is None: global_data = Data() if contact_count is None: global_data.contactcount = len(slots) else: global_data.contactcount = contact_count global_data.scantime = self.scantime while len(slots): r = self.create_report( application=self.cur_application, data=slots, global_data=global_data ) self.call_input_event(r) rs.append(r) global_data.contactcount = 0 return rs def get_report(self, req, rnum, rtype): if rtype != self.UHID_FEATURE_REPORT: return (1, []) rdesc = None for v in self.parsed_rdesc.feature_reports.values(): if v.report_ID == rnum: rdesc = v if rdesc is None: return (1, []) if "Contact Max" not in [f.usage_name for f in rdesc]: return (1, []) self.contactmax = self.max_contacts r = rdesc.create_report([self], None) return (0, r) def set_report(self, req, rnum, rtype, data): if rtype != self.UHID_FEATURE_REPORT: return 1 rdesc = None for v in self.parsed_rdesc.feature_reports.values(): if v.report_ID == rnum: rdesc = v if rdesc is None: return 1 if "Inputmode" not in [f.usage_name for f in rdesc]: return 0 Inputmode_seen = False for f in rdesc: if "Inputmode" == f.usage_name: values = f.get_values(data) assert len(values) == 1 value = values[0] if not Inputmode_seen: Inputmode_seen = True if value == 0: self.cur_application = "Mouse" elif value == 2: self.cur_application = "Touch Screen" elif value == 3: self.cur_application = "Touch Pad" else: if value != 0: # Elan bug where the device doesn't work properly # if we set twice an Input Mode in the same Feature self.cur_application = "Mouse" return 0 class HIDButtonType(enum.IntEnum): CLICKPAD = 0 PRESSUREPAD = 1 DISCRETE_BUTTONS = 2 class PTP(Digitizer): def __init__( self, name, buttontype=HIDButtonType.CLICKPAD, rdesc_str=None, rdesc=None, application="Touch Pad", physical="Pointer", max_contacts=None, input_info=None, ): self.buttontype = buttontype self.clickpad_state = False self.left_state = False self.right_state = False super().__init__( name, rdesc_str, rdesc, application, physical, max_contacts, input_info ) def event( self, slots=None, click=None, left=None, right=None, contact_count=None, incr_scantime=True, ): # update our internal state if click is not None: self.clickpad_state = click if left is not None: self.left_state = left if right is not None: self.right_state = right # now create the global data global_data = Data() global_data.b1 = 1 if self.clickpad_state else 0 global_data.b2 = 1 if self.left_state else 0 global_data.b3 = 1 if self.right_state else 0 if slots is None: slots = [Data()] return super().event(slots, global_data, contact_count, incr_scantime) class MinWin8TSParallel(Digitizer): def __init__(self, max_slots): self.max_slots = max_slots self.phys_max = 120, 90 rdesc_finger_str = f""" Usage Page (Digitizers) Usage (Finger) Collection (Logical) Report Size (1) Report Count (1) Logical Minimum (0) Logical Maximum (1) Usage (Tip Switch) Input (Data,Var,Abs) Report Size (7) Logical Maximum (127) Input (Cnst,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Id) Input (Data,Var,Abs) Report Size (16) Unit Exponent (-1) Unit (SILinear: cm) Logical Maximum (4095) Physical Minimum (0) Physical Maximum ({self.phys_max[0]}) Usage Page (Generic Desktop) Usage (X) Input (Data,Var,Abs) Physical Maximum ({self.phys_max[1]}) Usage (Y) Input (Data,Var,Abs) Usage Page (Digitizers) Usage (Azimuth) Logical Maximum (360) Unit (SILinear: deg) Report Size (16) Input (Data,Var,Abs) End Collection""" rdesc_str = f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID (1) {rdesc_finger_str * self.max_slots} Unit Exponent (-4) Unit (SILinear: s) Logical Maximum (65535) Physical Maximum (65535) Usage Page (Digitizers) Usage (Scan Time) Input (Data,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Count) Input (Data,Var,Abs) Report ID (2) Logical Maximum ({self.max_slots}) Usage (Contact Max) Feature (Data,Var,Abs) End Collection {Digitizer.msCertificationBlob(68)}""" super().__init__(f"uhid test parallel {self.max_slots}", rdesc_str) class MinWin8TSHybrid(Digitizer): def __init__(self): self.max_slots = 10 self.phys_max = 120, 90 rdesc_finger_str = f""" Usage Page (Digitizers) Usage (Finger) Collection (Logical) Report Size (1) Report Count (1) Logical Minimum (0) Logical Maximum (1) Usage (Tip Switch) Input (Data,Var,Abs) Report Size (7) Logical Maximum (127) Input (Cnst,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Id) Input (Data,Var,Abs) Report Size (16) Unit Exponent (-1) Unit (SILinear: cm) Logical Maximum (4095) Physical Minimum (0) Physical Maximum ({self.phys_max[0]}) Usage Page (Generic Desktop) Usage (X) Input (Data,Var,Abs) Physical Maximum ({self.phys_max[1]}) Usage (Y) Input (Data,Var,Abs) End Collection""" rdesc_str = f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID (1) {rdesc_finger_str * 2} Unit Exponent (-4) Unit (SILinear: s) Logical Maximum (65535) Physical Maximum (65535) Usage Page (Digitizers) Usage (Scan Time) Input (Data,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Count) Input (Data,Var,Abs) Report ID (2) Logical Maximum ({self.max_slots}) Usage (Contact Max) Feature (Data,Var,Abs) End Collection {Digitizer.msCertificationBlob(68)}""" super().__init__("uhid test hybrid", rdesc_str) class Win8TSConfidence(Digitizer): def __init__(self, max_slots): self.max_slots = max_slots self.phys_max = 120, 90 rdesc_finger_str = f""" Usage Page (Digitizers) Usage (Finger) Collection (Logical) Report Size (1) Report Count (1) Logical Minimum (0) Logical Maximum (1) Usage (Tip Switch) Input (Data,Var,Abs) Usage (Confidence) Input (Data,Var,Abs) Report Size (6) Logical Maximum (127) Input (Cnst,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Id) Input (Data,Var,Abs) Report Size (16) Unit Exponent (-1) Unit (SILinear: cm) Logical Maximum (4095) Physical Minimum (0) Physical Maximum ({self.phys_max[0]}) Usage Page (Generic Desktop) Usage (X) Input (Data,Var,Abs) Physical Maximum ({self.phys_max[1]}) Usage (Y) Input (Data,Var,Abs) Usage Page (Digitizers) Usage (Azimuth) Logical Maximum (360) Unit (SILinear: deg) Report Size (16) Input (Data,Var,Abs) End Collection""" rdesc_str = f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID (1) {rdesc_finger_str * self.max_slots} Unit Exponent (-4) Unit (SILinear: s) Logical Maximum (65535) Physical Maximum (65535) Usage Page (Digitizers) Usage (Scan Time) Input (Data,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Count) Input (Data,Var,Abs) Report ID (2) Logical Maximum ({self.max_slots}) Usage (Contact Max) Feature (Data,Var,Abs) End Collection {Digitizer.msCertificationBlob(68)}""" super().__init__(f"uhid test confidence {self.max_slots}", rdesc_str) class SmartTechDigitizer(Digitizer): def __init__(self, name, input_info): super().__init__( name, rdesc="05 01 09 02 a1 01 85 01 09 01 a1 00 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 05 81 03 05 01 15 00 26 ff 0f 55 0e 65 11 75 10 95 01 35 00 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 06 15 00 26 ff 00 a1 01 85 02 75 08 95 3f 09 00 82 02 01 95 3f 09 00 92 02 01 c0 05 0d 09 04 a1 01 85 05 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 75 08 95 01 15 00 25 0a 09 54 81 02 09 55 b1 02 c0 05 0d 09 0e a1 01 85 04 09 23 a1 02 15 00 25 02 75 08 95 02 09 52 09 53 b1 02 c0 c0 05 0d 09 04 a1 01 85 03 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 75 08 95 01 15 00 25 0a 09 54 81 02 09 55 b1 02 c0 05 0d 09 04 a1 01 85 06 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 06 81 03 95 01 75 10 65 11 55 0e 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 07 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 08 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 09 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 0a 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0", input_info=input_info, ) def create_report(self, data, global_data=None, reportID=None, application=None):Lines 1–500 of 2292. Load more
#!/bin/env python3 # SPDX-License-Identifier: GPL-2.0 # -*- coding: utf-8 -*- # # Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com> # Copyright (c) 2017 Red Hat, Inc. # from . import base from hidtools.hut import HUT from hidtools.util import BusType import enum import libevdev import logging import pytest import sys import time logger = logging.getLogger("hidtools.test.multitouch") KERNEL_MODULE = base.KernelModule("hid-multitouch", "hid_multitouch") def BIT(x): return 1 << x mt_quirks = { "NOT_SEEN_MEANS_UP": BIT(0), "SLOT_IS_CONTACTID": BIT(1), "CYPRESS": BIT(2), "SLOT_IS_CONTACTNUMBER": BIT(3), "ALWAYS_VALID": BIT(4), "VALID_IS_INRANGE": BIT(5), "VALID_IS_CONFIDENCE": BIT(6), "CONFIDENCE": BIT(7), "SLOT_IS_CONTACTID_MINUS_ONE": BIT(8), "NO_AREA": BIT(9), "IGNORE_DUPLICATES": BIT(10), "HOVERING": BIT(11), "CONTACT_CNT_ACCURATE": BIT(12), "FORCE_GET_FEATURE": BIT(13), "FIX_CONST_CONTACT_ID": BIT(14), "TOUCH_SIZE_SCALING": BIT(15), "STICKY_FINGERS": BIT(16), "ASUS_CUSTOM_UP": BIT(17), "WIN8_PTP_BUTTONS": BIT(18), "SEPARATE_APP_REPORT": BIT(19), "MT_QUIRK_FORCE_MULTI_INPUT": BIT(20), } class Data(object): pass class Touch(object): def __init__(self, id, x, y): self.contactid = id self.x = x self.y = y self.cx = x self.cy = y self.tipswitch = True self.confidence = True self.tippressure = 15 self.azimuth = 0 self.inrange = True self.width = 10 self.height = 10 class Pen(Touch): def __init__(self, x, y): super().__init__(0, x, y) self.barrel = False self.invert = False self.eraser = False self.x_tilt = False self.y_tilt = False self.twist = 0 class Digitizer(base.UHIDTestDevice): @classmethod def msCertificationBlob(cls, reportID): return f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID ({reportID}) Usage Page (0xff00) Usage (0xc5) Logical Minimum (0) Logical Maximum (255) Report Size (8) Report Count (256) Feature (Data,Var,Abs) End Collection """ def __init__( self, name, rdesc_str=None, rdesc=None, application="Touch Screen", physical="Finger", max_contacts=None, input_info=(BusType.USB, 1, 2), quirks=None, ): super().__init__(name, application, rdesc_str, rdesc, input_info) self.scantime = 0 self.quirks = quirks if max_contacts is None: self.max_contacts = sys.maxsize for features in self.parsed_rdesc.feature_reports.values(): for feature in features: if feature.usage_name in ["Contact Max"]: self.max_contacts = feature.logical_max for inputs in self.parsed_rdesc.input_reports.values(): for i in inputs: if ( i.usage_name in ["Contact Count"] and i.logical_max > 0 and self.max_contacts > i.logical_max ): self.max_contacts = i.logical_max if self.max_contacts == sys.maxsize: self.max_contacts = 1 else: self.max_contacts = max_contacts self.physical = physical self.cur_application = application for features in self.parsed_rdesc.feature_reports.values(): for feature in features: if feature.usage_name == "Inputmode": self.cur_application = "Mouse" self.fields = [] for r in self.parsed_rdesc.input_reports.values(): if r.application_name == self.application: physicals = [f.physical_name for f in r] if self.physical not in physicals and None not in physicals: continue self.fields = [f.usage_name for f in r] @property def touches_in_a_report(self): return self.fields.count("Contact Id") def event(self, slots, global_data=None, contact_count=None, incr_scantime=True): if incr_scantime: self.scantime += 1 rs = [] # make sure we have only the required number of available slots slots = slots[: self.max_contacts] if global_data is None: global_data = Data() if contact_count is None: global_data.contactcount = len(slots) else: global_data.contactcount = contact_count global_data.scantime = self.scantime while len(slots): r = self.create_report( application=self.cur_application, data=slots, global_data=global_data ) self.call_input_event(r) rs.append(r) global_data.contactcount = 0 return rs def get_report(self, req, rnum, rtype): if rtype != self.UHID_FEATURE_REPORT: return (1, []) rdesc = None for v in self.parsed_rdesc.feature_reports.values(): if v.report_ID == rnum: rdesc = v if rdesc is None: return (1, []) if "Contact Max" not in [f.usage_name for f in rdesc]: return (1, []) self.contactmax = self.max_contacts r = rdesc.create_report([self], None) return (0, r) def set_report(self, req, rnum, rtype, data): if rtype != self.UHID_FEATURE_REPORT: return 1 rdesc = None for v in self.parsed_rdesc.feature_reports.values(): if v.report_ID == rnum: rdesc = v if rdesc is None: return 1 if "Inputmode" not in [f.usage_name for f in rdesc]: return 0 Inputmode_seen = False for f in rdesc: if "Inputmode" == f.usage_name: values = f.get_values(data) assert len(values) == 1 value = values[0] if not Inputmode_seen: Inputmode_seen = True if value == 0: self.cur_application = "Mouse" elif value == 2: self.cur_application = "Touch Screen" elif value == 3: self.cur_application = "Touch Pad" else: if value != 0: # Elan bug where the device doesn't work properly # if we set twice an Input Mode in the same Feature self.cur_application = "Mouse" return 0 class HIDButtonType(enum.IntEnum): CLICKPAD = 0 PRESSUREPAD = 1 DISCRETE_BUTTONS = 2 class PTP(Digitizer): def __init__( self, name, buttontype=HIDButtonType.CLICKPAD, rdesc_str=None, rdesc=None, application="Touch Pad", physical="Pointer", max_contacts=None, input_info=None, ): self.buttontype = buttontype self.clickpad_state = False self.left_state = False self.right_state = False super().__init__( name, rdesc_str, rdesc, application, physical, max_contacts, input_info ) def event( self, slots=None, click=None, left=None, right=None, contact_count=None, incr_scantime=True, ): # update our internal state if click is not None: self.clickpad_state = click if left is not None: self.left_state = left if right is not None: self.right_state = right # now create the global data global_data = Data() global_data.b1 = 1 if self.clickpad_state else 0 global_data.b2 = 1 if self.left_state else 0 global_data.b3 = 1 if self.right_state else 0 if slots is None: slots = [Data()] return super().event(slots, global_data, contact_count, incr_scantime) class MinWin8TSParallel(Digitizer): def __init__(self, max_slots): self.max_slots = max_slots self.phys_max = 120, 90 rdesc_finger_str = f""" Usage Page (Digitizers) Usage (Finger) Collection (Logical) Report Size (1) Report Count (1) Logical Minimum (0) Logical Maximum (1) Usage (Tip Switch) Input (Data,Var,Abs) Report Size (7) Logical Maximum (127) Input (Cnst,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Id) Input (Data,Var,Abs) Report Size (16) Unit Exponent (-1) Unit (SILinear: cm) Logical Maximum (4095) Physical Minimum (0) Physical Maximum ({self.phys_max[0]}) Usage Page (Generic Desktop) Usage (X) Input (Data,Var,Abs) Physical Maximum ({self.phys_max[1]}) Usage (Y) Input (Data,Var,Abs) Usage Page (Digitizers) Usage (Azimuth) Logical Maximum (360) Unit (SILinear: deg) Report Size (16) Input (Data,Var,Abs) End Collection """ rdesc_str = f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID (1) {rdesc_finger_str * self.max_slots} Unit Exponent (-4) Unit (SILinear: s) Logical Maximum (65535) Physical Maximum (65535) Usage Page (Digitizers) Usage (Scan Time) Input (Data,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Count) Input (Data,Var,Abs) Report ID (2) Logical Maximum ({self.max_slots}) Usage (Contact Max) Feature (Data,Var,Abs) End Collection {Digitizer.msCertificationBlob(68)} """ super().__init__(f"uhid test parallel {self.max_slots}", rdesc_str) class MinWin8TSHybrid(Digitizer): def __init__(self): self.max_slots = 10 self.phys_max = 120, 90 rdesc_finger_str = f""" Usage Page (Digitizers) Usage (Finger) Collection (Logical) Report Size (1) Report Count (1) Logical Minimum (0) Logical Maximum (1) Usage (Tip Switch) Input (Data,Var,Abs) Report Size (7) Logical Maximum (127) Input (Cnst,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Id) Input (Data,Var,Abs) Report Size (16) Unit Exponent (-1) Unit (SILinear: cm) Logical Maximum (4095) Physical Minimum (0) Physical Maximum ({self.phys_max[0]}) Usage Page (Generic Desktop) Usage (X) Input (Data,Var,Abs) Physical Maximum ({self.phys_max[1]}) Usage (Y) Input (Data,Var,Abs) End Collection """ rdesc_str = f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID (1) {rdesc_finger_str * 2} Unit Exponent (-4) Unit (SILinear: s) Logical Maximum (65535) Physical Maximum (65535) Usage Page (Digitizers) Usage (Scan Time) Input (Data,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Count) Input (Data,Var,Abs) Report ID (2) Logical Maximum ({self.max_slots}) Usage (Contact Max) Feature (Data,Var,Abs) End Collection {Digitizer.msCertificationBlob(68)} """ super().__init__("uhid test hybrid", rdesc_str) class Win8TSConfidence(Digitizer): def __init__(self, max_slots): self.max_slots = max_slots self.phys_max = 120, 90 rdesc_finger_str = f""" Usage Page (Digitizers) Usage (Finger) Collection (Logical) Report Size (1) Report Count (1) Logical Minimum (0) Logical Maximum (1) Usage (Tip Switch) Input (Data,Var,Abs) Usage (Confidence) Input (Data,Var,Abs) Report Size (6) Logical Maximum (127) Input (Cnst,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Id) Input (Data,Var,Abs) Report Size (16) Unit Exponent (-1) Unit (SILinear: cm) Logical Maximum (4095) Physical Minimum (0) Physical Maximum ({self.phys_max[0]}) Usage Page (Generic Desktop) Usage (X) Input (Data,Var,Abs) Physical Maximum ({self.phys_max[1]}) Usage (Y) Input (Data,Var,Abs) Usage Page (Digitizers) Usage (Azimuth) Logical Maximum (360) Unit (SILinear: deg) Report Size (16) Input (Data,Var,Abs) End Collection """ rdesc_str = f""" Usage Page (Digitizers) Usage (Touch Screen) Collection (Application) Report ID (1) {rdesc_finger_str * self.max_slots} Unit Exponent (-4) Unit (SILinear: s) Logical Maximum (65535) Physical Maximum (65535) Usage Page (Digitizers) Usage (Scan Time) Input (Data,Var,Abs) Report Size (8) Logical Maximum (255) Usage (Contact Count) Input (Data,Var,Abs) Report ID (2) Logical Maximum ({self.max_slots}) Usage (Contact Max) Feature (Data,Var,Abs) End Collection {Digitizer.msCertificationBlob(68)} """ super().__init__(f"uhid test confidence {self.max_slots}", rdesc_str) class SmartTechDigitizer(Digitizer): def __init__(self, name, input_info): super().__init__( name, rdesc="05 01 09 02 a1 01 85 01 09 01 a1 00 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 05 81 03 05 01 15 00 26 ff 0f 55 0e 65 11 75 10 95 01 35 00 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 06 15 00 26 ff 00 a1 01 85 02 75 08 95 3f 09 00 82 02 01 95 3f 09 00 92 02 01 c0 05 0d 09 04 a1 01 85 05 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 09 20 a1 00 25 01 75 01 95 02 09 42 09 45 81 02 75 06 95 01 09 30 81 02 26 ff 00 75 08 09 51 81 02 75 10 09 38 81 02 95 02 26 ff 0f 09 48 09 49 81 02 05 01 09 30 09 31 81 02 c0 05 0d 75 08 95 01 15 00 25 0a 09 54 81 02 09 55 b1 02 c0 05 0d 09 0e a1 01 85 04 09 23 a1 02 15 00 25 02 75 08 95 02 09 52 09 53 b1 02 c0 c0 05 0d 09 04 a1 01 85 03 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 02 81 03 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 95 01 09 51 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 05 0d 75 08 95 01 15 00 25 0a 09 54 81 02 09 55 b1 02 c0 05 0d 09 04 a1 01 85 06 09 22 a1 02 15 00 25 01 75 01 95 02 09 42 09 47 81 02 95 06 81 03 95 01 75 10 65 11 55 0e 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 07 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 08 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 09 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0 05 0d 09 02 a1 01 85 0a 09 20 a1 02 25 01 75 01 95 04 09 42 09 44 09 3c 09 45 81 02 75 04 95 01 25 0f 09 30 81 02 26 ff 00 75 08 09 38 81 02 75 10 27 a0 8c 00 00 55 0e 65 14 47 a0 8c 00 00 09 3f 81 02 65 11 26 ff 0f 46 c8 37 09 48 81 02 46 68 1f 09 49 81 02 05 01 46 c8 37 09 30 81 02 46 68 1f 09 31 81 02 45 00 c0 c0", input_info=input_info, ) def create_report(self, data, global_data=None, reportID=None, application=None):