Path: blob/master/tools/testing/selftests/hid/tests/test_tablet.py
48890 views
#!/bin/env python31# SPDX-License-Identifier: GPL-2.02# -*- coding: utf-8 -*-3#4# Copyright (c) 2021 Benjamin Tissoires <[email protected]>5# Copyright (c) 2021 Red Hat, Inc.6#78from . import base9import copy10from enum import Enum11from hidtools.util import BusType12from .base import HidBpf13import libevdev14import logging15import pytest16from typing import Dict, List, Optional, Tuple1718logger = logging.getLogger("hidtools.test.tablet")192021class BtnTouch(Enum):22"""Represents whether the BTN_TOUCH event is set to True or False"""2324DOWN = True25UP = False262728class ToolType(Enum):29PEN = libevdev.EV_KEY.BTN_TOOL_PEN30RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER313233class BtnPressed(Enum):34"""Represents whether a button is pressed on the stylus"""3536PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS37SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS238THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS3394041class PenState(Enum):42"""Pen states according to Microsoft reference:43https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states4445We extend it with the various buttons when we need to check them.46"""4748PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False49PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False50PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True51PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False52PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True53PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False54PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True55PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False56PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True5758def __init__(59self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]60):61self.touch = touch # type: ignore62self.tool = tool # type: ignore63self.button = button # type: ignore6465@classmethod66def from_evdev(cls, evdev, test_button) -> "PenState":67touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])68tool = None69button = False70if (71evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]72and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]73):74tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)75elif (76evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]77and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]78):79tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)80elif (81evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]82or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]83):84raise ValueError("2 tools are not allowed")8586# we take only the provided button into account87if test_button is not None:88button = bool(evdev.value[test_button.value])8990# the kernel tends to insert an EV_SYN once removing the tool, so91# the button will be released after92if tool is None:93button = False9495return cls((touch, tool, button)) # type: ignore9697def apply(98self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed99) -> "PenState":100if libevdev.EV_SYN.SYN_REPORT in events:101raise ValueError("EV_SYN is in the event sequence")102touch = self.touch103touch_found = False104tool = self.tool105tool_found = False106button = self.button107button_found = False108109for ev in events:110if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):111if touch_found:112raise ValueError(f"duplicated BTN_TOUCH in {events}")113touch_found = True114touch = BtnTouch(ev.value)115elif ev in (116libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),117libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),118):119if tool_found:120raise ValueError(f"duplicated BTN_TOOL_* in {events}")121tool_found = True122tool = ToolType(ev.code) if ev.value else None123elif test_button is not None and ev in (test_button.value,):124if button_found:125raise ValueError(f"duplicated BTN_STYLUS* in {events}")126button_found = True127button = bool(ev.value)128129# the kernel tends to insert an EV_SYN once removing the tool, so130# the button will be released after131if tool is None:132button = False133134new_state = PenState((touch, tool, button)) # type: ignore135if strict:136assert (137new_state in self.valid_transitions()138), f"moving from {self} to {new_state} is forbidden"139else:140assert (141new_state in self.historically_tolerated_transitions()142), f"moving from {self} to {new_state} is forbidden"143144return new_state145146def valid_transitions(self) -> Tuple["PenState", ...]:147"""Following the state machine in the URL above.148149Note that those transitions are from the evdev point of view, not HID"""150if self == PenState.PEN_IS_OUT_OF_RANGE:151return (152PenState.PEN_IS_OUT_OF_RANGE,153PenState.PEN_IS_IN_RANGE,154PenState.PEN_IS_IN_RANGE_WITH_BUTTON,155PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,156PenState.PEN_IS_IN_CONTACT,157PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,158PenState.PEN_IS_ERASING,159)160161if self == PenState.PEN_IS_IN_RANGE:162return (163PenState.PEN_IS_IN_RANGE,164PenState.PEN_IS_IN_RANGE_WITH_BUTTON,165PenState.PEN_IS_OUT_OF_RANGE,166PenState.PEN_IS_IN_CONTACT,167)168169if self == PenState.PEN_IS_IN_CONTACT:170return (171PenState.PEN_IS_IN_CONTACT,172PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,173PenState.PEN_IS_IN_RANGE,174)175176if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:177return (178PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,179PenState.PEN_IS_OUT_OF_RANGE,180PenState.PEN_IS_ERASING,181)182183if self == PenState.PEN_IS_ERASING:184return (185PenState.PEN_IS_ERASING,186PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,187)188189if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:190return (191PenState.PEN_IS_IN_RANGE_WITH_BUTTON,192PenState.PEN_IS_IN_RANGE,193PenState.PEN_IS_OUT_OF_RANGE,194PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,195)196197if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:198return (199PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,200PenState.PEN_IS_IN_CONTACT,201PenState.PEN_IS_IN_RANGE_WITH_BUTTON,202)203204return tuple()205206def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:207"""Following the state machine in the URL above, with a couple of addition208for skipping the in-range state, due to historical reasons.209210Note that those transitions are from the evdev point of view, not HID"""211if self == PenState.PEN_IS_OUT_OF_RANGE:212return (213PenState.PEN_IS_OUT_OF_RANGE,214PenState.PEN_IS_IN_RANGE,215PenState.PEN_IS_IN_RANGE_WITH_BUTTON,216PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,217PenState.PEN_IS_IN_CONTACT,218PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,219PenState.PEN_IS_ERASING,220)221222if self == PenState.PEN_IS_IN_RANGE:223return (224PenState.PEN_IS_IN_RANGE,225PenState.PEN_IS_IN_RANGE_WITH_BUTTON,226PenState.PEN_IS_OUT_OF_RANGE,227PenState.PEN_IS_IN_CONTACT,228)229230if self == PenState.PEN_IS_IN_CONTACT:231return (232PenState.PEN_IS_IN_CONTACT,233PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,234PenState.PEN_IS_IN_RANGE,235PenState.PEN_IS_OUT_OF_RANGE,236)237238if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:239return (240PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,241PenState.PEN_IS_OUT_OF_RANGE,242PenState.PEN_IS_ERASING,243)244245if self == PenState.PEN_IS_ERASING:246return (247PenState.PEN_IS_ERASING,248PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,249PenState.PEN_IS_OUT_OF_RANGE,250)251252if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:253return (254PenState.PEN_IS_IN_RANGE_WITH_BUTTON,255PenState.PEN_IS_IN_RANGE,256PenState.PEN_IS_OUT_OF_RANGE,257PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,258)259260if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:261return (262PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,263PenState.PEN_IS_IN_CONTACT,264PenState.PEN_IS_IN_RANGE_WITH_BUTTON,265PenState.PEN_IS_OUT_OF_RANGE,266)267268return tuple()269270@staticmethod271def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:272"""This is the first half of the Windows Pen Implementation state machine:273we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.274https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states275"""276return {277"in-range": (PenState.PEN_IS_IN_RANGE,),278"in-range -> out-of-range": (279PenState.PEN_IS_IN_RANGE,280PenState.PEN_IS_OUT_OF_RANGE,281),282"in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT),283"in-range -> touch -> release": (284PenState.PEN_IS_IN_RANGE,285PenState.PEN_IS_IN_CONTACT,286PenState.PEN_IS_IN_RANGE,287),288"in-range -> touch -> release -> out-of-range": (289PenState.PEN_IS_IN_RANGE,290PenState.PEN_IS_IN_CONTACT,291PenState.PEN_IS_IN_RANGE,292PenState.PEN_IS_OUT_OF_RANGE,293),294}295296@staticmethod297def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:298"""This is the second half of the Windows Pen Implementation state machine:299we now have Invert and Erase bits, so move in/out or proximity with the intend300to erase.301https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states302"""303return {304"hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,),305"hover-erasing -> out-of-range": (306PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,307PenState.PEN_IS_OUT_OF_RANGE,308),309"hover-erasing -> erase": (310PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,311PenState.PEN_IS_ERASING,312),313"hover-erasing -> erase -> release": (314PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,315PenState.PEN_IS_ERASING,316PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,317),318"hover-erasing -> erase -> release -> out-of-range": (319PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,320PenState.PEN_IS_ERASING,321PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,322PenState.PEN_IS_OUT_OF_RANGE,323),324"hover-erasing -> in-range": (325PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,326PenState.PEN_IS_IN_RANGE,327),328"in-range -> hover-erasing": (329PenState.PEN_IS_IN_RANGE,330PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,331),332}333334@staticmethod335def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:336"""We revisit the Windows Pen Implementation state machine:337we now have a button.338"""339return {340"hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),341"hover-button -> out-of-range": (342PenState.PEN_IS_IN_RANGE_WITH_BUTTON,343PenState.PEN_IS_OUT_OF_RANGE,344),345"in-range -> button-press": (346PenState.PEN_IS_IN_RANGE,347PenState.PEN_IS_IN_RANGE_WITH_BUTTON,348),349"in-range -> button-press -> button-release": (350PenState.PEN_IS_IN_RANGE,351PenState.PEN_IS_IN_RANGE_WITH_BUTTON,352PenState.PEN_IS_IN_RANGE,353),354"in-range -> touch -> button-press -> button-release": (355PenState.PEN_IS_IN_RANGE,356PenState.PEN_IS_IN_CONTACT,357PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,358PenState.PEN_IS_IN_CONTACT,359),360"in-range -> touch -> button-press -> release -> button-release": (361PenState.PEN_IS_IN_RANGE,362PenState.PEN_IS_IN_CONTACT,363PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,364PenState.PEN_IS_IN_RANGE_WITH_BUTTON,365PenState.PEN_IS_IN_RANGE,366),367"in-range -> button-press -> touch -> release -> button-release": (368PenState.PEN_IS_IN_RANGE,369PenState.PEN_IS_IN_RANGE_WITH_BUTTON,370PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,371PenState.PEN_IS_IN_RANGE_WITH_BUTTON,372PenState.PEN_IS_IN_RANGE,373),374"in-range -> button-press -> touch -> button-release -> release": (375PenState.PEN_IS_IN_RANGE,376PenState.PEN_IS_IN_RANGE_WITH_BUTTON,377PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,378PenState.PEN_IS_IN_CONTACT,379PenState.PEN_IS_IN_RANGE,380),381}382383@staticmethod384def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:385"""This is not adhering to the Windows Pen Implementation state machine386but we should expect the kernel to behave properly, mostly for historical387reasons."""388return {389"direct-in-contact": (PenState.PEN_IS_IN_CONTACT,),390"direct-in-contact -> out-of-range": (391PenState.PEN_IS_IN_CONTACT,392PenState.PEN_IS_OUT_OF_RANGE,393),394}395396@staticmethod397def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:398"""This is the second half of the Windows Pen Implementation state machine:399we now have Invert and Erase bits, so move in/out or proximity with the intend400to erase.401https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states402"""403return {404"direct-erase": (PenState.PEN_IS_ERASING,),405"direct-erase -> out-of-range": (406PenState.PEN_IS_ERASING,407PenState.PEN_IS_OUT_OF_RANGE,408),409}410411@staticmethod412def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:413"""Those tests are definitely not part of the Windows specification.414However, a half broken device might export those transitions.415For example, a pen that has the eraser button might wobble between416touching and erasing if the tablet doesn't enforce the Windows417state machine."""418return {419"in-range -> touch -> erase -> hover-erase": (420PenState.PEN_IS_IN_RANGE,421PenState.PEN_IS_IN_CONTACT,422PenState.PEN_IS_ERASING,423PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,424),425"in-range -> erase -> hover-erase": (426PenState.PEN_IS_IN_RANGE,427PenState.PEN_IS_ERASING,428PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,429),430"hover-erase -> erase -> touch -> in-range": (431PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,432PenState.PEN_IS_ERASING,433PenState.PEN_IS_IN_CONTACT,434PenState.PEN_IS_IN_RANGE,435),436"hover-erase -> touch -> in-range": (437PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,438PenState.PEN_IS_IN_CONTACT,439PenState.PEN_IS_IN_RANGE,440),441"touch -> erase -> touch -> erase": (442PenState.PEN_IS_IN_CONTACT,443PenState.PEN_IS_ERASING,444PenState.PEN_IS_IN_CONTACT,445PenState.PEN_IS_ERASING,446),447}448449450class Pen(object):451def __init__(self, x, y):452self.x = x453self.y = y454self.distance = -10455self.tipswitch = False456self.tippressure = 15457self.azimuth = 0458self.inrange = False459self.width = 10460self.height = 10461self.barrelswitch = False462self.secondarybarrelswitch = False463self.invert = False464self.eraser = False465self.xtilt = 1466self.ytilt = 1467self.twist = 1468self._old_values = None469self.current_state = None470471def restore(self):472if self._old_values is not None:473for i in [474"x",475"y",476"distance",477"tippressure",478"azimuth",479"width",480"height",481"twist",482"xtilt",483"ytilt",484]:485setattr(self, i, getattr(self._old_values, i))486487def backup(self):488self._old_values = copy.copy(self)489490def __assert_axis(self, evdev, axis, value):491if (492axis == libevdev.EV_KEY.BTN_TOOL_RUBBER493and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None494):495return496497assert (498evdev.value[axis] == value499), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"500501def assert_expected_input_events(self, evdev, button):502assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x503assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y504505# assert no other buttons than the tested ones are set506buttons = [507BtnPressed.PRIMARY_PRESSED,508BtnPressed.SECONDARY_PRESSED,509BtnPressed.THIRD_PRESSED,510]511if button is not None:512buttons.remove(button)513for b in buttons:514assert evdev.value[b.value] is None or evdev.value[b.value] == False515516assert self.current_state == PenState.from_evdev(evdev, button)517518519class PenDigitizer(base.UHIDTestDevice):520def __init__(521self,522name,523rdesc_str=None,524rdesc=None,525application="Pen",526physical="Stylus",527input_info=(BusType.USB, 1, 2),528evdev_name_suffix=None,529):530super().__init__(name, application, rdesc_str, rdesc, input_info)531self.physical = physical532self.cur_application = application533if evdev_name_suffix is not None:534self.name += evdev_name_suffix535536self.fields = []537for r in self.parsed_rdesc.input_reports.values():538if r.application_name == self.application:539physicals = [f.physical_name for f in r]540if self.physical not in physicals and None not in physicals:541continue542self.fields = [f.usage_name for f in r]543544def move_to(self, pen, state, button):545# fill in the previous values546if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:547pen.restore()548549print(f"\n *** pen is moving to {state} ***")550551if state == PenState.PEN_IS_OUT_OF_RANGE:552pen.backup()553pen.x = 0554pen.y = 0555pen.tipswitch = False556pen.tippressure = 0557pen.azimuth = 0558pen.distance = 0559pen.inrange = False560pen.width = 0561pen.height = 0562pen.invert = False563pen.eraser = False564pen.xtilt = 0565pen.ytilt = 0566pen.twist = 0567pen.barrelswitch = False568pen.secondarybarrelswitch = False569elif state == PenState.PEN_IS_IN_RANGE:570pen.tipswitch = False571pen.inrange = True572pen.invert = False573pen.eraser = False574pen.barrelswitch = False575pen.secondarybarrelswitch = False576elif state == PenState.PEN_IS_IN_CONTACT:577pen.tipswitch = True578pen.inrange = True579pen.invert = False580pen.eraser = False581pen.barrelswitch = False582pen.secondarybarrelswitch = False583elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:584pen.tipswitch = False585pen.inrange = True586pen.invert = False587pen.eraser = False588assert button is not None589pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED590pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED591elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:592pen.tipswitch = True593pen.inrange = True594pen.invert = False595pen.eraser = False596assert button is not None597pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED598pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED599elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:600pen.tipswitch = False601pen.inrange = True602pen.invert = True603pen.eraser = False604pen.barrelswitch = False605pen.secondarybarrelswitch = False606elif state == PenState.PEN_IS_ERASING:607pen.tipswitch = False608pen.inrange = True609pen.invert = False610pen.eraser = True611pen.barrelswitch = False612pen.secondarybarrelswitch = False613614pen.current_state = state615616def event(self, pen, button):617rs = []618r = self.create_report(application=self.cur_application, data=pen)619self.call_input_event(r)620rs.append(r)621return rs622623def get_report(self, req, rnum, rtype):624if rtype != self.UHID_FEATURE_REPORT:625return (1, [])626627rdesc = None628for v in self.parsed_rdesc.feature_reports.values():629if v.report_ID == rnum:630rdesc = v631632if rdesc is None:633return (1, [])634635return (1, [])636637def set_report(self, req, rnum, rtype, data):638if rtype != self.UHID_FEATURE_REPORT:639return 1640641rdesc = None642for v in self.parsed_rdesc.feature_reports.values():643if v.report_ID == rnum:644rdesc = v645646if rdesc is None:647return 1648649return 1650651652class BaseTest:653class TestTablet(base.BaseTestCase.TestUhid):654def create_device(self):655raise Exception("please reimplement me in subclasses")656657def post(self, uhdev, pen, test_button):658r = uhdev.event(pen, test_button)659events = uhdev.next_sync_events()660self.debug_reports(r, uhdev, events)661return events662663def validate_transitions(664self, from_state, pen, evdev, events, allow_intermediate_states, button665):666# check that the final state is correct667pen.assert_expected_input_events(evdev, button)668669state = from_state670671# check that the transitions are valid672sync_events = []673while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:674# split the first EV_SYN from the list675idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))676sync_events = events[:idx]677events = events[idx + 1 :]678679# now check for a valid transition680state = state.apply(sync_events, not allow_intermediate_states, button)681682if events:683state = state.apply(sync_events, not allow_intermediate_states, button)684685def _test_states(686self, state_list, scribble, allow_intermediate_states, button=None687):688"""Internal method to test against a list of689transition between states.690state_list is a list of PenState objects691scribble is a boolean which tells if we need692to wobble a little the X,Y coordinates of the pen693between each state transition."""694uhdev = self.uhdev695evdev = uhdev.get_evdev()696697cur_state = PenState.PEN_IS_OUT_OF_RANGE698699p = Pen(50, 60)700uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)701events = self.post(uhdev, p, button)702self.validate_transitions(703cur_state, p, evdev, events, allow_intermediate_states, button704)705706cur_state = p.current_state707708for state in state_list:709if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:710p.x += 1711p.y -= 1712events = self.post(uhdev, p, button)713self.validate_transitions(714cur_state, p, evdev, events, allow_intermediate_states, button715)716assert len(events) >= 3 # X, Y, SYN717uhdev.move_to(p, state, button)718if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:719p.x += 1720p.y -= 1721events = self.post(uhdev, p, button)722self.validate_transitions(723cur_state, p, evdev, events, allow_intermediate_states, button724)725cur_state = p.current_state726727@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])728@pytest.mark.parametrize(729"state_list",730[pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],731)732def test_valid_pen_states(self, state_list, scribble):733"""This is the first half of the Windows Pen Implementation state machine:734we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.735https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states736"""737self._test_states(state_list, scribble, allow_intermediate_states=False)738739@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])740@pytest.mark.parametrize(741"state_list",742[743pytest.param(v, id=k)744for k, v in PenState.tolerated_transitions().items()745],746)747def test_tolerated_pen_states(self, state_list, scribble):748"""This is not adhering to the Windows Pen Implementation state machine749but we should expect the kernel to behave properly, mostly for historical750reasons."""751self._test_states(state_list, scribble, allow_intermediate_states=True)752753@pytest.mark.skip_if_uhdev(754lambda uhdev: "Barrel Switch" not in uhdev.fields,755"Device not compatible, missing Barrel Switch usage",756)757@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])758@pytest.mark.parametrize(759"state_list",760[761pytest.param(v, id=k)762for k, v in PenState.legal_transitions_with_button().items()763],764)765def test_valid_primary_button_pen_states(self, state_list, scribble):766"""Rework the transition state machine by adding the primary button."""767self._test_states(768state_list,769scribble,770allow_intermediate_states=False,771button=BtnPressed.PRIMARY_PRESSED,772)773774@pytest.mark.skip_if_uhdev(775lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,776"Device not compatible, missing Secondary Barrel Switch usage",777)778@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])779@pytest.mark.parametrize(780"state_list",781[782pytest.param(v, id=k)783for k, v in PenState.legal_transitions_with_button().items()784],785)786def test_valid_secondary_button_pen_states(self, state_list, scribble):787"""Rework the transition state machine by adding the secondary button."""788self._test_states(789state_list,790scribble,791allow_intermediate_states=False,792button=BtnPressed.SECONDARY_PRESSED,793)794795@pytest.mark.skip_if_uhdev(796lambda uhdev: "Third Barrel Switch" not in uhdev.fields,797"Device not compatible, missing Third Barrel Switch usage",798)799@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])800@pytest.mark.parametrize(801"state_list",802[803pytest.param(v, id=k)804for k, v in PenState.legal_transitions_with_button().items()805],806)807def test_valid_third_button_pen_states(self, state_list, scribble):808"""Rework the transition state machine by adding the secondary button."""809self._test_states(810state_list,811scribble,812allow_intermediate_states=False,813button=BtnPressed.THIRD_PRESSED,814)815816@pytest.mark.skip_if_uhdev(817lambda uhdev: "Invert" not in uhdev.fields,818"Device not compatible, missing Invert usage",819)820@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])821@pytest.mark.parametrize(822"state_list",823[824pytest.param(v, id=k)825for k, v in PenState.legal_transitions_with_invert().items()826],827)828def test_valid_invert_pen_states(self, state_list, scribble):829"""This is the second half of the Windows Pen Implementation state machine:830we now have Invert and Erase bits, so move in/out or proximity with the intend831to erase.832https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states833"""834self._test_states(state_list, scribble, allow_intermediate_states=False)835836@pytest.mark.skip_if_uhdev(837lambda uhdev: "Invert" not in uhdev.fields,838"Device not compatible, missing Invert usage",839)840@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])841@pytest.mark.parametrize(842"state_list",843[844pytest.param(v, id=k)845for k, v in PenState.tolerated_transitions_with_invert().items()846],847)848def test_tolerated_invert_pen_states(self, state_list, scribble):849"""This is the second half of the Windows Pen Implementation state machine:850we now have Invert and Erase bits, so move in/out or proximity with the intend851to erase.852https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states853"""854self._test_states(state_list, scribble, allow_intermediate_states=True)855856@pytest.mark.skip_if_uhdev(857lambda uhdev: "Invert" not in uhdev.fields,858"Device not compatible, missing Invert usage",859)860@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])861@pytest.mark.parametrize(862"state_list",863[pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],864)865def test_tolerated_broken_pen_states(self, state_list, scribble):866"""Those tests are definitely not part of the Windows specification.867However, a half broken device might export those transitions.868For example, a pen that has the eraser button might wobble between869touching and erasing if the tablet doesn't enforce the Windows870state machine."""871self._test_states(state_list, scribble, allow_intermediate_states=True)872873@pytest.mark.skip_if_uhdev(874lambda uhdev: "Z" not in uhdev.fields,875"Device not compatible, missing Z usage",876)877@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])878@pytest.mark.parametrize(879"state_list",880[pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],881)882def test_z_reported_as_distance(self, state_list, scribble):883"""Verify stylus Z values are reported as ABS_DISTANCE."""884self._test_states(state_list, scribble, allow_intermediate_states=False)885886uhdev = self.uhdev887evdev = uhdev.get_evdev()888p = Pen(0, 0)889uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, None)890p = Pen(100, 200)891uhdev.move_to(p, PenState.PEN_IS_IN_RANGE, None)892p.distance = -1893events = self.post(uhdev, p, None)894assert evdev.value[libevdev.EV_ABS.ABS_DISTANCE] == -1895896897class GXTP_pen(PenDigitizer):898def event(self, pen, test_button):899if not hasattr(self, "prev_tip_state"):900self.prev_tip_state = False901902internal_pen = copy.copy(pen)903904# bug in the controller: when the pen touches the905# surface, in-range stays to 1, but when906# the pen moves in-range gets reverted to 0907if pen.tipswitch and self.prev_tip_state:908internal_pen.inrange = False909910self.prev_tip_state = pen.tipswitch911912# another bug in the controller: when the pen is913# inverted, invert is set to 1, but as soon as914# the pen touches the surface, eraser is correctly915# set to 1 but invert is released916if pen.eraser:917internal_pen.invert = False918919return super().event(internal_pen, test_button)920921922class USIPen(PenDigitizer):923pass924925926class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):927"""928Pen with two buttons and a rubber end, but which reports929the second button as an eraser930"""931932def __init__(933self,934name,935rdesc_str=None,936rdesc=None,937application="Pen",938physical="Stylus",939input_info=(BusType.USB, 0x28BD, 0x095B),940evdev_name_suffix=None,941):942super().__init__(943name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix944)945self.fields.append("Secondary Barrel Switch")946947def move_to(self, pen, state, button):948# fill in the previous values949if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:950pen.restore()951952print(f"\n *** pen is moving to {state} ***")953954if state == PenState.PEN_IS_OUT_OF_RANGE:955pen.backup()956pen.x = 0957pen.y = 0958pen.tipswitch = False959pen.tippressure = 0960pen.azimuth = 0961pen.inrange = False962pen.width = 0963pen.height = 0964pen.invert = False965pen.eraser = False966pen.xtilt = 0967pen.ytilt = 0968pen.twist = 0969pen.barrelswitch = False970elif state == PenState.PEN_IS_IN_RANGE:971pen.tipswitch = False972pen.inrange = True973pen.invert = False974pen.eraser = False975pen.barrelswitch = False976elif state == PenState.PEN_IS_IN_CONTACT:977pen.tipswitch = True978pen.inrange = True979pen.invert = False980pen.eraser = False981pen.barrelswitch = False982elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:983pen.tipswitch = False984pen.inrange = True985pen.invert = False986assert button is not None987pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED988pen.eraser = button == BtnPressed.SECONDARY_PRESSED989elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:990pen.tipswitch = True991pen.inrange = True992pen.invert = False993assert button is not None994pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED995pen.eraser = button == BtnPressed.SECONDARY_PRESSED996elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:997pen.tipswitch = False998pen.inrange = True999pen.invert = True1000pen.eraser = False1001pen.barrelswitch = False1002elif state == PenState.PEN_IS_ERASING:1003pen.tipswitch = True1004pen.inrange = True1005pen.invert = True1006pen.eraser = False1007pen.barrelswitch = False10081009pen.current_state = state10101011def event(self, pen, test_button):1012import math10131014pen_copy = copy.copy(pen)1015width = 13.5671016height = 8.4801017tip_height = 0.0556776991018hx = tip_height * (32767 / width)1019hy = tip_height * (32767 / height)1020if pen_copy.xtilt != 0:1021pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))1022if pen_copy.ytilt != 0:1023pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))10241025return super().event(pen_copy, test_button)102610271028class XPPen_Artist24_28bd_093a(PenDigitizer):1029"""1030Pen that reports secondary barrel switch through eraser1031"""10321033def __init__(1034self,1035name,1036rdesc_str=None,1037rdesc=None,1038application="Pen",1039physical="Stylus",1040input_info=(BusType.USB, 0x28BD, 0x093A),1041evdev_name_suffix=None,1042):1043super().__init__(1044name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1045)1046self.fields.append("Secondary Barrel Switch")1047self.previous_state = PenState.PEN_IS_OUT_OF_RANGE10481049def move_to(self, pen, state, button, debug=True):1050# fill in the previous values1051if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1052pen.restore()10531054if debug:1055print(f"\n *** pen is moving to {state} ***")10561057if state == PenState.PEN_IS_OUT_OF_RANGE:1058pen.backup()1059pen.tipswitch = False1060pen.tippressure = 01061pen.azimuth = 01062pen.inrange = False1063pen.width = 01064pen.height = 01065pen.invert = False1066pen.eraser = False1067pen.xtilt = 01068pen.ytilt = 01069pen.twist = 01070pen.barrelswitch = False1071elif state == PenState.PEN_IS_IN_RANGE:1072pen.tipswitch = False1073pen.inrange = True1074pen.invert = False1075pen.eraser = False1076pen.barrelswitch = False1077elif state == PenState.PEN_IS_IN_CONTACT:1078pen.tipswitch = True1079pen.inrange = True1080pen.invert = False1081pen.eraser = False1082pen.barrelswitch = False1083elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1084pen.tipswitch = False1085pen.inrange = True1086pen.invert = False1087assert button is not None1088pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1089pen.eraser = button == BtnPressed.SECONDARY_PRESSED1090elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1091pen.tipswitch = True1092pen.inrange = True1093pen.invert = False1094assert button is not None1095pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1096pen.eraser = button == BtnPressed.SECONDARY_PRESSED10971098pen.current_state = state10991100def send_intermediate_state(self, pen, state, button):1101intermediate_pen = copy.copy(pen)1102self.move_to(intermediate_pen, state, button, debug=False)1103return super().event(intermediate_pen, button)11041105def event(self, pen, button):1106rs = []11071108# the pen reliably sends in-range events in a normal case (non emulation of eraser mode)1109if self.previous_state == PenState.PEN_IS_IN_CONTACT:1110if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1111rs.extend(1112self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1113)11141115if button == BtnPressed.SECONDARY_PRESSED:1116if self.previous_state == PenState.PEN_IS_IN_RANGE:1117if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1118rs.extend(1119self.send_intermediate_state(1120pen, PenState.PEN_IS_OUT_OF_RANGE, button1121)1122)11231124if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1125if pen.current_state == PenState.PEN_IS_IN_RANGE:1126rs.extend(1127self.send_intermediate_state(1128pen, PenState.PEN_IS_OUT_OF_RANGE, button1129)1130)11311132if self.previous_state == PenState.PEN_IS_IN_CONTACT:1133if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1134rs.extend(1135self.send_intermediate_state(1136pen, PenState.PEN_IS_OUT_OF_RANGE, button1137)1138)1139rs.extend(1140self.send_intermediate_state(1141pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button1142)1143)11441145if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1146if pen.current_state == PenState.PEN_IS_IN_CONTACT:1147rs.extend(1148self.send_intermediate_state(1149pen, PenState.PEN_IS_OUT_OF_RANGE, button1150)1151)1152rs.extend(1153self.send_intermediate_state(1154pen, PenState.PEN_IS_IN_RANGE, button1155)1156)11571158rs.extend(super().event(pen, button))1159self.previous_state = pen.current_state1160return rs116111621163class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):1164"""1165Pen that reports secondary barrel switch through secondary TipSwtich1166and 3rd button through Invert1167"""11681169def __init__(1170self,1171name,1172rdesc_str=None,1173rdesc=None,1174application="Stylus",1175physical=None,1176input_info=(BusType.USB, 0x256C, 0x006B),1177evdev_name_suffix=None,1178):1179super().__init__(1180name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1181)1182self.fields.append("Secondary Barrel Switch")1183self.fields.append("Third Barrel Switch")1184self.previous_state = PenState.PEN_IS_OUT_OF_RANGE11851186def move_to(self, pen, state, button, debug=True):1187# fill in the previous values1188if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1189pen.restore()11901191if debug:1192print(f"\n *** pen is moving to {state} ***")11931194if state == PenState.PEN_IS_OUT_OF_RANGE:1195pen.backup()1196pen.tipswitch = False1197pen.tippressure = 01198pen.azimuth = 01199pen.inrange = False1200pen.width = 01201pen.height = 01202pen.invert = False1203pen.eraser = False1204pen.xtilt = 01205pen.ytilt = 01206pen.twist = 01207pen.barrelswitch = False1208pen.secondarytipswitch = False1209elif state == PenState.PEN_IS_IN_RANGE:1210pen.tipswitch = False1211pen.inrange = True1212pen.invert = False1213pen.eraser = False1214pen.barrelswitch = False1215pen.secondarytipswitch = False1216elif state == PenState.PEN_IS_IN_CONTACT:1217pen.tipswitch = True1218pen.inrange = True1219pen.invert = False1220pen.eraser = False1221pen.barrelswitch = False1222pen.secondarytipswitch = False1223elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1224pen.tipswitch = False1225pen.inrange = True1226pen.eraser = False1227assert button is not None1228pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1229pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1230pen.invert = button == BtnPressed.THIRD_PRESSED1231elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1232pen.tipswitch = True1233pen.inrange = True1234pen.eraser = False1235assert button is not None1236pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1237pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1238pen.invert = button == BtnPressed.THIRD_PRESSED1239elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:1240pen.tipswitch = False1241pen.inrange = True1242pen.invert = True1243pen.eraser = False1244pen.barrelswitch = False1245pen.secondarytipswitch = False1246elif state == PenState.PEN_IS_ERASING:1247pen.tipswitch = False1248pen.inrange = True1249pen.invert = False1250pen.eraser = True1251pen.barrelswitch = False1252pen.secondarytipswitch = False12531254pen.current_state = state12551256def call_input_event(self, report):1257if report[0] == 0x0A:1258# ensures the original second Eraser usage is null1259report[1] &= 0xDF12601261# ensures the original last bit is equal to bit 6 (In Range)1262if report[1] & 0x40:1263report[1] |= 0x8012641265super().call_input_event(report)12661267def send_intermediate_state(self, pen, state, test_button):1268intermediate_pen = copy.copy(pen)1269self.move_to(intermediate_pen, state, test_button, debug=False)1270return super().event(intermediate_pen, test_button)12711272def event(self, pen, button):1273rs = []12741275# it's not possible to go between eraser mode or not without1276# going out-of-prox: the eraser mode is activated by presenting1277# the tail of the pen1278if self.previous_state in (1279PenState.PEN_IS_IN_RANGE,1280PenState.PEN_IS_IN_RANGE_WITH_BUTTON,1281PenState.PEN_IS_IN_CONTACT,1282PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,1283) and pen.current_state in (1284PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,1285PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,1286PenState.PEN_IS_ERASING,1287PenState.PEN_IS_ERASING_WITH_BUTTON,1288):1289rs.extend(1290self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1291)12921293# same than above except from eraser to normal1294if self.previous_state in (1295PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,1296PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,1297PenState.PEN_IS_ERASING,1298PenState.PEN_IS_ERASING_WITH_BUTTON,1299) and pen.current_state in (1300PenState.PEN_IS_IN_RANGE,1301PenState.PEN_IS_IN_RANGE_WITH_BUTTON,1302PenState.PEN_IS_IN_CONTACT,1303PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,1304):1305rs.extend(1306self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1307)13081309if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:1310if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1311rs.extend(1312self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1313)13141315rs.extend(super().event(pen, button))1316self.previous_state = pen.current_state1317return rs131813191320class Wacom_2d1f_014b(PenDigitizer):1321"""1322Pen that reports distance values with HID_GD_Z usage.1323"""1324def __init__(1325self,1326name,1327rdesc_str=None,1328rdesc=None,1329application="Pen",1330physical="Stylus",1331input_info=(BusType.USB, 0x2D1F, 0x014B),1332evdev_name_suffix=None,1333):1334super().__init__(1335name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1336)13371338def match_evdev_rule(self, application, evdev):1339# there are 2 nodes created by the device, only one matters1340return evdev.name.endswith("Stylus")13411342def event(self, pen, test_button):1343# this device reports the distance through Z1344pen.z = pen.distance13451346return super().event(pen, test_button)134713481349################################################################################1350#1351# Windows 7 compatible devices1352#1353################################################################################1354# class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):1355# def create_device(self):1356# return PenDigitizer('uhid test egalax-capacitive_0eef_7224',1357# rdesc='05 0d 09 04 a1 01 85 04 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 15 00 25 01 81 02 09 51 75 05 95 01 16 00 00 26 10 00 81 02 09 47 75 01 95 01 15 00 25 01 81 02 05 01 09 30 75 10 95 01 55 0d 65 33 35 00 46 34 49 26 ff 7f 81 02 09 31 75 10 95 01 55 0d 65 33 35 00 46 37 29 26 ff 7f 81 02 05 0d 09 55 25 08 75 08 95 01 b1 02 c0 c0 05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 01 75 06 81 01 05 01 09 30 09 31 16 00 00 26 ff 0f 36 00 00 46 ff 0f 66 00 00 75 10 95 02 81 02 c0 c0 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 85 03 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 20 a1 00 09 42 09 32 15 00 25 01 95 02 75 01 81 02 95 06 75 01 81 03 05 01 09 30 75 10 95 01 a4 55 0d 65 33 36 00 00 46 34 49 16 00 00 26 ff 0f 81 02 09 31 16 00 00 26 ff 0f 36 00 00 46 37 29 81 02 b4 c0 c0 05 0d 09 0e a1 01 85 05 09 22 a1 00 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0',1358# input_info=(BusType.USB, 0x0eef, 0x7224),1359# evdev_name_suffix=' Touchscreen')1360#1361#1362# class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):1363# def create_device(self):1364# return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',1365# rdesc='05 0d 09 04 a1 01 85 04 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 15 00 25 01 81 02 09 51 75 05 95 01 16 00 00 26 10 00 81 02 09 47 75 01 95 01 15 00 25 01 81 02 05 01 09 30 75 10 95 01 55 0d 65 33 35 00 46 72 22 26 ff 7f 81 02 09 31 75 10 95 01 55 0d 65 33 35 00 46 87 13 26 ff 7f 81 02 05 0d 09 55 25 08 75 08 95 01 b1 02 c0 c0 05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 01 75 06 81 01 05 01 09 30 09 31 16 00 00 26 ff 0f 36 00 00 46 ff 0f 66 00 00 75 10 95 02 81 02 c0 c0 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 85 03 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 20 a1 00 09 42 09 32 15 00 25 01 95 02 75 01 81 02 95 06 75 01 81 03 05 01 09 30 75 10 95 01 a4 55 0d 65 33 36 00 00 46 72 22 16 00 00 26 ff 0f 81 02 09 31 16 00 00 26 ff 0f 36 00 00 46 87 13 81 02 b4 c0 c0 05 0d 09 0e a1 01 85 05 09 22 a1 00 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0',1366# input_info=(BusType.USB, 0x0eef, 0x72fa),1367# evdev_name_suffix=' Touchscreen')1368#1369#1370# class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):1371# def create_device(self):1372# return PenDigitizer('uhid test egalax-capacitive_0eef_7336',1373# rdesc='05 0d 09 04 a1 01 85 04 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 15 00 25 01 81 02 09 51 75 05 95 01 16 00 00 26 10 00 81 02 09 47 75 01 95 01 15 00 25 01 81 02 05 01 09 30 75 10 95 01 55 0d 65 33 35 00 46 c1 20 26 ff 7f 81 02 09 31 75 10 95 01 55 0d 65 33 35 00 46 c2 18 26 ff 7f 81 02 05 0d 09 55 25 08 75 08 95 01 b1 02 c0 c0 05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 01 75 06 81 01 05 01 09 30 09 31 16 00 00 26 ff 0f 36 00 00 46 ff 0f 66 00 00 75 10 95 02 81 02 c0 c0 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 85 03 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 20 a1 00 09 42 09 32 15 00 25 01 95 02 75 01 81 02 95 06 75 01 81 03 05 01 09 30 75 10 95 01 a4 55 0d 65 33 36 00 00 46 c1 20 16 00 00 26 ff 0f 81 02 09 31 16 00 00 26 ff 0f 36 00 00 46 c2 18 81 02 b4 c0 c0 05 0d 09 0e a1 01 85 05 09 22 a1 00 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0',1374# input_info=(BusType.USB, 0x0eef, 0x7336),1375# evdev_name_suffix=' Touchscreen')1376#1377#1378# class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):1379# def create_device(self):1380# return PenDigitizer('uhid test egalax-capacitive_0eef_7337',1381# rdesc='05 0d 09 04 a1 01 85 04 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 15 00 25 01 81 02 09 51 75 05 95 01 16 00 00 26 10 00 81 02 09 47 75 01 95 01 15 00 25 01 81 02 05 01 09 30 75 10 95 01 55 0d 65 33 35 00 46 ae 17 26 ff 7f 81 02 09 31 75 10 95 01 55 0d 65 33 35 00 46 c3 0e 26 ff 7f 81 02 05 0d 09 55 25 08 75 08 95 01 b1 02 c0 c0 05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 01 75 06 81 01 05 01 09 30 09 31 16 00 00 26 ff 0f 36 00 00 46 ff 0f 66 00 00 75 10 95 02 81 02 c0 c0 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 85 03 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 20 a1 00 09 42 09 32 15 00 25 01 95 02 75 01 81 02 95 06 75 01 81 03 05 01 09 30 75 10 95 01 a4 55 0d 65 33 36 00 00 46 ae 17 16 00 00 26 ff 0f 81 02 09 31 16 00 00 26 ff 0f 36 00 00 46 c3 0e 81 02 b4 c0 c0 05 0d 09 0e a1 01 85 05 09 22 a1 00 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0',1382# input_info=(BusType.USB, 0x0eef, 0x7337),1383# evdev_name_suffix=' Touchscreen')1384#1385#1386# class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):1387# def create_device(self):1388# return PenDigitizer('uhid test egalax-capacitive_0eef_7349',1389# rdesc='05 0d 09 04 a1 01 85 04 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 15 00 25 01 81 02 09 51 75 05 95 01 16 00 00 26 10 00 81 02 09 47 75 01 95 01 15 00 25 01 81 02 05 01 09 30 75 10 95 01 55 0d 65 33 35 00 46 34 49 26 ff 7f 81 02 09 31 75 10 95 01 55 0d 65 33 35 00 46 37 29 26 ff 7f 81 02 05 0d 09 55 25 08 75 08 95 01 b1 02 c0 c0 05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 01 75 06 81 01 05 01 09 30 09 31 16 00 00 26 ff 0f 36 00 00 46 ff 0f 66 00 00 75 10 95 02 81 02 c0 c0 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 85 03 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 20 a1 00 09 42 09 32 15 00 25 01 95 02 75 01 81 02 95 06 75 01 81 03 05 01 09 30 75 10 95 01 a4 55 0d 65 33 36 00 00 46 34 49 16 00 00 26 ff 0f 81 02 09 31 16 00 00 26 ff 0f 36 00 00 46 37 29 81 02 b4 c0 c0 05 0d 09 0e a1 01 85 05 09 22 a1 00 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0',1390# input_info=(BusType.USB, 0x0eef, 0x7349),1391# evdev_name_suffix=' Touchscreen')1392#1393#1394# class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):1395# def create_device(self):1396# return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',1397# rdesc='05 0d 09 04 a1 01 85 04 09 22 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 09 32 15 00 25 01 81 02 09 51 75 05 95 01 16 00 00 26 10 00 81 02 09 47 75 01 95 01 15 00 25 01 81 02 05 01 09 30 75 10 95 01 55 0d 65 33 35 00 46 96 4e 26 ff 7f 81 02 09 31 75 10 95 01 55 0d 65 33 35 00 46 23 2c 26 ff 7f 81 02 05 0d 09 55 25 08 75 08 95 01 b1 02 c0 c0 05 01 09 01 a1 01 85 01 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 01 75 06 81 01 05 01 09 30 09 31 16 00 00 26 ff 0f 36 00 00 46 ff 0f 66 00 00 75 10 95 02 81 02 c0 c0 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 85 03 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0 05 0d 09 04 a1 01 85 02 09 20 a1 00 09 42 09 32 15 00 25 01 95 02 75 01 81 02 95 06 75 01 81 03 05 01 09 30 75 10 95 01 a4 55 0d 65 33 36 00 00 46 96 4e 16 00 00 26 ff 0f 81 02 09 31 16 00 00 26 ff 0f 36 00 00 46 23 2c 81 02 b4 c0 c0 05 0d 09 0e a1 01 85 05 09 22 a1 00 09 52 09 53 15 00 25 0a 75 08 95 02 b1 02 c0 c0',1398# input_info=(BusType.USB, 0x0eef, 0x73f4),1399# evdev_name_suffix=' Touchscreen')1400#1401# bogus: BTN_TOOL_PEN is not emitted1402# class TestIrtouch_6615_0070(BaseTest.TestTablet):1403# def create_device(self):1404# return PenDigitizer('uhid test irtouch_6615_0070',1405# rdesc='05 01 09 02 a1 01 85 10 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 95 02 75 01 81 02 95 06 81 03 05 01 09 30 09 31 15 00 26 ff 7f 75 10 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 30 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 09 30 26 ff 7f 55 0f 65 11 35 00 46 51 02 75 10 95 01 81 02 09 31 35 00 46 73 01 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 09 51 75 08 95 01 81 02 05 01 09 30 26 ff 7f 55 0f 65 11 35 00 46 51 02 75 10 95 01 81 02 09 31 35 00 46 73 01 81 02 c0 05 0d 09 54 15 00 26 02 00 75 08 95 01 81 02 85 03 09 55 15 00 26 ff 00 75 08 95 01 b1 02 c0 05 0d 09 0e a1 01 85 02 09 52 09 53 15 00 26 ff 00 75 08 95 02 b1 02 c0 05 0d 09 02 a1 01 85 20 09 20 a1 00 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 03 05 01 09 30 26 ff 7f 55 0f 65 11 35 00 46 51 02 75 10 95 01 81 02 09 31 35 00 46 73 01 81 02 85 01 06 00 ff 09 01 75 08 95 01 b1 02 c0 c0',1406# input_info=(BusType.USB, 0x6615, 0x0070))140714081409class TestNexio_1870_0100(BaseTest.TestTablet):1410def create_device(self):1411return PenDigitizer(1412"uhid test nexio_1870_0100",1413rdesc="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 3f 75 10 55 0e 65 11 09 30 35 00 46 1e 19 81 02 26 ff 3f 09 31 35 00 46 be 0f 81 02 26 ff 3f 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 3f 75 10 55 0e 65 11 09 30 35 00 46 1e 19 81 02 26 ff 3f 09 31 35 00 46 be 0f 81 02 26 ff 3f c0 05 0d 09 54 95 01 75 08 25 02 81 02 85 02 09 55 25 02 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 05 01 09 02 a1 01 09 01 a1 00 85 04 05 09 95 03 75 01 19 01 29 03 15 00 25 01 81 02 95 01 75 05 81 01 05 01 75 10 95 02 09 30 09 31 15 00 26 ff 7f 81 02 c0 c0 05 0d 09 02 a1 01 85 05 09 20 a1 00 09 42 09 32 15 00 25 01 75 01 95 02 81 02 95 0e 81 03 05 01 26 ff 3f 75 10 95 01 55 0e 65 11 09 30 35 00 46 1e 19 81 02 26 ff 3f 09 31 35 00 46 be 0f 81 02 26 ff 3f c0 c0 06 00 ff 09 01 a1 01 85 06 19 01 29 40 15 00 26 ff 00 75 08 95 40 81 00 19 01 29 40 91 00 c0",1414input_info=(BusType.USB, 0x1870, 0x0100),1415)141614171418class TestNexio_1870_010d(BaseTest.TestTablet):1419def create_device(self):1420return PenDigitizer(1421"uhid test nexio_1870_010d",1422rdesc="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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 81 02 c0 05 0d 09 54 95 01 75 08 25 02 81 02 85 02 09 55 25 06 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 05 01 09 02 a1 01 09 01 a1 00 85 04 05 09 95 03 75 01 19 01 29 03 15 00 25 01 81 02 95 01 75 05 81 01 05 01 75 10 95 02 09 30 09 31 15 00 26 ff 7f 81 02 c0 c0 05 0d 09 02 a1 01 85 05 09 20 a1 00 09 42 09 32 15 00 25 01 75 01 95 02 81 02 95 0e 81 03 05 01 26 ff 3f 75 10 95 01 55 0e 65 11 09 30 35 00 46 1e 19 81 02 26 ff 3f 09 31 35 00 46 be 0f 81 02 26 ff 3f c0 c0 06 00 ff 09 01 a1 01 85 06 19 01 29 40 15 00 26 ff 00 75 08 95 3e 81 00 19 01 29 40 91 00 c0",1423input_info=(BusType.USB, 0x1870, 0x010D),1424)142514261427class TestNexio_1870_0119(BaseTest.TestTablet):1428def create_device(self):1429return PenDigitizer(1430"uhid test nexio_1870_0119",1431rdesc="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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 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 3f 75 10 55 0d 65 00 09 30 35 00 46 00 00 81 02 26 ff 3f 09 31 35 00 46 00 00 81 02 26 ff 3f 05 0d 09 48 35 00 26 ff 3f 81 02 09 49 35 00 26 ff 3f 81 02 c0 05 0d 09 54 95 01 75 08 25 02 81 02 85 02 09 55 25 06 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 05 01 09 02 a1 01 09 01 a1 00 85 04 05 09 95 03 75 01 19 01 29 03 15 00 25 01 81 02 95 01 75 05 81 01 05 01 75 10 95 02 09 30 09 31 15 00 26 ff 7f 81 02 c0 c0 05 0d 09 02 a1 01 85 05 09 20 a1 00 09 42 09 32 15 00 25 01 75 01 95 02 81 02 95 0e 81 03 05 01 26 ff 3f 75 10 95 01 55 0e 65 11 09 30 35 00 46 1e 19 81 02 26 ff 3f 09 31 35 00 46 be 0f 81 02 26 ff 3f c0 c0 06 00 ff 09 01 a1 01 85 06 19 01 29 40 15 00 26 ff 00 75 08 95 3e 81 00 19 01 29 40 91 00 c0",1432input_info=(BusType.USB, 0x1870, 0x0119),1433)143414351436################################################################################1437#1438# Windows 8 compatible devices1439#1440################################################################################14411442# bogus: application is 'undefined'1443# class Testatmel_03eb_8409(BaseTest.TestTablet):1444# def create_device(self):1445# return PenDigitizer('uhid test atmel_03eb_8409', 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 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 02 46 c8 0a 26 6f 08 09 30 81 02 35 00 35 00 46 18 06 26 77 0f 09 31 81 02 35 00 35 00 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 48 81 02 09 49 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 02 46 c8 0a 26 6f 08 09 30 81 02 35 00 35 00 46 18 06 26 77 0f 09 31 81 02 35 00 35 00 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 48 81 02 09 49 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 02 46 c8 0a 26 6f 08 09 30 81 02 35 00 35 00 46 18 06 26 77 0f 09 31 81 02 35 00 35 00 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 48 81 02 09 49 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 02 46 c8 0a 26 6f 08 09 30 81 02 35 00 35 00 46 18 06 26 77 0f 09 31 81 02 35 00 35 00 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 48 81 02 09 49 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 02 46 c8 0a 26 6f 08 09 30 81 02 35 00 35 00 46 18 06 26 77 0f 09 31 81 02 35 00 35 00 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 48 81 02 09 49 81 02 c0 05 0d 27 ff ff 00 00 75 10 95 01 09 56 81 02 15 00 25 1f 75 05 09 54 95 01 81 02 75 03 25 01 95 01 81 03 75 08 85 02 09 55 25 10 b1 02 06 00 ff 85 05 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 00 a1 01 85 03 09 20 a1 00 15 00 25 01 75 01 95 01 09 42 81 02 09 44 81 02 09 45 81 02 81 03 09 32 81 02 95 03 81 03 05 01 55 0e 65 11 35 00 75 10 95 02 46 c8 0a 26 6f 08 09 30 81 02 46 18 06 26 77 0f 09 31 81 02 05 0d 09 30 15 01 26 ff 00 75 08 95 01 81 02 c0 c0')144614471448class Testatmel_03eb_840b(BaseTest.TestTablet):1449def create_device(self):1450return PenDigitizer(1451"uhid test atmel_03eb_840b",1452rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 01 46 00 0a 26 ff 0f 09 30 81 02 09 00 81 03 46 a0 05 26 ff 0f 09 31 81 02 09 00 81 03 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 00 81 03 09 00 81 03 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 01 46 00 0a 26 ff 0f 09 30 81 02 09 00 81 03 46 a0 05 26 ff 0f 09 31 81 02 09 00 81 03 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 00 81 03 09 00 81 03 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 01 46 00 0a 26 ff 0f 09 30 81 02 09 00 81 03 46 a0 05 26 ff 0f 09 31 81 02 09 00 81 03 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 00 81 03 09 00 81 03 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 01 46 00 0a 26 ff 0f 09 30 81 02 09 00 81 03 46 a0 05 26 ff 0f 09 31 81 02 09 00 81 03 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 00 81 03 09 00 81 03 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 95 01 81 03 25 1f 75 05 09 51 81 02 05 01 55 0e 65 11 35 00 75 10 95 01 46 00 0a 26 ff 0f 09 30 81 02 09 00 81 03 46 a0 05 26 ff 0f 09 31 81 02 09 00 81 03 05 0d 95 01 75 08 15 00 26 ff 00 46 ff 00 09 00 81 03 09 00 81 03 c0 05 0d 27 ff ff 00 00 75 10 95 01 09 56 81 02 15 00 25 1f 75 05 09 54 95 01 81 02 75 03 25 01 95 01 81 03 75 08 85 02 09 55 25 10 b1 02 06 00 ff 85 05 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 02 a1 01 85 03 09 20 a1 00 15 00 25 01 75 01 95 01 09 42 81 02 09 44 81 02 09 45 81 02 81 03 09 32 81 02 95 03 81 03 05 01 55 0e 65 11 35 00 75 10 95 02 46 00 0a 26 ff 0f 09 30 81 02 46 a0 05 26 ff 0f 09 31 81 02 05 0d 09 30 15 01 26 ff 00 75 08 95 01 81 02 c0 c0",1453)145414551456class Testn_trig_1b96_0c01(BaseTest.TestTablet):1457def create_device(self):1458return PenDigitizer(1459"uhid test n_trig_1b96_0c01",1460rdesc="75 08 15 00 26 ff 00 06 0b ff 09 0b a1 01 95 0f 09 29 85 29 b1 02 95 1f 09 2a 85 2a b1 02 95 3e 09 2b 85 2b b1 02 95 fe 09 2c 85 2c b1 02 96 fe 01 09 2d 85 2d b1 02 95 02 09 48 85 48 b1 02 95 0f 09 2e 85 2e 81 02 95 1f 09 2f 85 2f 81 02 95 3e 09 30 85 30 81 02 95 fe 09 31 85 31 81 02 96 fe 01 09 32 85 32 81 02 75 08 96 fe 0f 09 35 85 35 81 02 c0 05 0d 09 02 a1 01 85 01 09 20 35 00 a1 00 09 32 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 05 81 02 95 03 81 03 05 01 09 30 75 10 95 01 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 b4 05 0d 09 30 26 00 01 81 02 06 00 ff 09 01 81 02 c0 85 0c 06 00 ff 09 0c 75 08 95 06 26 ff 00 b1 02 85 0b 09 0b 95 02 b1 02 85 11 09 11 b1 02 85 15 09 15 95 05 b1 02 85 18 09 18 95 0c b1 02 c0 05 0d 09 04 a1 01 85 03 06 00 ff 09 01 75 10 95 01 15 00 27 ff ff 00 00 81 02 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 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 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 54 95 01 75 08 81 02 09 56 75 20 95 01 27 ff ff ff 0f 81 02 85 04 09 55 75 08 95 01 25 0b b1 02 85 0a 06 00 ff 09 03 15 00 b1 02 85 1b 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 03 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0",1461)146214631464class Testn_trig_1b96_0c03(BaseTest.TestTablet):1465def create_device(self):1466return PenDigitizer(1467"uhid test n_trig_1b96_0c03",1468rdesc="75 08 15 00 26 ff 00 06 0b ff 09 0b a1 01 95 0f 09 29 85 29 b1 02 95 1f 09 2a 85 2a b1 02 95 3e 09 2b 85 2b b1 02 95 fe 09 2c 85 2c b1 02 96 fe 01 09 2d 85 2d b1 02 95 02 09 48 85 48 b1 02 95 0f 09 2e 85 2e 81 02 95 1f 09 2f 85 2f 81 02 95 3e 09 30 85 30 81 02 95 fe 09 31 85 31 81 02 96 fe 01 09 32 85 32 81 02 75 08 96 fe 0f 09 35 85 35 81 02 c0 05 0d 09 02 a1 01 85 01 09 20 35 00 a1 00 09 32 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 05 81 02 95 03 81 03 05 01 09 30 75 10 95 01 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 b4 05 0d 09 30 26 00 01 81 02 06 00 ff 09 01 81 02 c0 85 0c 06 00 ff 09 0c 75 08 95 06 26 ff 00 b1 02 85 0b 09 0b 95 02 b1 02 85 11 09 11 b1 02 85 15 09 15 95 05 b1 02 85 18 09 18 95 0c b1 02 c0 05 0d 09 04 a1 01 85 03 06 00 ff 09 01 75 10 95 01 15 00 27 ff ff 00 00 81 02 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 15 0a 26 80 25 81 02 09 31 46 b4 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 54 95 01 75 08 81 02 09 56 75 20 95 01 27 ff ff ff 0f 81 02 85 04 09 55 75 08 95 01 25 0b b1 02 85 0a 06 00 ff 09 03 15 00 b1 02 85 1b 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 03 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0",1469)147014711472class Testn_trig_1b96_0f00(BaseTest.TestTablet):1473def create_device(self):1474return PenDigitizer(1475"uhid test n_trig_1b96_0f00",1476rdesc="75 08 15 00 26 ff 00 06 0b ff 09 0b a1 01 95 0f 09 29 85 29 b1 02 95 1f 09 2a 85 2a b1 02 95 3e 09 2b 85 2b b1 02 95 fe 09 2c 85 2c b1 02 96 fe 01 09 2d 85 2d b1 02 95 02 09 48 85 48 b1 02 95 0f 09 2e 85 2e 81 02 95 1f 09 2f 85 2f 81 02 95 3e 09 30 85 30 81 02 95 fe 09 31 85 31 81 02 96 fe 01 09 32 85 32 81 02 75 08 96 fe 0f 09 35 85 35 81 02 c0 05 0d 09 02 a1 01 85 01 09 20 35 00 a1 00 09 32 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 05 81 02 95 03 81 03 05 01 09 30 75 10 95 01 a4 55 0e 65 11 46 03 0a 26 80 25 81 02 09 31 46 a1 05 26 20 1c 81 02 b4 05 0d 09 30 26 00 01 81 02 06 00 ff 09 01 81 02 c0 85 0c 06 00 ff 09 0c 75 08 95 06 26 ff 00 b1 02 85 0b 09 0b 95 02 b1 02 85 11 09 11 b1 02 85 15 09 15 95 05 b1 02 85 18 09 18 95 0c b1 02 c0 05 0d 09 04 a1 01 85 03 06 00 ff 09 01 75 10 95 01 15 00 27 ff ff 00 00 81 02 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 03 0a 26 80 25 81 02 09 31 46 a1 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 03 0a 26 80 25 81 02 09 31 46 a1 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 54 95 01 75 08 81 02 09 56 75 20 95 01 27 ff ff ff 0f 81 02 85 04 09 55 75 08 95 01 25 0b b1 02 85 0a 06 00 ff 09 03 15 00 b1 02 85 1b 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 03 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0",1477)147814791480class Testn_trig_1b96_0f04(BaseTest.TestTablet):1481def create_device(self):1482return PenDigitizer(1483"uhid test n_trig_1b96_0f04",1484rdesc="75 08 15 00 26 ff 00 06 0b ff 09 0b a1 01 95 0f 09 29 85 29 b1 02 95 1f 09 2a 85 2a b1 02 95 3e 09 2b 85 2b b1 02 95 fe 09 2c 85 2c b1 02 96 fe 01 09 2d 85 2d b1 02 95 02 09 48 85 48 b1 02 95 0f 09 2e 85 2e 81 02 95 1f 09 2f 85 2f 81 02 95 3e 09 30 85 30 81 02 95 fe 09 31 85 31 81 02 96 fe 01 09 32 85 32 81 02 75 08 96 fe 0f 09 35 85 35 81 02 c0 05 0d 09 02 a1 01 85 01 09 20 35 00 a1 00 09 32 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 05 81 02 95 03 81 03 05 01 09 30 75 10 95 01 a4 55 0e 65 11 46 7f 0b 26 80 25 81 02 09 31 46 78 06 26 20 1c 81 02 b4 05 0d 09 30 26 00 01 81 02 06 00 ff 09 01 81 02 c0 85 0c 06 00 ff 09 0c 75 08 95 06 26 ff 00 b1 02 85 0b 09 0b 95 02 b1 02 85 11 09 11 b1 02 85 15 09 15 95 05 b1 02 85 18 09 18 95 0c b1 02 c0 05 0d 09 04 a1 01 85 03 06 00 ff 09 01 75 10 95 01 15 00 27 ff ff 00 00 81 02 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 7f 0b 26 80 25 81 02 09 31 46 78 06 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 7f 0b 26 80 25 81 02 09 31 46 78 06 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 54 95 01 75 08 81 02 09 56 75 20 95 01 27 ff ff ff 0f 81 02 85 04 09 55 75 08 95 01 25 0b b1 02 85 0a 06 00 ff 09 03 15 00 b1 02 85 1b 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 03 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0",1485)148614871488class Testn_trig_1b96_1000(BaseTest.TestTablet):1489def create_device(self):1490return PenDigitizer(1491"uhid test n_trig_1b96_1000",1492rdesc="75 08 15 00 26 ff 00 06 0b ff 09 0b a1 01 95 0f 09 29 85 29 b1 02 95 1f 09 2a 85 2a b1 02 95 3e 09 2b 85 2b b1 02 95 fe 09 2c 85 2c b1 02 96 fe 01 09 2d 85 2d b1 02 95 02 09 48 85 48 b1 02 95 0f 09 2e 85 2e 81 02 95 1f 09 2f 85 2f 81 02 95 3e 09 30 85 30 81 02 95 fe 09 31 85 31 81 02 96 fe 01 09 32 85 32 81 02 75 08 96 fe 0f 09 35 85 35 81 02 c0 05 0d 09 02 a1 01 85 01 09 20 35 00 a1 00 09 32 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 05 81 02 95 03 81 03 05 01 09 30 75 10 95 01 a4 55 0e 65 11 46 03 0a 26 80 25 81 02 09 31 46 a1 05 26 20 1c 81 02 b4 05 0d 09 30 26 00 01 81 02 06 00 ff 09 01 81 02 c0 85 0c 06 00 ff 09 0c 75 08 95 06 26 ff 00 b1 02 85 0b 09 0b 95 02 b1 02 85 11 09 11 b1 02 85 15 09 15 95 05 b1 02 85 18 09 18 95 0c b1 02 c0 05 0d 09 04 a1 01 85 03 06 00 ff 09 01 75 10 95 01 15 00 27 ff ff 00 00 81 02 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 03 0a 26 80 25 81 02 09 31 46 a1 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 01 81 03 09 47 81 02 95 05 81 03 75 10 09 51 27 ff ff 00 00 95 01 81 02 05 01 09 30 75 10 95 02 a4 55 0e 65 11 46 03 0a 26 80 25 81 02 09 31 46 a1 05 26 20 1c 81 02 05 0d 09 48 95 01 26 80 25 81 02 09 49 26 20 1c 81 02 b4 06 00 ff 09 02 75 08 95 04 15 00 26 ff 00 81 02 c0 05 0d 09 54 95 01 75 08 81 02 09 56 75 20 95 01 27 ff ff ff 0f 81 02 85 04 09 55 75 08 95 01 25 0b b1 02 85 0a 06 00 ff 09 03 15 00 b1 02 85 1b 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 03 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0",1493)149414951496class TestGXTP_27c6_0113(BaseTest.TestTablet):1497def create_device(self):1498return GXTP_pen(1499"uhid test GXTP_27c6_0113",1500rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 55 0e 65 11 35 00 15 00 09 42 25 01 75 01 95 01 81 02 95 07 81 01 95 01 75 08 09 51 81 02 75 10 05 01 26 00 14 46 1f 07 09 30 81 02 26 80 0c 46 77 04 09 31 81 02 05 0d c0 09 22 a1 02 09 42 25 01 75 01 95 01 81 02 95 07 81 01 95 01 75 08 09 51 81 02 75 10 05 01 26 00 14 46 1f 07 09 30 81 02 26 80 0c 46 77 04 09 31 81 02 05 0d c0 09 22 a1 02 09 42 25 01 75 01 95 01 81 02 95 07 81 01 95 01 75 08 09 51 81 02 75 10 05 01 26 00 14 46 1f 07 09 30 81 02 26 80 0c 46 77 04 09 31 81 02 05 0d c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 14 75 10 55 0e 65 11 09 30 35 00 46 1f 07 81 02 26 80 0c 46 77 04 09 31 81 02 05 0d c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 14 75 10 55 0e 65 11 09 30 35 00 46 1f 07 81 02 26 80 0c 46 77 04 09 31 81 02 05 0d c0 09 54 15 00 25 7f 75 08 95 01 81 02 85 02 09 55 95 01 25 0a b1 02 85 03 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 02 a1 01 85 08 09 20 a1 00 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 04 81 02 95 01 81 03 09 32 81 02 95 02 81 03 95 01 75 08 09 51 81 02 05 01 09 30 75 10 95 01 a4 55 0e 65 11 35 00 26 00 14 46 1f 07 81 42 09 31 26 80 0c 46 77 04 81 42 b4 05 0d 09 30 26 ff 0f 81 02 09 3d 65 14 55 0e 36 d8 dc 46 28 23 16 d8 dc 26 28 23 81 02 09 3e 81 02 c0 c0 06 f0 ff 09 01 a1 01 85 0e 09 01 15 00 25 ff 75 08 95 40 91 02 09 01 15 00 25 ff 75 08 95 40 81 02 c0 05 01 09 06 a1 01 85 04 05 07 09 e3 15 00 25 01 75 01 95 01 81 02 95 07 81 03 c0",1501)150215031504################################################################################1505#1506# Windows 8 compatible devices with USI Pen1507#1508################################################################################150915101511class TestElan_04f3_2A49(BaseTest.TestTablet):1512def create_device(self):1513return USIPen(1514"uhid test Elan_04f3_2A49",1515rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 75 01 81 03 75 06 09 51 25 3f 81 02 26 ff 00 75 08 55 0f 65 11 35 00 45 ff 09 48 81 02 09 49 81 02 09 30 81 02 95 01 05 01 a4 26 cf 0f 75 10 55 0f 65 11 09 30 35 00 46 26 01 95 01 81 02 26 77 0a 46 a6 00 09 31 81 02 b4 c0 05 0d 09 22 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 75 01 81 03 75 06 09 51 25 3f 81 02 26 ff 00 75 08 55 0f 65 11 35 00 45 ff 09 48 81 02 09 49 81 02 09 30 81 02 95 01 05 01 a4 26 cf 0f 75 10 55 0f 65 11 09 30 35 00 46 26 01 95 01 81 02 26 77 0a 46 a6 00 09 31 81 02 b4 c0 05 0d 09 22 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 75 01 81 03 75 06 09 51 25 3f 81 02 26 ff 00 75 08 55 0f 65 11 35 00 45 ff 09 48 81 02 09 49 81 02 09 30 81 02 95 01 05 01 a4 26 cf 0f 75 10 55 0f 65 11 09 30 35 00 46 26 01 95 01 81 02 26 77 0a 46 a6 00 09 31 81 02 b4 c0 05 0d 09 22 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 75 01 81 03 75 06 09 51 25 3f 81 02 26 ff 00 75 08 55 0f 65 11 35 00 45 ff 09 48 81 02 09 49 81 02 09 30 81 02 95 01 05 01 a4 26 cf 0f 75 10 55 0f 65 11 09 30 35 00 46 26 01 95 01 81 02 26 77 0a 46 a6 00 09 31 81 02 b4 c0 05 0d 09 22 a1 02 05 0d 09 42 15 00 25 01 75 01 95 01 81 02 75 01 81 03 75 06 09 51 25 3f 81 02 26 ff 00 75 08 55 0f 65 11 35 00 45 ff 09 48 81 02 09 49 81 02 09 30 81 02 95 01 05 01 a4 26 cf 0f 75 10 55 0f 65 11 09 30 35 00 46 26 01 95 01 81 02 26 77 0a 46 a6 00 09 31 81 02 b4 c0 05 0d 09 54 25 7f 96 01 00 75 08 81 02 85 0a 09 55 25 0a b1 02 85 44 06 00 ff 09 c5 16 00 00 26 ff 00 75 08 96 00 01 b1 02 c0 06 ff 01 09 01 a1 01 85 02 16 00 00 26 ff 00 75 08 95 40 09 00 81 02 c0 06 00 ff 09 01 a1 01 85 03 75 08 95 20 09 01 91 02 c0 06 00 ff 09 01 a1 01 85 06 09 03 75 08 95 12 91 02 09 04 75 08 95 03 b1 02 c0 06 01 ff 09 01 a1 01 85 04 15 00 26 ff 00 75 08 95 13 09 00 81 02 c0 05 0d 09 02 a1 01 85 07 35 00 09 20 a1 00 09 32 09 42 09 44 09 3c 09 45 15 00 25 01 75 01 95 05 81 02 95 03 81 03 05 01 09 30 75 10 95 01 a4 55 0f 65 11 46 26 01 26 1c 48 81 42 09 31 46 a6 00 26 bc 2f 81 42 b4 05 0d 09 30 26 00 10 81 02 75 08 95 01 09 3b 25 64 81 42 09 38 15 00 25 02 81 02 09 5c 26 ff 00 81 02 09 5e 81 02 09 70 a1 02 15 01 25 06 09 72 09 73 09 74 09 75 09 76 09 77 81 20 09 5b 25 ff 75 40 81 02 c0 06 00 ff 75 08 95 02 09 01 81 02 c0 05 0d 85 60 09 81 a1 02 09 38 75 08 95 01 15 00 25 02 81 02 09 81 15 01 25 04 09 82 09 83 09 84 09 85 81 20 c0 85 61 09 5c a1 02 15 00 26 ff 00 75 08 95 01 09 38 b1 02 09 5c 26 ff 00 b1 02 09 5d 75 01 95 01 25 01 b1 02 95 07 b1 03 c0 85 62 09 5e a1 02 09 38 15 00 25 02 75 08 95 01 b1 02 09 5e 26 ff 00 b1 02 09 5f 75 01 25 01 b1 02 75 07 b1 03 c0 85 63 09 70 a1 02 75 08 95 01 15 00 25 02 09 38 b1 02 09 70 a1 02 25 06 09 72 09 73 09 74 09 75 09 76 09 77 b1 20 c0 09 71 75 01 25 01 b1 02 75 07 b1 03 c0 85 64 09 80 15 00 25 ff 75 40 95 01 b1 02 85 65 09 44 a1 02 09 38 75 08 95 01 25 02 b1 02 15 01 25 03 09 44 a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 09 5a a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 09 45 a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 c0 85 66 75 08 95 01 05 0d 09 90 a1 02 09 38 25 02 b1 02 09 91 75 10 26 ff 0f b1 02 09 92 75 40 25 ff b1 02 05 06 09 2a 75 08 26 ff 00 a1 02 09 2d b1 02 09 2e b1 02 c0 c0 85 67 05 06 09 2b a1 02 05 0d 25 02 09 38 b1 02 05 06 09 2b a1 02 09 2d 26 ff 00 b1 02 09 2e b1 02 c0 c0 85 68 06 00 ff 09 01 a1 02 05 0d 09 38 75 08 95 01 25 02 b1 02 06 00 ff 09 01 75 10 27 ff ff 00 00 b1 02 c0 85 69 05 0d 09 38 75 08 95 01 15 00 25 02 b1 02 c0 06 00 ff 09 81 a1 01 85 17 75 08 95 1f 09 05 81 02 c0",1516input_info=(BusType.I2C, 0x04F3, 0x2A49),1517)151815191520class TestGoodix_27c6_0e00(BaseTest.TestTablet):1521def create_device(self):1522return USIPen(1523"uhid test Elan_04f3_2A49",1524rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 55 0e 65 11 35 00 15 00 09 42 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 95 01 75 08 09 51 81 02 75 10 05 01 26 04 20 46 e6 09 09 30 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 95 01 75 08 09 51 81 02 75 10 05 01 26 04 20 46 e6 09 09 30 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 95 01 75 08 09 51 81 02 75 10 05 01 26 04 20 46 e6 09 09 30 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 75 08 09 51 95 01 81 02 05 01 26 04 20 75 10 55 0e 65 11 09 30 35 00 46 e6 09 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 75 08 09 51 95 01 81 02 05 01 26 04 20 75 10 55 0e 65 11 09 30 35 00 46 e6 09 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 54 15 00 25 7f 75 08 95 01 81 02 85 02 09 55 95 01 25 0a b1 02 85 03 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 02 a1 01 09 20 a1 00 85 08 05 01 a4 09 30 35 00 46 e6 09 15 00 26 04 20 55 0d 65 13 75 10 95 01 81 02 09 31 46 9a 06 26 60 15 81 02 b4 05 0d 09 38 95 01 75 08 15 00 25 01 81 02 09 30 75 10 26 ff 0f 81 02 09 31 81 02 09 42 09 44 09 5a 09 3c 09 45 09 32 75 01 95 06 25 01 81 02 95 02 81 03 09 3d 55 0e 65 14 36 d8 dc 46 28 23 16 d8 dc 26 28 23 95 01 75 10 81 02 09 3e 81 02 09 41 15 00 27 a0 8c 00 00 35 00 47 a0 8c 00 00 81 02 05 20 0a 53 04 65 00 16 01 f8 26 ff 07 75 10 95 01 81 02 0a 54 04 81 02 0a 55 04 81 02 0a 57 04 81 02 0a 58 04 81 02 0a 59 04 81 02 0a 72 04 81 02 0a 73 04 81 02 0a 74 04 81 02 05 0d 09 3b 15 00 25 64 75 08 81 02 09 5b 25 ff 75 40 81 02 06 00 ff 09 5b 75 20 81 02 05 0d 09 5c 26 ff 00 75 08 81 02 09 5e 81 02 09 70 a1 02 15 01 25 06 09 72 09 73 09 74 09 75 09 76 09 77 81 20 c0 06 00 ff 09 01 15 00 27 ff ff 00 00 75 10 95 01 81 02 85 09 09 81 a1 02 09 81 15 01 25 04 09 82 09 83 09 84 09 85 81 20 c0 85 10 09 5c a1 02 15 00 25 01 75 08 95 01 09 38 b1 02 09 5c 26 ff 00 b1 02 09 5d 75 01 95 01 25 01 b1 02 95 07 b1 03 c0 85 11 09 5e a1 02 09 38 15 00 25 01 75 08 95 01 b1 02 09 5e 26 ff 00 b1 02 09 5f 75 01 25 01 b1 02 75 07 b1 03 c0 85 12 09 70 a1 02 75 08 95 01 15 00 25 01 09 38 b1 02 09 70 a1 02 25 06 09 72 09 73 09 74 09 75 09 76 09 77 b1 20 c0 09 71 75 01 25 01 b1 02 75 07 b1 03 c0 85 13 09 80 15 00 25 ff 75 40 95 01 b1 02 85 14 09 44 a1 02 09 38 75 08 95 01 25 01 b1 02 15 01 25 03 09 44 a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 09 5a a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 09 45 a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 c0 85 15 75 08 95 01 05 0d 09 90 a1 02 09 38 25 01 b1 02 09 91 75 10 26 ff 0f b1 02 09 92 75 40 25 ff b1 02 05 06 09 2a 75 08 26 ff 00 a1 02 09 2d b1 02 09 2e b1 02 c0 c0 85 16 05 06 09 2b a1 02 05 0d 25 01 09 38 b1 02 05 06 09 2b a1 02 09 2d 26 ff 00 b1 02 09 2e b1 02 c0 c0 85 17 06 00 ff 09 01 a1 02 05 0d 09 38 75 08 95 01 25 01 b1 02 06 00 ff 09 01 75 10 27 ff ff 00 00 b1 02 c0 85 18 05 0d 09 38 75 08 95 01 15 00 25 01 b1 02 c0 c0 06 f0 ff 09 01 a1 01 85 0e 09 01 15 00 25 ff 75 08 95 40 91 02 09 01 15 00 25 ff 75 08 95 40 81 02 c0",1525input_info=(BusType.I2C, 0x27C6, 0x0E00),1526)152715281529class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):1530hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]15311532def create_device(self):1533dev = XPPen_ArtistPro16Gen2_28bd_095b(1534"uhid test XPPen Artist Pro 16 Gen2 28bd 095b",1535rdesc="05 0d 09 02 a1 01 85 07 09 20 a1 00 09 42 09 44 09 45 09 3c 15 00 25 01 75 01 95 04 81 02 95 01 81 03 09 32 15 00 25 01 95 01 81 02 95 02 81 03 75 10 95 01 35 00 a4 05 01 09 30 65 13 55 0d 46 ff 34 26 ff 7f 81 02 09 31 46 20 21 26 ff 7f 81 02 b4 09 30 45 00 26 ff 3f 81 42 09 3d 15 81 25 7f 75 08 95 01 81 02 09 3e 15 81 25 7f 81 02 c0 c0",1536input_info=(BusType.USB, 0x28BD, 0x095B),1537)1538return dev153915401541class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):1542hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]15431544def create_device(self):1545return XPPen_Artist24_28bd_093a(1546"uhid test XPPen Artist 24 28bd 093a",1547rdesc="05 0d 09 02 a1 01 85 07 09 20 a1 00 09 42 09 44 09 45 15 00 25 01 75 01 95 03 81 02 95 02 81 03 09 32 95 01 81 02 95 02 81 03 75 10 95 01 35 00 a4 05 01 09 30 65 13 55 0d 46 f0 50 26 ff 7f 81 02 09 31 46 91 2d 26 ff 7f 81 02 b4 09 30 45 00 26 ff 1f 81 42 09 3d 15 81 25 7f 75 08 95 01 81 02 09 3e 15 81 25 7f 81 02 c0 c0",1548input_info=(BusType.USB, 0x28BD, 0x093A),1549)155015511552class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):1553hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]15541555def create_device(self):1556return Huion_Kamvas_Pro_19_256c_006b(1557"uhid test HUION Huion Tablet_GT1902",1558rdesc="05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0",1559input_info=(BusType.USB, 0x256C, 0x006B),1560)156115621563################################################################################1564#1565# Devices Reporting Distance1566#1567################################################################################156815691570class TestWacom_2d1f_014b(BaseTest.TestTablet):1571def create_device(self):1572return Wacom_2d1f_014b(1573"uhid test Wacom 2d1f_014b",1574rdesc="05 0d 09 02 a1 01 85 02 09 20 a1 00 09 42 09 44 09 45 09 3c 09 5a 09 32 15 00 25 01 75 01 95 06 81 02 95 02 81 03 05 01 09 30 26 88 3e 46 88 3e 65 11 55 0d 75 10 95 01 81 02 09 31 26 60 53 46 60 53 81 02 05 0d 09 30 26 ff 0f 45 00 65 00 55 00 81 02 06 00 ff 09 04 75 08 26 ff 00 46 ff 00 65 11 55 0e 81 02 05 0d 09 3d 75 10 16 d8 dc 26 28 23 36 d8 dc 46 28 23 65 14 81 02 09 3e 81 02 05 01 09 32 16 01 ff 25 00 36 01 ff 45 00 65 11 81 02 05 0d 09 56 15 00 27 ff ff 00 00 35 00 47 ff ff 00 00 66 01 10 55 0c 81 02 45 00 65 00 55 00 c0 09 00 75 08 26 ff 00 b1 12 85 03 09 00 95 12 b1 12 85 05 09 00 95 04 b1 02 85 06 09 00 95 24 b1 02 85 16 09 00 15 00 26 ff 00 95 06 b1 02 85 17 09 00 95 0c b1 02 85 19 09 00 95 01 b1 02 85 0a 09 00 75 08 95 01 15 10 26 ff 00 b1 02 85 1e 09 00 95 10 b1 02 c0 06 00 ff 09 00 a1 01 85 09 05 0d 09 20 a1 00 09 00 15 00 26 ff 00 75 08 95 10 81 02 c0 09 00 95 03 b1 12 c0 06 00 ff 09 02 a1 01 85 07 09 00 96 09 01 b1 02 85 08 09 00 95 03 81 02 09 00 b1 02 85 0e 09 00 96 0a 01 b1 02 c0 05 0d 09 02 a1 01 85 1a 09 20 a1 00 09 42 09 44 09 45 09 3c 09 5a 09 32 15 00 25 01 75 01 95 06 81 02 09 38 25 03 75 02 95 01 81 02 05 01 09 30 26 88 3e 46 88 3e 65 11 55 0d 75 10 95 01 81 02 09 31 26 60 53 46 60 53 81 02 05 0d 09 30 26 ff 0f 46 b0 0f 66 11 e1 55 02 81 02 06 00 ff 09 04 75 08 26 ff 00 46 ff 00 65 11 55 0e 81 02 05 0d 09 3d 75 10 16 d8 dc 26 28 23 36 d8 dc 46 28 23 65 14 81 02 09 3e 81 02 05 01 09 32 16 01 ff 25 00 36 01 ff 45 00 65 11 81 02 05 0d 09 56 15 00 27 ff ff 00 00 35 00 47 ff ff 00 00 66 01 10 55 0c 81 02 45 00 65 00 55 00 c0 c0 06 00 ff 09 00 a1 01 85 1b 05 0d 09 20 a1 00 09 00 26 ff 00 75 08 95 10 81 02 c0 c0",1575input_info=(BusType.USB, 0x2D1F, 0x014B),1576)157715781579