Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/testing/selftests/hid/tests/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 222 kB image not shown  

Quelle  test_multitouch.py   Sprache: Python

 
#!/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 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 PTP(Digitizer):
    def __init__(
        self,
        name,
        type="Click Pad",
        rdesc_str=None,
        rdesc=None,
        application="Touch Pad",
        physical="Pointer",
        max_contacts=None,
        input_info=None,
    ):
        self.type = type.lower().replace(" """)
        if self.type == "clickpad":
            self.buttontype = 0
        else:  # pressurepad
            self.buttontype = 1
        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):
        # this device has *a lot* of different reports, and most of them
        # have the Touch Screen application. But the first one is a stylus
        # report (as stated in the physical type), so we simply override
        # the report ID to use what the device sends
        return super().create_report(data, global_data=global_data, reportID=3)

    def match_evdev_rule(self, application, evdev):
        # we need to select the correct evdev node, as the device has multiple
        # Touch Screen application collections
        if application != "Touch Screen":
            return True
        absinfo = evdev.absinfo[libevdev.EV_ABS.ABS_MT_POSITION_X]
        return absinfo is not None and absinfo.resolution == 3


class BaseTest:
    class TestMultitouch(base.BaseTestCase.TestUhid):
        kernel_modules = [KERNEL_MODULE]

        def create_device(self):
            raise Exception("please reimplement me in subclasses")

        def get_slot(self, uhdev, t, default):
            if uhdev.quirks is None:
                return default

            if "SLOT_IS_CONTACTID" in uhdev.quirks:
                return t.contactid

            if "SLOT_IS_CONTACTID_MINUS_ONE" in uhdev.quirks:
                return t.contactid - 1

            return default

        def test_creation(self):
            """Make sure the device gets processed by the kernel and creates
            the expected application input node.

            If this fail, there is something wrong in the device report
            descriptors."""
            super().test_creation()

            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            # some sanity checking for the quirks
            if uhdev.quirks is not None:
                for q in uhdev.quirks:
                    assert q in mt_quirks

            assert evdev.num_slots == uhdev.max_contacts

            if uhdev.max_contacts > 1:
                assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
                assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
            if uhdev.max_contacts > 2:
                assert evdev.slots[2][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        def test_required_usages(self):
            """Make sure the device exports the correct required features and
            inputs."""
            uhdev = self.uhdev
            rdesc = uhdev.parsed_rdesc
            for feature in rdesc.feature_reports.values():
                for field in feature:
                    page_id = field.usage >> 16
                    value = field.usage & 0xFF
                    try:
                        if HUT[page_id][value] == "Contact Max":
                            assert HUT[page_id][field.application] in [
                                "Touch Screen",
                                "Touch Pad",
                                "System Multi-Axis Controller",
                            ]
                    except KeyError:
                        pass

                    try:
                        if HUT[page_id][value] == "Inputmode":
                            assert HUT[page_id][field.application] in [
                                "Touch Screen",
                                "Touch Pad",
                                "Device Configuration",
                            ]
                    except KeyError:
                        pass

        def test_mt_single_touch(self):
            """send a single touch in the first slot of the device,
            and release it."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 50, 100)
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            slot = self.get_slot(uhdev, t0, 0)

            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
            assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
            assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100

            t0.tipswitch = False
            if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks:
                t0.inrange = False
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
            assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        def test_mt_dual_touch(self):
            """Send 2 touches in the first 2 slots.
            Make sure the kernel sees this as a dual touch.
            Release and check

            Note: PTP will send here BTN_DOUBLETAP emulation"""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 50, 100)
            t1 = Touch(2, 150, 200)

            if uhdev.quirks is not None and (
                "SLOT_IS_CONTACTID" in uhdev.quirks
                or "SLOT_IS_CONTACTNUMBER" in uhdev.quirks
            ):
                t1.contactid = 0

            slot0 = self.get_slot(uhdev, t0, 0)
            slot1 = self.get_slot(uhdev, t1, 1)

            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
            assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

            r = uhdev.event([t0, t1])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH) not in events
            assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
            assert (
                libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_X, 5) not in events
            )
            assert (
                libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_Y, 10) not in events
            )
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_POSITION_X] == 150
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 200

            t0.tipswitch = False
            if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks:
                t0.inrange = False
            r = uhdev.event([t0, t1])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_X) not in events
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_Y) not in events

            t1.tipswitch = False
            if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks:
                t1.inrange = False

            if uhdev.quirks is not None and "SLOT_IS_CONTACTNUMBER" in uhdev.quirks:
                r = uhdev.event([t0, t1])
            else:
                r = uhdev.event([t1])

            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: uhdev.max_contacts <= 2, "Device not compatible"
        )
        def test_mt_triple_tap(self):
            """Send 3 touches in the first 3 slots.
            Make sure the kernel sees this as a triple touch.
            Release and check

            Note: PTP will send here BTN_TRIPLETAP emulation"""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 50, 100)
            t1 = Touch(2, 150, 200)
            t2 = Touch(3, 250, 300)
            r = uhdev.event([t0, t1, t2])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            slot0 = self.get_slot(uhdev, t0, 0)
            slot1 = self.get_slot(uhdev, t1, 1)
            slot2 = self.get_slot(uhdev, t2, 2)

            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_POSITION_X] == 150
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 200
            assert evdev.slots[slot2][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 2
            assert evdev.slots[slot2][libevdev.EV_ABS.ABS_MT_POSITION_X] == 250
            assert evdev.slots[slot2][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 300

            t0.tipswitch = False
            t1.tipswitch = False
            t2.tipswitch = False
            if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks:
                t0.inrange = False
                t1.inrange = False
                t2.inrange = False
            r = uhdev.event([t0, t1, t2])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
            assert evdev.slots[slot2][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: uhdev.max_contacts <= 2, "Device not compatible"
        )
        def test_mt_max_contact(self):
            """send the maximum number of contact as reported by the device.
            Make sure all contacts are forwarded and that there is no miss.
            Release and check."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            touches = [
                Touch(i, (i + 3) * 20, (i + 3) * 20 + 5)
                for i in range(uhdev.max_contacts)
            ]
            if (
                uhdev.quirks is not None
                and "SLOT_IS_CONTACTID_MINUS_ONE" in uhdev.quirks
            ):
                for t in touches:
                    t.contactid += 1
            r = uhdev.event(touches)
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            for i, t in enumerate(touches):
                slot = self.get_slot(uhdev, t, i)

                assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == i
                assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_X] == t.x
                assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_Y] == t.y

            for t in touches:
                t.tipswitch = False
                if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks:
                    t.inrange = False

            r = uhdev.event(touches)
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            for i, t in enumerate(touches):
                slot = self.get_slot(uhdev, t, i)

                assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: (
                uhdev.touches_in_a_report == 1
                or uhdev.quirks is not None
                and "CONTACT_CNT_ACCURATE" not in uhdev.quirks
            ),
            "Device not compatible, we can not trigger the conditions",
        )
        def test_mt_contact_count_accurate(self):
            """Test the MT_QUIRK_CONTACT_CNT_ACCURATE from the kernel.
            A report should forward an accurate contact count and the kernel
            should ignore any data provided after we have reached this
            contact count."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 50, 100)
            t1 = Touch(2, 150, 200)

            slot0 = self.get_slot(uhdev, t0, 0)
            slot1 = self.get_slot(uhdev, t1, 1)

            r = uhdev.event([t0, t1], contact_count=1)
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
            assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_TRACKING_ID, 0) in events
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
            assert evdev.slots[slot0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
            assert evdev.slots[slot1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

    class TestWin8Multitouch(TestMultitouch):
        def test_required_usages8(self):
            """Make sure the device exports the correct required features and
            inputs."""
            uhdev = self.uhdev
            rdesc = uhdev.parsed_rdesc
            for feature in rdesc.feature_reports.values():
                for field in feature:
                    page_id = field.usage >> 16
                    value = field.usage & 0xFF
                    try:
                        if HUT[page_id][value] == "Inputmode":
                            assert HUT[field.application] not in ["Touch Screen"]
                    except KeyError:
                        pass

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: uhdev.fields.count("X") == uhdev.touches_in_a_report,
            "Device not compatible, we can not trigger the conditions",
        )
        def test_mt_tx_cx(self):
            """send a single touch in the first slot of the device, with
            different values of Tx and Cx. Make sure the kernel reports Tx."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 5, 10)
            t0.cx = 50
            t0.cy = 100
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 5
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TOOL_X] == 50
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 10
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TOOL_Y] == 100

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: "In Range" not in uhdev.fields,
            "Device not compatible, missing In Range usage",
        )
        def test_mt_inrange(self):
            """Send one contact that has the InRange bit set before/after
            tipswitch.
            Kernel is supposed to mark the contact with a distance > 0
            when inrange is set but not tipswitch.

            This tests the hovering capability of devices (MT_QUIRK_HOVERING).

            Make sure the contact is only released from the kernel POV
            when the inrange bit is set to 0."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 150, 200)
            t0.tipswitch = False
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
            assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_TRACKING_ID, 0) in events
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_DISTANCE) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_DISTANCE] > 0
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 150
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 200
            assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

            t0.tipswitch = True
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_DISTANCE, 0) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_DISTANCE] == 0

            t0.tipswitch = False
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_DISTANCE) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_DISTANCE] > 0

            t0.inrange = False
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        def test_mt_duplicates(self):
            """Test the MT_QUIRK_IGNORE_DUPLICATES from the kernel.
            If a touch is reported more than once with the same Contact ID,
            we should only handle the first touch.

            Note: this is not in MS spec, but the current kernel behaves
            like that"""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 5, 10)
            t1 = Touch(1, 15, 20)
            t2 = Touch(2, 50, 100)

            r = uhdev.event([t0, t1, t2], contact_count=2)
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
            assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_TRACKING_ID, 0) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 5
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 10
            assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1
            assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
            assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100

        def test_mt_release_miss(self):
            """send a single touch in the first slot of the device, and
            forget to release it. The kernel is supposed to release by itself
            the touch in 100ms.
            Make sure that we are dealing with a new touch by resending the
            same touch after the timeout expired, and check that the kernel
            considers it as a separate touch (different tracking ID)"""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 5, 10)
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0

            time.sleep(0.2)
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: "Azimuth" not in uhdev.fields,
            "Device not compatible, missing Azimuth usage",
        )
        def test_mt_azimuth(self):
            """Check for the azimtuh information bit.
            When azimuth is presented by the device, it should be exported
            as ABS_MT_ORIENTATION and the exported value should report a quarter
            of circle."""
            uhdev = self.uhdev

            t0 = Touch(1, 5, 10)
            t0.azimuth = 270

            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            # orientation is clockwise, while Azimuth is counter clockwise
            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_ORIENTATION, 90) in events

    class TestPTP(TestWin8Multitouch):
        def test_ptp_buttons(self):
            """check for button reliability.
            There are 2 types of touchpads: the click pads and the pressure pads.
            Each should reliably report the BTN_LEFT events.
            """
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            if uhdev.type == "clickpad":
                r = uhdev.event(click=True)
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                assert libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1) in events
                assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1

                r = uhdev.event(click=False)
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                assert libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0) in events
                assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
            else:
                r = uhdev.event(left=True)
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                assert libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1) in events
                assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1

                r = uhdev.event(left=False)
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                assert libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0) in events
                assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0

                r = uhdev.event(right=True)
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                assert libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1) in events
                assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1

                r = uhdev.event(right=False)
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                assert libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0) in events
                assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: "Confidence" not in uhdev.fields,
            "Device not compatible, missing Confidence usage",
        )
        def test_ptp_confidence(self):
            """Check for the validity of the confidence bit.
            When a contact is marked as not confident, it should be detected
            as a palm from the kernel POV and released.

            Note: if the kernel exports ABS_MT_TOOL_TYPE, it shouldn't release
            the touch but instead convert it to ABS_MT_TOOL_PALM."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            t0 = Touch(1, 150, 200)
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            t0.confidence = False
            r = uhdev.event([t0])
            events = uhdev.next_sync_events()
            self.debug_reports(r, uhdev, events)

            if evdev.absinfo[libevdev.EV_ABS.ABS_MT_TOOL_TYPE] is not None:
                # the kernel exports MT_TOOL_PALM
                assert (
                    libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_TOOL_TYPE, 2) in events
                )
                assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] != -1

                t0.tipswitch = False
                r = uhdev.event([t0])
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)

            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
            assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1

        @pytest.mark.skip_if_uhdev(
            lambda uhdev: uhdev.touches_in_a_report >= uhdev.max_contacts,
            "Device not compatible, we can not trigger the conditions",
        )
        def test_ptp_non_touch_data(self):
            """Some single finger hybrid touchpads might not provide the
            button information in subsequent reports (only in the first report).

            Emulate this and make sure we do not release the buttons in the
            middle of the event."""
            uhdev = self.uhdev
            evdev = uhdev.get_evdev()

            touches = [Touch(i, i * 10, i * 10 + 5) for i in range(uhdev.max_contacts)]
            contact_count = uhdev.max_contacts
            incr_scantime = True
            btn_state = True
            events = None
            while touches:
                t = touches[: uhdev.touches_in_a_report]
                touches = touches[uhdev.touches_in_a_report :]
                r = uhdev.event(
                    t,
                    click=btn_state,
                    left=btn_state,
                    contact_count=contact_count,
                    incr_scantime=incr_scantime,
                )
                contact_count = 0
                incr_scantime = False
                btn_state = False
                events = uhdev.next_sync_events()
                self.debug_reports(r, uhdev, events)
                if touches:
                    assert len(events) == 0

            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1) in events
            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0) not in events
            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1


################################################################################
#
# Windows 7 compatible devices
#
################################################################################
class Test3m_0596_0500(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test 3m_0596_0500",
            rdesc="05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 09 01 95 01 75 01 15 00 25 01 81 02 95 07 75 01 81 03 95 01 75 08 81 03 05 01 09 30 09 31 15 00 26 ff 7f 35 00 46 00 00 95 02 75 10 81 02 c0 a1 02 15 00 26 ff 00 09 01 95 39 75 08 81 01 c0 c0 05 0d 09 0e a1 01 85 11 09 23 a1 02 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0 09 04 a1 01 85 10 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 3a 06 81 02 09 31 46 e8 03 81 02 c0 05 0d 09 54 95 01 75 08 15 00 25 0a 81 02 85 12 09 55 95 01 75 08 15 00 25 0a b1 02 06 00 ff 15 00 26 ff 00 85 03 09 01 75 08 95 07 b1 02 85 04 09 01 75 08 95 17 b1 02 85 05 09 01 75 08 95 47 b1 02 85 06 09 01 75 08 95 07 b1 02 85 07 09 01 75 08 95 07 b1 02 85 08 09 01 75 08 95 07 b1 02 85 09 09 01 75 08 95 3f b1 02 c0",
            input_info=(BusType.USB, 0x0596, 0x0500),
            max_contacts=60,
            quirks=("VALID_IS_CONFIDENCE""SLOT_IS_CONTACTID""TOUCH_SIZE_SCALING"),
        )


class Test3m_0596_0506(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test 3m_0596_0506",
            rdesc="05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 09 01 95 01 75 01 15 00 25 01 81 02 95 07 75 01 81 03 95 01 75 08 81 03 05 01 09 30 09 31 15 00 26 ff 7f 35 00 46 00 00 95 02 75 10 81 02 c0 a1 02 15 00 26 ff 00 09 01 95 39 75 08 81 03 c0 c0 05 0d 09 0e a1 01 85 11 09 23 a1 02 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0 09 04 a1 01 85 13 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 d6 0a 81 02 09 31 46 22 06 81 02 05 0d 75 10 95 01 09 48 81 02 09 49 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 d6 0a 81 02 09 31 46 22 06 81 02 05 0d 75 10 95 01 09 48 81 02 09 49 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 d6 0a 81 02 09 31 46 22 06 81 02 05 0d 75 10 95 01 09 48 81 02 09 49 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 d6 0a 81 02 09 31 46 22 06 81 02 05 0d 75 10 95 01 09 48 81 02 09 49 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 d6 0a 81 02 09 31 46 22 06 81 02 05 0d 75 10 95 01 09 48 81 02 09 49 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 0e 65 33 09 30 35 00 46 d6 0a 81 02 09 31 46 22 06 81 02 05 0d 75 10 95 01 09 48 81 02 09 49 81 02 c0 05 0d 09 54 95 01 75 08 15 00 25 3c 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 02 81 03 05 0d 85 12 09 55 95 01 75 08 15 00 25 3c b1 02 06 00 ff 15 00 26 ff 00 85 03 09 01 75 08 95 07 b1 02 85 04 09 01 75 08 95 17 b1 02 85 05 09 01 75 08 95 47 b1 02 85 06 09 01 75 08 95 07 b1 02 85 73 09 01 75 08 95 07 b1 02 85 08 09 01 75 08 95 07 b1 02 85 09 09 01 75 08 95 3f b1 02 85 0f 09 01 75 08 96 07 02 b1 02 c0",
            input_info=(BusType.USB, 0x0596, 0x0506),
            max_contacts=60,
            quirks=("VALID_IS_CONFIDENCE""SLOT_IS_CONTACTID""TOUCH_SIZE_SCALING"),
        )


class TestActionStar_2101_1011(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test ActionStar_2101_1011",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 09 51 75 08 95 01 81 02 05 01 35 00 55 0e 65 33 75 10 95 01 09 30 26 ff 4d 46 70 03 81 02 09 31 26 ff 2b 46 f1 01 81 02 46 00 00 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 09 51 75 08 95 01 81 02 05 01 35 00 55 0e 65 33 75 10 95 01 09 30 26 ff 4d 46 70 03 81 02 09 31 26 ff 2b 46 f1 01 81 02 46 00 00 c0 05 0d 09 54 75 08 95 01 81 02 05 0d 85 02 09 55 25 02 75 08 95 01 b1 02 c0",
            input_info=(BusType.USB, 0x2101, 0x1011),
        )

    def test_mt_actionstar_inrange(self):
        """Special sequence that might not be handled properly"""
        uhdev = self.uhdev
        evdev = uhdev.get_evdev()

        # fmt: off
        sequence = [
            # t0 = Touch(1, 6999, 2441) | t1 = Touch(2, 15227, 2026)
            '01 ff 01 57 1b 89 09 ff 02 7b 3b ea 07 02',
            # t0.xy = (6996, 2450)      | t1.y = 2028
            '01 ff 01 54 1b 92 09 ff 02 7b 3b ec 07 02',
            # t1.xy = (15233, 2040)     | t0.tipswitch = False
            '01 ff 02 81 3b f8 07 fe 01 54 1b 92 09 02',
            # t1                        | t0.inrange = False
            '01 ff 02 81 3b f8 07 fc 01 54 1b 92 09 02',
        ]
        # fmt: on

        for num, r_str in enumerate(sequence):
            r = [int(i, 16) for i in r_str.split()]
            uhdev.call_input_event(r)
            events = uhdev.next_sync_events()
            self.debug_reports([r], uhdev)
            for e in events:
                print(e)
            if num == 2:
                assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1


class TestAsus_computers_0486_0185(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test asus-computers_0486_0185",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 95 01 75 01 81 02 09 32 81 02 09 47 81 02 75 05 81 03 09 30 26 ff 00 75 08 81 02 09 51 25 02 81 02 26 96 0d 05 01 75 10 55 0d 65 33 09 30 35 00 46 fd 1d 81 02 09 31 46 60 11 81 02 c0 09 22 a1 02 05 0d 35 00 45 00 55 00 65 00 09 42 25 01 75 01 81 02 09 32 81 02 09 47 81 02 75 05 81 03 09 30 26 ff 00 75 08 81 02 09 51 25 02 81 02 26 96 0d 05 01 75 10 55 0d 65 33 09 30 46 fd 1d 81 02 09 31 46 60 11 81 02 c0 35 00 45 00 55 00 65 00 05 0d 09 54 75 08 25 02 81 02 85 08 09 55 b1 02 c0 09 0e a1 01 85 07 09 22 a1 00 09 52 25 0a b1 02 c0 05 0c 09 01 a1 01 85 06 09 01 26 ff 00 95 08 b1 02 c0 c0 05 01 09 02 a1 01 85 03 09 01 a1 00 05 09 19 01 29 02 25 01 75 01 95 02 81 02 95 06 81 03 26 96 0d 05 01 75 10 95 01 55 0d 65 33 09 30 46 fd 1d 81 02 09 31 46 60 11 81 02 c0 c0 06 ff 01 09 01 a1 01 26 ff 00 35 00 45 00 55 00 65 00 85 05 75 08 95 3f 09 00 81 02 c0",
            input_info=(BusType.USB, 0x0486, 0x0185),
            quirks=("VALID_IS_CONFIDENCE""SLOT_IS_CONTACTID_MINUS_ONE"),
        )


class TestAtmel_03eb_201c(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test atmel_03eb_201c",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 09 51 75 08 95 01 81 02 05 01 35 00 55 0e 65 33 75 10 95 01 09 30 26 ff 4b 46 70 03 81 02 09 31 26 ff 2b 46 f1 01 81 02 46 00 00 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 09 51 75 08 95 01 81 02 05 01 35 00 55 0e 65 33 75 10 95 01 09 30 26 ff 4b 46 70 03 81 02 09 31 26 ff 2b 46 f1 01 81 02 46 00 00 c0 05 0d 09 54 75 08 95 01 81 02 05 0d 85 02 09 55 25 02 75 08 95 01 b1 02 c0",
            input_info=(BusType.USB, 0x03EB, 0x201C),
        )


class TestAtmel_03eb_211c(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test atmel_03eb_211c",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 37 81 02 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 46 56 0a 26 ff 0f 09 30 81 02 46 b2 05 26 ff 0f 09 31 81 02 05 0d 75 08 85 02 09 55 25 10 b1 02 c0 c0",
            input_info=(BusType.USB, 0x03EB, 0x211C),
        )


class TestCando_2087_0a02(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test cando_2087_0a02",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 0f 75 10 55 0e 65 33 09 30 35 00 46 6d 03 81 02 46 ec 01 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 0f 75 10 55 0e 65 33 09 30 35 00 46 6d 03 81 02 46 ec 01 09 31 81 02 c0 05 0d 09 54 95 01 75 08 15 00 25 02 81 02 85 02 09 55 b1 02 c0 06 00 ff 09 01 a1 01 85 a6 95 22 75 08 26 ff 00 15 00 09 01 81 02 85 a5 95 06 75 08 26 ff 00 15 00 09 01 91 02 c0",
            input_info=(BusType.USB, 0x2087, 0x0A02),
        )


class TestCando_2087_0b03(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test cando_2087_0b03",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 09 51 75 08 95 01 81 02 05 01 35 00 55 0e 65 33 75 10 95 01 09 30 26 ff 49 46 f2 03 81 02 09 31 26 ff 29 46 39 02 81 02 46 00 00 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 09 51 75 08 95 01 81 02 05 01 35 00 55 0e 65 33 75 10 95 01 09 30 26 ff 49 46 f2 03 81 02 09 31 26 ff 29 46 39 02 81 02 46 00 00 c0 05 0d 09 54 75 08 95 01 81 02 05 0d 85 02 09 55 25 02 75 08 95 01 b1 02 c0",
            input_info=(BusType.USB, 0x2087, 0x0B03),
        )


class TestCVTouch_1ff7_0013(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test cvtouch_1ff7_0013",
            rdesc="06 00 ff 09 00 a1 01 85 fd 06 00 ff 09 01 09 02 09 03 09 04 09 05 09 06 15 00 26 ff 00 75 08 95 06 81 02 85 fe 06 00 ff 09 01 09 02 09 03 09 04 15 00 26 ff 00 75 08 95 04 b1 02 c0 05 01 09 02 a1 01 09 01 a1 00 85 01 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 01 75 05 81 03 05 01 09 30 09 31 15 00 26 ff 7f 35 00 46 ff 7f 75 10 95 02 81 02 05 0d 09 33 15 00 26 ff 00 35 00 46 ff 00 75 08 95 01 81 02 05 01 09 38 15 81 25 7f 35 81 45 7f 95 01 81 06 c0 c0 06 00 ff 09 00 a1 01 85 fc 15 00 26 ff 00 19 01 29 3f 75 08 95 3f 81 02 19 01 29 3f 91 02 c0 06 00 ff 09 00 a1 01 85 fb 15 00 26 ff 00 19 01 29 3f 75 08 95 3f 81 02 19 01 29 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 81 02 c0 05 0d 09 54 15 00 26 ff 00 95 01 75 08 81 02 85 03 09 55 15 00 25 02 b1 02 c0 09 0e a1 01 85 04 09 23 a1 02 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0",
            input_info=(BusType.USB, 0x1FF7, 0x0013),
            quirks=("NOT_SEEN_MEANS_UP",),
        )


class TestCvtouch_1ff7_0017(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test cvtouch_1ff7_0017",
            rdesc="06 00 ff 09 00 a1 01 85 fd 06 00 ff 09 01 09 02 09 03 09 04 09 05 09 06 15 00 26 ff 00 75 08 95 06 81 02 85 fe 06 00 ff 09 01 09 02 09 03 09 04 15 00 26 ff 00 75 08 95 04 b1 02 c0 05 01 09 02 a1 01 09 01 a1 00 85 01 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 01 75 05 81 03 05 01 09 30 09 31 15 00 26 ff 0f 35 00 46 ff 0f 75 10 95 02 81 02 09 00 15 00 25 ff 35 00 45 ff 75 08 95 01 81 02 09 38 15 81 25 7f 95 01 81 06 c0 c0 06 00 ff 09 00 a1 01 85 fc 15 00 25 ff 19 01 29 3f 75 08 95 3f 81 02 19 01 29 3f 91 02 c0 06 00 ff 09 00 a1 01 85 fb 15 00 25 ff 19 01 29 3f 75 08 95 3f 81 02 19 01 29 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 0f 75 10 55 00 65 00 09 30 35 00 46 ff 0f 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 0f 75 10 55 00 65 00 09 30 35 00 46 ff 0f 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 0f 75 10 55 00 65 00 09 30 35 00 46 ff 0f 81 02 09 31 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 15 00 26 ff 0f 75 10 55 00 65 00 09 30 35 00 46 ff 0f 81 02 09 31 81 02 c0 05 0d 09 54 95 01 75 08 81 02 85 03 09 55 25 02 b1 02 c0 09 0e a1 01 85 04 09 23 a1 02 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0",
            input_info=(BusType.USB, 0x1FF7, 0x0017),
        )


class TestCypress_04b4_c001(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test cypress_04b4_c001",
            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 01 75 05 81 01 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0 05 0d 09 04 a1 01 85 02 09 22 09 53 95 01 75 08 81 02 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 15 00 25 20 09 48 81 02 09 49 81 02 05 01 15 00 26 d0 07 75 10 55 00 65 00 09 30 15 00 26 d0 07 35 00 45 00 81 02 09 31 45 00 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 15 00 25 20 09 48 81 02 09 49 81 02 05 01 15 00 26 d0 07 75 10 55 00 65 00 09 30 15 00 26 d0 07 35 00 45 00 81 02 09 31 45 00 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 15 00 25 20 09 48 81 02 09 49 81 02 05 01 15 00 26 d0 07 75 10 55 00 65 00 09 30 15 00 26 d0 07 35 00 45 00 81 02 09 31 45 00 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 15 00 25 20 09 48 81 02 09 49 81 02 05 01 15 00 26 d0 07 75 10 55 00 65 00 09 30 15 00 26 d0 07 35 00 45 00 81 02 09 31 45 00 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 15 00 25 20 09 48 81 02 09 49 81 02 05 01 15 00 26 d0 07 75 10 55 00 65 00 09 30 15 00 26 d0 07 35 00 45 00 81 02 09 31 45 00 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 15 00 25 20 09 48 81 02 09 49 81 02 05 01 15 00 26 d0 07 75 10 55 00 65 00 09 30 15 00 26 d0 07 35 00 45 00 81 02 09 31 45 00 81 02 c0 05 0d 09 54 95 01 75 08 15 00 25 0a 81 02 09 55 b1 02 c0 09 0e a1 01 85 03 09 23 a1 02 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0",
            input_info=(BusType.USB, 0x04B4, 0xC001),
        )


class TestData_modul_7374_1232(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test data-modul_7374_1232",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 37 81 02 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 46 d0 07 26 ff 0f 09 30 81 02 46 40 06 09 31 81 02 05 0d 75 08 85 02 09 55 25 10 b1 02 c0 c0",
            input_info=(BusType.USB, 0x7374, 0x1232),
        )


class TestData_modul_7374_1252(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test data-modul_7374_1252",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 37 81 02 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 46 d0 07 26 ff 0f 09 30 81 02 46 40 06 09 31 81 02 05 0d 75 08 85 02 09 55 25 10 b1 02 c0 c0",
            input_info=(BusType.USB, 0x7374, 0x1252),
        )


class TestE4_2219_044c(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test e4_2219_044c",
            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 46 00 00 81 02 c0 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 7f 75 10 55 00 65 00 09 30 35 00 46 00 00 81 02 09 31 46 00 00 81 02 c0 05 0d 09 54 95 01 75 08 15 00 25 08 81 02 09 55 b1 02 c0 09 0e a1 01 85 02 09 23 a1 02 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0 05 01 09 02 a1 01 85 03 09 01 a1 00 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 01 75 05 81 01 05 01 09 30 09 31 15 00 26 ff 7f 75 10 95 02 81 02 05 01 09 38 15 81 25 7f 75 08 95 01 81 06 c0 c0",
            input_info=(BusType.USB, 0x2219, 0x044C),
        )


class TestEgalax_capacitive_0eef_7224(BaseTest.TestMultitouch):
    def create_device(self):
        return Digitizer(
            "uhid test egalax-capacitive_0eef_7224",
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=90 G=93

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.44Angebot  ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.