Path: blob/master/tools/testing/selftests/hid/tests/test_tablet.py
26308 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.tipswitch = False455self.tippressure = 15456self.azimuth = 0457self.inrange = False458self.width = 10459self.height = 10460self.barrelswitch = False461self.secondarybarrelswitch = False462self.invert = False463self.eraser = False464self.xtilt = 1465self.ytilt = 1466self.twist = 1467self._old_values = None468self.current_state = None469470def restore(self):471if self._old_values is not None:472for i in [473"x",474"y",475"tippressure",476"azimuth",477"width",478"height",479"twist",480"xtilt",481"ytilt",482]:483setattr(self, i, getattr(self._old_values, i))484485def backup(self):486self._old_values = copy.copy(self)487488def __assert_axis(self, evdev, axis, value):489if (490axis == libevdev.EV_KEY.BTN_TOOL_RUBBER491and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None492):493return494495assert (496evdev.value[axis] == value497), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"498499def assert_expected_input_events(self, evdev, button):500assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x501assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y502503# assert no other buttons than the tested ones are set504buttons = [505BtnPressed.PRIMARY_PRESSED,506BtnPressed.SECONDARY_PRESSED,507BtnPressed.THIRD_PRESSED,508]509if button is not None:510buttons.remove(button)511for b in buttons:512assert evdev.value[b.value] is None or evdev.value[b.value] == False513514assert self.current_state == PenState.from_evdev(evdev, button)515516517class PenDigitizer(base.UHIDTestDevice):518def __init__(519self,520name,521rdesc_str=None,522rdesc=None,523application="Pen",524physical="Stylus",525input_info=(BusType.USB, 1, 2),526evdev_name_suffix=None,527):528super().__init__(name, application, rdesc_str, rdesc, input_info)529self.physical = physical530self.cur_application = application531if evdev_name_suffix is not None:532self.name += evdev_name_suffix533534self.fields = []535for r in self.parsed_rdesc.input_reports.values():536if r.application_name == self.application:537physicals = [f.physical_name for f in r]538if self.physical not in physicals and None not in physicals:539continue540self.fields = [f.usage_name for f in r]541542def move_to(self, pen, state, button):543# fill in the previous values544if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:545pen.restore()546547print(f"\n *** pen is moving to {state} ***")548549if state == PenState.PEN_IS_OUT_OF_RANGE:550pen.backup()551pen.x = 0552pen.y = 0553pen.tipswitch = False554pen.tippressure = 0555pen.azimuth = 0556pen.inrange = False557pen.width = 0558pen.height = 0559pen.invert = False560pen.eraser = False561pen.xtilt = 0562pen.ytilt = 0563pen.twist = 0564pen.barrelswitch = False565pen.secondarybarrelswitch = False566elif state == PenState.PEN_IS_IN_RANGE:567pen.tipswitch = False568pen.inrange = True569pen.invert = False570pen.eraser = False571pen.barrelswitch = False572pen.secondarybarrelswitch = False573elif state == PenState.PEN_IS_IN_CONTACT:574pen.tipswitch = True575pen.inrange = True576pen.invert = False577pen.eraser = False578pen.barrelswitch = False579pen.secondarybarrelswitch = False580elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:581pen.tipswitch = False582pen.inrange = True583pen.invert = False584pen.eraser = False585assert button is not None586pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED587pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED588elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:589pen.tipswitch = True590pen.inrange = True591pen.invert = False592pen.eraser = False593assert button is not None594pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED595pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED596elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:597pen.tipswitch = False598pen.inrange = True599pen.invert = True600pen.eraser = False601pen.barrelswitch = False602pen.secondarybarrelswitch = False603elif state == PenState.PEN_IS_ERASING:604pen.tipswitch = False605pen.inrange = True606pen.invert = False607pen.eraser = True608pen.barrelswitch = False609pen.secondarybarrelswitch = False610611pen.current_state = state612613def event(self, pen, button):614rs = []615r = self.create_report(application=self.cur_application, data=pen)616self.call_input_event(r)617rs.append(r)618return rs619620def get_report(self, req, rnum, rtype):621if rtype != self.UHID_FEATURE_REPORT:622return (1, [])623624rdesc = None625for v in self.parsed_rdesc.feature_reports.values():626if v.report_ID == rnum:627rdesc = v628629if rdesc is None:630return (1, [])631632return (1, [])633634def set_report(self, req, rnum, rtype, data):635if rtype != self.UHID_FEATURE_REPORT:636return 1637638rdesc = None639for v in self.parsed_rdesc.feature_reports.values():640if v.report_ID == rnum:641rdesc = v642643if rdesc is None:644return 1645646return 1647648649class BaseTest:650class TestTablet(base.BaseTestCase.TestUhid):651def create_device(self):652raise Exception("please reimplement me in subclasses")653654def post(self, uhdev, pen, test_button):655r = uhdev.event(pen, test_button)656events = uhdev.next_sync_events()657self.debug_reports(r, uhdev, events)658return events659660def validate_transitions(661self, from_state, pen, evdev, events, allow_intermediate_states, button662):663# check that the final state is correct664pen.assert_expected_input_events(evdev, button)665666state = from_state667668# check that the transitions are valid669sync_events = []670while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:671# split the first EV_SYN from the list672idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))673sync_events = events[:idx]674events = events[idx + 1 :]675676# now check for a valid transition677state = state.apply(sync_events, not allow_intermediate_states, button)678679if events:680state = state.apply(sync_events, not allow_intermediate_states, button)681682def _test_states(683self, state_list, scribble, allow_intermediate_states, button=None684):685"""Internal method to test against a list of686transition between states.687state_list is a list of PenState objects688scribble is a boolean which tells if we need689to wobble a little the X,Y coordinates of the pen690between each state transition."""691uhdev = self.uhdev692evdev = uhdev.get_evdev()693694cur_state = PenState.PEN_IS_OUT_OF_RANGE695696p = Pen(50, 60)697uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)698events = self.post(uhdev, p, button)699self.validate_transitions(700cur_state, p, evdev, events, allow_intermediate_states, button701)702703cur_state = p.current_state704705for state in state_list:706if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:707p.x += 1708p.y -= 1709events = self.post(uhdev, p, button)710self.validate_transitions(711cur_state, p, evdev, events, allow_intermediate_states, button712)713assert len(events) >= 3 # X, Y, SYN714uhdev.move_to(p, state, button)715if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:716p.x += 1717p.y -= 1718events = self.post(uhdev, p, button)719self.validate_transitions(720cur_state, p, evdev, events, allow_intermediate_states, button721)722cur_state = p.current_state723724@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])725@pytest.mark.parametrize(726"state_list",727[pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],728)729def test_valid_pen_states(self, state_list, scribble):730"""This is the first half of the Windows Pen Implementation state machine:731we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.732https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states733"""734self._test_states(state_list, scribble, allow_intermediate_states=False)735736@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])737@pytest.mark.parametrize(738"state_list",739[740pytest.param(v, id=k)741for k, v in PenState.tolerated_transitions().items()742],743)744def test_tolerated_pen_states(self, state_list, scribble):745"""This is not adhering to the Windows Pen Implementation state machine746but we should expect the kernel to behave properly, mostly for historical747reasons."""748self._test_states(state_list, scribble, allow_intermediate_states=True)749750@pytest.mark.skip_if_uhdev(751lambda uhdev: "Barrel Switch" not in uhdev.fields,752"Device not compatible, missing Barrel Switch usage",753)754@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])755@pytest.mark.parametrize(756"state_list",757[758pytest.param(v, id=k)759for k, v in PenState.legal_transitions_with_button().items()760],761)762def test_valid_primary_button_pen_states(self, state_list, scribble):763"""Rework the transition state machine by adding the primary button."""764self._test_states(765state_list,766scribble,767allow_intermediate_states=False,768button=BtnPressed.PRIMARY_PRESSED,769)770771@pytest.mark.skip_if_uhdev(772lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,773"Device not compatible, missing Secondary Barrel Switch usage",774)775@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])776@pytest.mark.parametrize(777"state_list",778[779pytest.param(v, id=k)780for k, v in PenState.legal_transitions_with_button().items()781],782)783def test_valid_secondary_button_pen_states(self, state_list, scribble):784"""Rework the transition state machine by adding the secondary button."""785self._test_states(786state_list,787scribble,788allow_intermediate_states=False,789button=BtnPressed.SECONDARY_PRESSED,790)791792@pytest.mark.skip_if_uhdev(793lambda uhdev: "Third Barrel Switch" not in uhdev.fields,794"Device not compatible, missing Third Barrel Switch usage",795)796@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])797@pytest.mark.parametrize(798"state_list",799[800pytest.param(v, id=k)801for k, v in PenState.legal_transitions_with_button().items()802],803)804def test_valid_third_button_pen_states(self, state_list, scribble):805"""Rework the transition state machine by adding the secondary button."""806self._test_states(807state_list,808scribble,809allow_intermediate_states=False,810button=BtnPressed.THIRD_PRESSED,811)812813@pytest.mark.skip_if_uhdev(814lambda uhdev: "Invert" not in uhdev.fields,815"Device not compatible, missing Invert usage",816)817@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])818@pytest.mark.parametrize(819"state_list",820[821pytest.param(v, id=k)822for k, v in PenState.legal_transitions_with_invert().items()823],824)825def test_valid_invert_pen_states(self, state_list, scribble):826"""This is the second half of the Windows Pen Implementation state machine:827we now have Invert and Erase bits, so move in/out or proximity with the intend828to erase.829https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states830"""831self._test_states(state_list, scribble, allow_intermediate_states=False)832833@pytest.mark.skip_if_uhdev(834lambda uhdev: "Invert" not in uhdev.fields,835"Device not compatible, missing Invert usage",836)837@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])838@pytest.mark.parametrize(839"state_list",840[841pytest.param(v, id=k)842for k, v in PenState.tolerated_transitions_with_invert().items()843],844)845def test_tolerated_invert_pen_states(self, state_list, scribble):846"""This is the second half of the Windows Pen Implementation state machine:847we now have Invert and Erase bits, so move in/out or proximity with the intend848to erase.849https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states850"""851self._test_states(state_list, scribble, allow_intermediate_states=True)852853@pytest.mark.skip_if_uhdev(854lambda uhdev: "Invert" not in uhdev.fields,855"Device not compatible, missing Invert usage",856)857@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])858@pytest.mark.parametrize(859"state_list",860[pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],861)862def test_tolerated_broken_pen_states(self, state_list, scribble):863"""Those tests are definitely not part of the Windows specification.864However, a half broken device might export those transitions.865For example, a pen that has the eraser button might wobble between866touching and erasing if the tablet doesn't enforce the Windows867state machine."""868self._test_states(state_list, scribble, allow_intermediate_states=True)869870871class GXTP_pen(PenDigitizer):872def event(self, pen, test_button):873if not hasattr(self, "prev_tip_state"):874self.prev_tip_state = False875876internal_pen = copy.copy(pen)877878# bug in the controller: when the pen touches the879# surface, in-range stays to 1, but when880# the pen moves in-range gets reverted to 0881if pen.tipswitch and self.prev_tip_state:882internal_pen.inrange = False883884self.prev_tip_state = pen.tipswitch885886# another bug in the controller: when the pen is887# inverted, invert is set to 1, but as soon as888# the pen touches the surface, eraser is correctly889# set to 1 but invert is released890if pen.eraser:891internal_pen.invert = False892893return super().event(internal_pen, test_button)894895896class USIPen(PenDigitizer):897pass898899900class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):901"""902Pen with two buttons and a rubber end, but which reports903the second button as an eraser904"""905906def __init__(907self,908name,909rdesc_str=None,910rdesc=None,911application="Pen",912physical="Stylus",913input_info=(BusType.USB, 0x28BD, 0x095B),914evdev_name_suffix=None,915):916super().__init__(917name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix918)919self.fields.append("Secondary Barrel Switch")920921def move_to(self, pen, state, button):922# fill in the previous values923if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:924pen.restore()925926print(f"\n *** pen is moving to {state} ***")927928if state == PenState.PEN_IS_OUT_OF_RANGE:929pen.backup()930pen.x = 0931pen.y = 0932pen.tipswitch = False933pen.tippressure = 0934pen.azimuth = 0935pen.inrange = False936pen.width = 0937pen.height = 0938pen.invert = False939pen.eraser = False940pen.xtilt = 0941pen.ytilt = 0942pen.twist = 0943pen.barrelswitch = False944elif state == PenState.PEN_IS_IN_RANGE:945pen.tipswitch = False946pen.inrange = True947pen.invert = False948pen.eraser = False949pen.barrelswitch = False950elif state == PenState.PEN_IS_IN_CONTACT:951pen.tipswitch = True952pen.inrange = True953pen.invert = False954pen.eraser = False955pen.barrelswitch = False956elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:957pen.tipswitch = False958pen.inrange = True959pen.invert = False960assert button is not None961pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED962pen.eraser = button == BtnPressed.SECONDARY_PRESSED963elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:964pen.tipswitch = True965pen.inrange = True966pen.invert = False967assert button is not None968pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED969pen.eraser = button == BtnPressed.SECONDARY_PRESSED970elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:971pen.tipswitch = False972pen.inrange = True973pen.invert = True974pen.eraser = False975pen.barrelswitch = False976elif state == PenState.PEN_IS_ERASING:977pen.tipswitch = True978pen.inrange = True979pen.invert = True980pen.eraser = False981pen.barrelswitch = False982983pen.current_state = state984985def event(self, pen, test_button):986import math987988pen_copy = copy.copy(pen)989width = 13.567990height = 8.480991tip_height = 0.055677699992hx = tip_height * (32767 / width)993hy = tip_height * (32767 / height)994if pen_copy.xtilt != 0:995pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))996if pen_copy.ytilt != 0:997pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))998999return super().event(pen_copy, test_button)100010011002class XPPen_Artist24_28bd_093a(PenDigitizer):1003"""1004Pen that reports secondary barrel switch through eraser1005"""10061007def __init__(1008self,1009name,1010rdesc_str=None,1011rdesc=None,1012application="Pen",1013physical="Stylus",1014input_info=(BusType.USB, 0x28BD, 0x093A),1015evdev_name_suffix=None,1016):1017super().__init__(1018name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1019)1020self.fields.append("Secondary Barrel Switch")1021self.previous_state = PenState.PEN_IS_OUT_OF_RANGE10221023def move_to(self, pen, state, button, debug=True):1024# fill in the previous values1025if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1026pen.restore()10271028if debug:1029print(f"\n *** pen is moving to {state} ***")10301031if state == PenState.PEN_IS_OUT_OF_RANGE:1032pen.backup()1033pen.tipswitch = False1034pen.tippressure = 01035pen.azimuth = 01036pen.inrange = False1037pen.width = 01038pen.height = 01039pen.invert = False1040pen.eraser = False1041pen.xtilt = 01042pen.ytilt = 01043pen.twist = 01044pen.barrelswitch = False1045elif state == PenState.PEN_IS_IN_RANGE:1046pen.tipswitch = False1047pen.inrange = True1048pen.invert = False1049pen.eraser = False1050pen.barrelswitch = False1051elif state == PenState.PEN_IS_IN_CONTACT:1052pen.tipswitch = True1053pen.inrange = True1054pen.invert = False1055pen.eraser = False1056pen.barrelswitch = False1057elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1058pen.tipswitch = False1059pen.inrange = True1060pen.invert = False1061assert button is not None1062pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1063pen.eraser = button == BtnPressed.SECONDARY_PRESSED1064elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1065pen.tipswitch = True1066pen.inrange = True1067pen.invert = False1068assert button is not None1069pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1070pen.eraser = button == BtnPressed.SECONDARY_PRESSED10711072pen.current_state = state10731074def send_intermediate_state(self, pen, state, button):1075intermediate_pen = copy.copy(pen)1076self.move_to(intermediate_pen, state, button, debug=False)1077return super().event(intermediate_pen, button)10781079def event(self, pen, button):1080rs = []10811082# the pen reliably sends in-range events in a normal case (non emulation of eraser mode)1083if self.previous_state == PenState.PEN_IS_IN_CONTACT:1084if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1085rs.extend(1086self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1087)10881089if button == BtnPressed.SECONDARY_PRESSED:1090if self.previous_state == PenState.PEN_IS_IN_RANGE:1091if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1092rs.extend(1093self.send_intermediate_state(1094pen, PenState.PEN_IS_OUT_OF_RANGE, button1095)1096)10971098if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1099if pen.current_state == PenState.PEN_IS_IN_RANGE:1100rs.extend(1101self.send_intermediate_state(1102pen, PenState.PEN_IS_OUT_OF_RANGE, button1103)1104)11051106if self.previous_state == PenState.PEN_IS_IN_CONTACT:1107if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1108rs.extend(1109self.send_intermediate_state(1110pen, PenState.PEN_IS_OUT_OF_RANGE, button1111)1112)1113rs.extend(1114self.send_intermediate_state(1115pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button1116)1117)11181119if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1120if pen.current_state == PenState.PEN_IS_IN_CONTACT:1121rs.extend(1122self.send_intermediate_state(1123pen, PenState.PEN_IS_OUT_OF_RANGE, button1124)1125)1126rs.extend(1127self.send_intermediate_state(1128pen, PenState.PEN_IS_IN_RANGE, button1129)1130)11311132rs.extend(super().event(pen, button))1133self.previous_state = pen.current_state1134return rs113511361137class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):1138"""1139Pen that reports secondary barrel switch through secondary TipSwtich1140and 3rd button through Invert1141"""11421143def __init__(1144self,1145name,1146rdesc_str=None,1147rdesc=None,1148application="Stylus",1149physical=None,1150input_info=(BusType.USB, 0x256C, 0x006B),1151evdev_name_suffix=None,1152):1153super().__init__(1154name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1155)1156self.fields.append("Secondary Barrel Switch")1157self.fields.append("Third Barrel Switch")1158self.previous_state = PenState.PEN_IS_OUT_OF_RANGE11591160def move_to(self, pen, state, button, debug=True):1161# fill in the previous values1162if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1163pen.restore()11641165if debug:1166print(f"\n *** pen is moving to {state} ***")11671168if state == PenState.PEN_IS_OUT_OF_RANGE:1169pen.backup()1170pen.tipswitch = False1171pen.tippressure = 01172pen.azimuth = 01173pen.inrange = False1174pen.width = 01175pen.height = 01176pen.invert = False1177pen.eraser = False1178pen.xtilt = 01179pen.ytilt = 01180pen.twist = 01181pen.barrelswitch = False1182pen.secondarytipswitch = False1183elif state == PenState.PEN_IS_IN_RANGE:1184pen.tipswitch = False1185pen.inrange = True1186pen.invert = False1187pen.eraser = False1188pen.barrelswitch = False1189pen.secondarytipswitch = False1190elif state == PenState.PEN_IS_IN_CONTACT:1191pen.tipswitch = True1192pen.inrange = True1193pen.invert = False1194pen.eraser = False1195pen.barrelswitch = False1196pen.secondarytipswitch = False1197elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1198pen.tipswitch = False1199pen.inrange = True1200pen.eraser = False1201assert button is not None1202pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1203pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1204pen.invert = button == BtnPressed.THIRD_PRESSED1205elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1206pen.tipswitch = True1207pen.inrange = True1208pen.eraser = False1209assert button is not None1210pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1211pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1212pen.invert = button == BtnPressed.THIRD_PRESSED1213elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:1214pen.tipswitch = False1215pen.inrange = True1216pen.invert = True1217pen.eraser = False1218pen.barrelswitch = False1219pen.secondarytipswitch = False1220elif state == PenState.PEN_IS_ERASING:1221pen.tipswitch = False1222pen.inrange = True1223pen.invert = False1224pen.eraser = True1225pen.barrelswitch = False1226pen.secondarytipswitch = False12271228pen.current_state = state12291230def call_input_event(self, report):1231if report[0] == 0x0A:1232# ensures the original second Eraser usage is null1233report[1] &= 0xDF12341235# ensures the original last bit is equal to bit 6 (In Range)1236if report[1] & 0x40:1237report[1] |= 0x8012381239super().call_input_event(report)12401241def send_intermediate_state(self, pen, state, test_button):1242intermediate_pen = copy.copy(pen)1243self.move_to(intermediate_pen, state, test_button, debug=False)1244return super().event(intermediate_pen, test_button)12451246def event(self, pen, button):1247rs = []12481249# it's not possible to go between eraser mode or not without1250# going out-of-prox: the eraser mode is activated by presenting1251# the tail of the pen1252if self.previous_state in (1253PenState.PEN_IS_IN_RANGE,1254PenState.PEN_IS_IN_RANGE_WITH_BUTTON,1255PenState.PEN_IS_IN_CONTACT,1256PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,1257) and pen.current_state in (1258PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,1259PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,1260PenState.PEN_IS_ERASING,1261PenState.PEN_IS_ERASING_WITH_BUTTON,1262):1263rs.extend(1264self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1265)12661267# same than above except from eraser to normal1268if self.previous_state in (1269PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,1270PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,1271PenState.PEN_IS_ERASING,1272PenState.PEN_IS_ERASING_WITH_BUTTON,1273) and pen.current_state in (1274PenState.PEN_IS_IN_RANGE,1275PenState.PEN_IS_IN_RANGE_WITH_BUTTON,1276PenState.PEN_IS_IN_CONTACT,1277PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,1278):1279rs.extend(1280self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1281)12821283if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:1284if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1285rs.extend(1286self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1287)12881289rs.extend(super().event(pen, button))1290self.previous_state = pen.current_state1291return rs129212931294################################################################################1295#1296# Windows 7 compatible devices1297#1298################################################################################1299# class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):1300# def create_device(self):1301# return PenDigitizer('uhid test egalax-capacitive_0eef_7224',1302# 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',1303# input_info=(BusType.USB, 0x0eef, 0x7224),1304# evdev_name_suffix=' Touchscreen')1305#1306#1307# class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):1308# def create_device(self):1309# return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',1310# 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',1311# input_info=(BusType.USB, 0x0eef, 0x72fa),1312# evdev_name_suffix=' Touchscreen')1313#1314#1315# class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):1316# def create_device(self):1317# return PenDigitizer('uhid test egalax-capacitive_0eef_7336',1318# 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',1319# input_info=(BusType.USB, 0x0eef, 0x7336),1320# evdev_name_suffix=' Touchscreen')1321#1322#1323# class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):1324# def create_device(self):1325# return PenDigitizer('uhid test egalax-capacitive_0eef_7337',1326# 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',1327# input_info=(BusType.USB, 0x0eef, 0x7337),1328# evdev_name_suffix=' Touchscreen')1329#1330#1331# class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):1332# def create_device(self):1333# return PenDigitizer('uhid test egalax-capacitive_0eef_7349',1334# 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',1335# input_info=(BusType.USB, 0x0eef, 0x7349),1336# evdev_name_suffix=' Touchscreen')1337#1338#1339# class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):1340# def create_device(self):1341# return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',1342# 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',1343# input_info=(BusType.USB, 0x0eef, 0x73f4),1344# evdev_name_suffix=' Touchscreen')1345#1346# bogus: BTN_TOOL_PEN is not emitted1347# class TestIrtouch_6615_0070(BaseTest.TestTablet):1348# def create_device(self):1349# return PenDigitizer('uhid test irtouch_6615_0070',1350# 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',1351# input_info=(BusType.USB, 0x6615, 0x0070))135213531354class TestNexio_1870_0100(BaseTest.TestTablet):1355def create_device(self):1356return PenDigitizer(1357"uhid test nexio_1870_0100",1358rdesc="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",1359input_info=(BusType.USB, 0x1870, 0x0100),1360)136113621363class TestNexio_1870_010d(BaseTest.TestTablet):1364def create_device(self):1365return PenDigitizer(1366"uhid test nexio_1870_010d",1367rdesc="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",1368input_info=(BusType.USB, 0x1870, 0x010D),1369)137013711372class TestNexio_1870_0119(BaseTest.TestTablet):1373def create_device(self):1374return PenDigitizer(1375"uhid test nexio_1870_0119",1376rdesc="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",1377input_info=(BusType.USB, 0x1870, 0x0119),1378)137913801381################################################################################1382#1383# Windows 8 compatible devices1384#1385################################################################################13861387# bogus: application is 'undefined'1388# class Testatmel_03eb_8409(BaseTest.TestTablet):1389# def create_device(self):1390# 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')139113921393class Testatmel_03eb_840b(BaseTest.TestTablet):1394def create_device(self):1395return PenDigitizer(1396"uhid test atmel_03eb_840b",1397rdesc="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",1398)139914001401class Testn_trig_1b96_0c01(BaseTest.TestTablet):1402def create_device(self):1403return PenDigitizer(1404"uhid test n_trig_1b96_0c01",1405rdesc="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",1406)140714081409class Testn_trig_1b96_0c03(BaseTest.TestTablet):1410def create_device(self):1411return PenDigitizer(1412"uhid test n_trig_1b96_0c03",1413rdesc="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",1414)141514161417class Testn_trig_1b96_0f00(BaseTest.TestTablet):1418def create_device(self):1419return PenDigitizer(1420"uhid test n_trig_1b96_0f00",1421rdesc="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",1422)142314241425class Testn_trig_1b96_0f04(BaseTest.TestTablet):1426def create_device(self):1427return PenDigitizer(1428"uhid test n_trig_1b96_0f04",1429rdesc="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",1430)143114321433class Testn_trig_1b96_1000(BaseTest.TestTablet):1434def create_device(self):1435return PenDigitizer(1436"uhid test n_trig_1b96_1000",1437rdesc="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",1438)143914401441class TestGXTP_27c6_0113(BaseTest.TestTablet):1442def create_device(self):1443return GXTP_pen(1444"uhid test GXTP_27c6_0113",1445rdesc="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",1446)144714481449################################################################################1450#1451# Windows 8 compatible devices with USI Pen1452#1453################################################################################145414551456class TestElan_04f3_2A49(BaseTest.TestTablet):1457def create_device(self):1458return USIPen(1459"uhid test Elan_04f3_2A49",1460rdesc="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",1461input_info=(BusType.I2C, 0x04F3, 0x2A49),1462)146314641465class TestGoodix_27c6_0e00(BaseTest.TestTablet):1466def create_device(self):1467return USIPen(1468"uhid test Elan_04f3_2A49",1469rdesc="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",1470input_info=(BusType.I2C, 0x27C6, 0x0E00),1471)147214731474class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):1475hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]14761477def create_device(self):1478dev = XPPen_ArtistPro16Gen2_28bd_095b(1479"uhid test XPPen Artist Pro 16 Gen2 28bd 095b",1480rdesc="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",1481input_info=(BusType.USB, 0x28BD, 0x095B),1482)1483return dev148414851486class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):1487hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]14881489def create_device(self):1490return XPPen_Artist24_28bd_093a(1491"uhid test XPPen Artist 24 28bd 093a",1492rdesc="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",1493input_info=(BusType.USB, 0x28BD, 0x093A),1494)149514961497class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):1498hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]14991500def create_device(self):1501return Huion_Kamvas_Pro_19_256c_006b(1502"uhid test HUION Huion Tablet_GT1902",1503rdesc="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",1504input_info=(BusType.USB, 0x256C, 0x006B),1505)150615071508