brintos

brintos / linux-shallow public Read only

0
0
Text · 90.7 KiB · a9e2de1 Raw
1506 lines · python
1#!/bin/env python32# SPDX-License-Identifier: GPL-2.03# -*- coding: utf-8 -*-4#5# Copyright (c) 2021 Benjamin Tissoires <benjamin.tissoires@gmail.com>6# Copyright (c) 2021 Red Hat, Inc.7#8 9from . import base10import copy11from enum import Enum12from hidtools.util import BusType13import libevdev14import logging15import pytest16from typing import Dict, List, Optional, Tuple17 18logger = logging.getLogger("hidtools.test.tablet")19 20 21class BtnTouch(Enum):22    """Represents whether the BTN_TOUCH event is set to True or False"""23 24    DOWN = True25    UP = False26 27 28class ToolType(Enum):29    PEN = libevdev.EV_KEY.BTN_TOOL_PEN30    RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER31 32 33class BtnPressed(Enum):34    """Represents whether a button is pressed on the stylus"""35 36    PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS37    SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS238    THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS339 40 41class PenState(Enum):42    """Pen states according to Microsoft reference:43    https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states44 45    We extend it with the various buttons when we need to check them.46    """47 48    PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False49    PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False50    PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True51    PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False52    PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True53    PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False54    PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True55    PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False56    PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True57 58    def __init__(59        self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]60    ):61        self.touch = touch  # type: ignore62        self.tool = tool  # type: ignore63        self.button = button  # type: ignore64 65    @classmethod66    def from_evdev(cls, evdev, test_button) -> "PenState":67        touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])68        tool = None69        button = False70        if (71            evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]72            and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]73        ):74            tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)75        elif (76            evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]77            and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]78        ):79            tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)80        elif (81            evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]82            or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]83        ):84            raise ValueError("2 tools are not allowed")85 86        # we take only the provided button into account87        if test_button is not None:88            button = bool(evdev.value[test_button.value])89 90        # the kernel tends to insert an EV_SYN once removing the tool, so91        # the button will be released after92        if tool is None:93            button = False94 95        return cls((touch, tool, button))  # type: ignore96 97    def apply(98        self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed99    ) -> "PenState":100        if libevdev.EV_SYN.SYN_REPORT in events:101            raise ValueError("EV_SYN is in the event sequence")102        touch = self.touch103        touch_found = False104        tool = self.tool105        tool_found = False106        button = self.button107        button_found = False108 109        for ev in events:110            if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):111                if touch_found:112                    raise ValueError(f"duplicated BTN_TOUCH in {events}")113                touch_found = True114                touch = BtnTouch(ev.value)115            elif ev in (116                libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),117                libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),118            ):119                if tool_found:120                    raise ValueError(f"duplicated BTN_TOOL_* in {events}")121                tool_found = True122                tool = ToolType(ev.code) if ev.value else None123            elif test_button is not None and ev in (test_button.value,):124                if button_found:125                    raise ValueError(f"duplicated BTN_STYLUS* in {events}")126                button_found = True127                button = bool(ev.value)128 129        # the kernel tends to insert an EV_SYN once removing the tool, so130        # the button will be released after131        if tool is None:132            button = False133 134        new_state = PenState((touch, tool, button))  # type: ignore135        if strict:136            assert (137                new_state in self.valid_transitions()138            ), f"moving from {self} to {new_state} is forbidden"139        else:140            assert (141                new_state in self.historically_tolerated_transitions()142            ), f"moving from {self} to {new_state} is forbidden"143 144        return new_state145 146    def valid_transitions(self) -> Tuple["PenState", ...]:147        """Following the state machine in the URL above.148 149        Note that those transitions are from the evdev point of view, not HID"""150        if self == PenState.PEN_IS_OUT_OF_RANGE:151            return (152                PenState.PEN_IS_OUT_OF_RANGE,153                PenState.PEN_IS_IN_RANGE,154                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,155                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,156                PenState.PEN_IS_IN_CONTACT,157                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,158                PenState.PEN_IS_ERASING,159            )160 161        if self == PenState.PEN_IS_IN_RANGE:162            return (163                PenState.PEN_IS_IN_RANGE,164                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,165                PenState.PEN_IS_OUT_OF_RANGE,166                PenState.PEN_IS_IN_CONTACT,167            )168 169        if self == PenState.PEN_IS_IN_CONTACT:170            return (171                PenState.PEN_IS_IN_CONTACT,172                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,173                PenState.PEN_IS_IN_RANGE,174            )175 176        if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:177            return (178                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,179                PenState.PEN_IS_OUT_OF_RANGE,180                PenState.PEN_IS_ERASING,181            )182 183        if self == PenState.PEN_IS_ERASING:184            return (185                PenState.PEN_IS_ERASING,186                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,187            )188 189        if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:190            return (191                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,192                PenState.PEN_IS_IN_RANGE,193                PenState.PEN_IS_OUT_OF_RANGE,194                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,195            )196 197        if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:198            return (199                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,200                PenState.PEN_IS_IN_CONTACT,201                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,202            )203 204        return tuple()205 206    def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:207        """Following the state machine in the URL above, with a couple of addition208        for skipping the in-range state, due to historical reasons.209 210        Note that those transitions are from the evdev point of view, not HID"""211        if self == PenState.PEN_IS_OUT_OF_RANGE:212            return (213                PenState.PEN_IS_OUT_OF_RANGE,214                PenState.PEN_IS_IN_RANGE,215                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,216                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,217                PenState.PEN_IS_IN_CONTACT,218                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,219                PenState.PEN_IS_ERASING,220            )221 222        if self == PenState.PEN_IS_IN_RANGE:223            return (224                PenState.PEN_IS_IN_RANGE,225                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,226                PenState.PEN_IS_OUT_OF_RANGE,227                PenState.PEN_IS_IN_CONTACT,228            )229 230        if self == PenState.PEN_IS_IN_CONTACT:231            return (232                PenState.PEN_IS_IN_CONTACT,233                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,234                PenState.PEN_IS_IN_RANGE,235                PenState.PEN_IS_OUT_OF_RANGE,236            )237 238        if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:239            return (240                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,241                PenState.PEN_IS_OUT_OF_RANGE,242                PenState.PEN_IS_ERASING,243            )244 245        if self == PenState.PEN_IS_ERASING:246            return (247                PenState.PEN_IS_ERASING,248                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,249                PenState.PEN_IS_OUT_OF_RANGE,250            )251 252        if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:253            return (254                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,255                PenState.PEN_IS_IN_RANGE,256                PenState.PEN_IS_OUT_OF_RANGE,257                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,258            )259 260        if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:261            return (262                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,263                PenState.PEN_IS_IN_CONTACT,264                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,265                PenState.PEN_IS_OUT_OF_RANGE,266            )267 268        return tuple()269 270    @staticmethod271    def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:272        """This is the first half of the Windows Pen Implementation state machine:273        we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.274        https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states275        """276        return {277            "in-range": (PenState.PEN_IS_IN_RANGE,),278            "in-range -> out-of-range": (279                PenState.PEN_IS_IN_RANGE,280                PenState.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": (284                PenState.PEN_IS_IN_RANGE,285                PenState.PEN_IS_IN_CONTACT,286                PenState.PEN_IS_IN_RANGE,287            ),288            "in-range -> touch -> release -> out-of-range": (289                PenState.PEN_IS_IN_RANGE,290                PenState.PEN_IS_IN_CONTACT,291                PenState.PEN_IS_IN_RANGE,292                PenState.PEN_IS_OUT_OF_RANGE,293            ),294        }295 296    @staticmethod297    def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:298        """This is the second half of the Windows Pen Implementation state machine:299        we now have Invert and Erase bits, so move in/out or proximity with the intend300        to erase.301        https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states302        """303        return {304            "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,),305            "hover-erasing -> out-of-range": (306                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,307                PenState.PEN_IS_OUT_OF_RANGE,308            ),309            "hover-erasing -> erase": (310                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,311                PenState.PEN_IS_ERASING,312            ),313            "hover-erasing -> erase -> release": (314                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,315                PenState.PEN_IS_ERASING,316                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,317            ),318            "hover-erasing -> erase -> release -> out-of-range": (319                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,320                PenState.PEN_IS_ERASING,321                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,322                PenState.PEN_IS_OUT_OF_RANGE,323            ),324            "hover-erasing -> in-range": (325                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,326                PenState.PEN_IS_IN_RANGE,327            ),328            "in-range -> hover-erasing": (329                PenState.PEN_IS_IN_RANGE,330                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,331            ),332        }333 334    @staticmethod335    def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:336        """We revisit the Windows Pen Implementation state machine:337        we now have a button.338        """339        return {340            "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),341            "hover-button -> out-of-range": (342                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,343                PenState.PEN_IS_OUT_OF_RANGE,344            ),345            "in-range -> button-press": (346                PenState.PEN_IS_IN_RANGE,347                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,348            ),349            "in-range -> button-press -> button-release": (350                PenState.PEN_IS_IN_RANGE,351                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,352                PenState.PEN_IS_IN_RANGE,353            ),354            "in-range -> touch -> button-press -> button-release": (355                PenState.PEN_IS_IN_RANGE,356                PenState.PEN_IS_IN_CONTACT,357                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,358                PenState.PEN_IS_IN_CONTACT,359            ),360            "in-range -> touch -> button-press -> release -> button-release": (361                PenState.PEN_IS_IN_RANGE,362                PenState.PEN_IS_IN_CONTACT,363                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,364                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,365                PenState.PEN_IS_IN_RANGE,366            ),367            "in-range -> button-press -> touch -> release -> button-release": (368                PenState.PEN_IS_IN_RANGE,369                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,370                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,371                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,372                PenState.PEN_IS_IN_RANGE,373            ),374            "in-range -> button-press -> touch -> button-release -> release": (375                PenState.PEN_IS_IN_RANGE,376                PenState.PEN_IS_IN_RANGE_WITH_BUTTON,377                PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,378                PenState.PEN_IS_IN_CONTACT,379                PenState.PEN_IS_IN_RANGE,380            ),381        }382 383    @staticmethod384    def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:385        """This is not adhering to the Windows Pen Implementation state machine386        but we should expect the kernel to behave properly, mostly for historical387        reasons."""388        return {389            "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,),390            "direct-in-contact -> out-of-range": (391                PenState.PEN_IS_IN_CONTACT,392                PenState.PEN_IS_OUT_OF_RANGE,393            ),394        }395 396    @staticmethod397    def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:398        """This is the second half of the Windows Pen Implementation state machine:399        we now have Invert and Erase bits, so move in/out or proximity with the intend400        to erase.401        https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states402        """403        return {404            "direct-erase": (PenState.PEN_IS_ERASING,),405            "direct-erase -> out-of-range": (406                PenState.PEN_IS_ERASING,407                PenState.PEN_IS_OUT_OF_RANGE,408            ),409        }410 411    @staticmethod412    def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:413        """Those tests are definitely not part of the Windows specification.414        However, a half broken device might export those transitions.415        For example, a pen that has the eraser button might wobble between416        touching and erasing if the tablet doesn't enforce the Windows417        state machine."""418        return {419            "in-range -> touch -> erase -> hover-erase": (420                PenState.PEN_IS_IN_RANGE,421                PenState.PEN_IS_IN_CONTACT,422                PenState.PEN_IS_ERASING,423                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,424            ),425            "in-range -> erase -> hover-erase": (426                PenState.PEN_IS_IN_RANGE,427                PenState.PEN_IS_ERASING,428                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,429            ),430            "hover-erase -> erase -> touch -> in-range": (431                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,432                PenState.PEN_IS_ERASING,433                PenState.PEN_IS_IN_CONTACT,434                PenState.PEN_IS_IN_RANGE,435            ),436            "hover-erase -> touch -> in-range": (437                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,438                PenState.PEN_IS_IN_CONTACT,439                PenState.PEN_IS_IN_RANGE,440            ),441            "touch -> erase -> touch -> erase": (442                PenState.PEN_IS_IN_CONTACT,443                PenState.PEN_IS_ERASING,444                PenState.PEN_IS_IN_CONTACT,445                PenState.PEN_IS_ERASING,446            ),447        }448 449 450class Pen(object):451    def __init__(self, x, y):452        self.x = x453        self.y = y454        self.tipswitch = False455        self.tippressure = 15456        self.azimuth = 0457        self.inrange = False458        self.width = 10459        self.height = 10460        self.barrelswitch = False461        self.secondarybarrelswitch = False462        self.invert = False463        self.eraser = False464        self.xtilt = 1465        self.ytilt = 1466        self.twist = 1467        self._old_values = None468        self.current_state = None469 470    def restore(self):471        if self._old_values is not None:472            for i in [473                "x",474                "y",475                "tippressure",476                "azimuth",477                "width",478                "height",479                "twist",480                "xtilt",481                "ytilt",482            ]:483                setattr(self, i, getattr(self._old_values, i))484 485    def backup(self):486        self._old_values = copy.copy(self)487 488    def __assert_axis(self, evdev, axis, value):489        if (490            axis == libevdev.EV_KEY.BTN_TOOL_RUBBER491            and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None492        ):493            return494 495        assert (496            evdev.value[axis] == value497        ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"498 499    def assert_expected_input_events(self, evdev, button):500        assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x501        assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y502 503        # assert no other buttons than the tested ones are set504        buttons = [505            BtnPressed.PRIMARY_PRESSED,506            BtnPressed.SECONDARY_PRESSED,507            BtnPressed.THIRD_PRESSED,508        ]509        if button is not None:510            buttons.remove(button)511        for b in buttons:512            assert evdev.value[b.value] is None or evdev.value[b.value] == False513 514        assert self.current_state == PenState.from_evdev(evdev, button)515 516 517class PenDigitizer(base.UHIDTestDevice):518    def __init__(519        self,520        name,521        rdesc_str=None,522        rdesc=None,523        application="Pen",524        physical="Stylus",525        input_info=(BusType.USB, 1, 2),526        evdev_name_suffix=None,527    ):528        super().__init__(name, application, rdesc_str, rdesc, input_info)529        self.physical = physical530        self.cur_application = application531        if evdev_name_suffix is not None:532            self.name += evdev_name_suffix533 534        self.fields = []535        for r in self.parsed_rdesc.input_reports.values():536            if r.application_name == self.application:537                physicals = [f.physical_name for f in r]538                if self.physical not in physicals and None not in physicals:539                    continue540                self.fields = [f.usage_name for f in r]541 542    def move_to(self, pen, state, button):543        # fill in the previous values544        if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:545            pen.restore()546 547        print(f"\n  *** pen is moving to {state} ***")548 549        if state == PenState.PEN_IS_OUT_OF_RANGE:550            pen.backup()551            pen.x = 0552            pen.y = 0553            pen.tipswitch = False554            pen.tippressure = 0555            pen.azimuth = 0556            pen.inrange = False557            pen.width = 0558            pen.height = 0559            pen.invert = False560            pen.eraser = False561            pen.xtilt = 0562            pen.ytilt = 0563            pen.twist = 0564            pen.barrelswitch = False565            pen.secondarybarrelswitch = False566        elif state == PenState.PEN_IS_IN_RANGE:567            pen.tipswitch = False568            pen.inrange = True569            pen.invert = False570            pen.eraser = False571            pen.barrelswitch = False572            pen.secondarybarrelswitch = False573        elif state == PenState.PEN_IS_IN_CONTACT:574            pen.tipswitch = True575            pen.inrange = True576            pen.invert = False577            pen.eraser = False578            pen.barrelswitch = False579            pen.secondarybarrelswitch = False580        elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:581            pen.tipswitch = False582            pen.inrange = True583            pen.invert = False584            pen.eraser = False585            assert button is not None586            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED587            pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED588        elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:589            pen.tipswitch = True590            pen.inrange = True591            pen.invert = False592            pen.eraser = False593            assert button is not None594            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED595            pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED596        elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:597            pen.tipswitch = False598            pen.inrange = True599            pen.invert = True600            pen.eraser = False601            pen.barrelswitch = False602            pen.secondarybarrelswitch = False603        elif state == PenState.PEN_IS_ERASING:604            pen.tipswitch = False605            pen.inrange = True606            pen.invert = False607            pen.eraser = True608            pen.barrelswitch = False609            pen.secondarybarrelswitch = False610 611        pen.current_state = state612 613    def event(self, pen, button):614        rs = []615        r = self.create_report(application=self.cur_application, data=pen)616        self.call_input_event(r)617        rs.append(r)618        return rs619 620    def get_report(self, req, rnum, rtype):621        if rtype != self.UHID_FEATURE_REPORT:622            return (1, [])623 624        rdesc = None625        for v in self.parsed_rdesc.feature_reports.values():626            if v.report_ID == rnum:627                rdesc = v628 629        if rdesc is None:630            return (1, [])631 632        return (1, [])633 634    def set_report(self, req, rnum, rtype, data):635        if rtype != self.UHID_FEATURE_REPORT:636            return 1637 638        rdesc = None639        for v in self.parsed_rdesc.feature_reports.values():640            if v.report_ID == rnum:641                rdesc = v642 643        if rdesc is None:644            return 1645 646        return 1647 648 649class BaseTest:650    class TestTablet(base.BaseTestCase.TestUhid):651        def create_device(self):652            raise Exception("please reimplement me in subclasses")653 654        def post(self, uhdev, pen, test_button):655            r = uhdev.event(pen, test_button)656            events = uhdev.next_sync_events()657            self.debug_reports(r, uhdev, events)658            return events659 660        def validate_transitions(661            self, from_state, pen, evdev, events, allow_intermediate_states, button662        ):663            # check that the final state is correct664            pen.assert_expected_input_events(evdev, button)665 666            state = from_state667 668            # check that the transitions are valid669            sync_events = []670            while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:671                # split the first EV_SYN from the list672                idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))673                sync_events = events[:idx]674                events = events[idx + 1 :]675 676                # now check for a valid transition677                state = state.apply(sync_events, not allow_intermediate_states, button)678 679            if events:680                state = state.apply(sync_events, not allow_intermediate_states, button)681 682        def _test_states(683            self, state_list, scribble, allow_intermediate_states, button=None684        ):685            """Internal method to test against a list of686            transition between states.687            state_list is a list of PenState objects688            scribble is a boolean which tells if we need689            to wobble a little the X,Y coordinates of the pen690            between each state transition."""691            uhdev = self.uhdev692            evdev = uhdev.get_evdev()693 694            cur_state = PenState.PEN_IS_OUT_OF_RANGE695 696            p = Pen(50, 60)697            uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)698            events = self.post(uhdev, p, button)699            self.validate_transitions(700                cur_state, p, evdev, events, allow_intermediate_states, button701            )702 703            cur_state = p.current_state704 705            for state in state_list:706                if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:707                    p.x += 1708                    p.y -= 1709                    events = self.post(uhdev, p, button)710                    self.validate_transitions(711                        cur_state, p, evdev, events, allow_intermediate_states, button712                    )713                    assert len(events) >= 3  # X, Y, SYN714                uhdev.move_to(p, state, button)715                if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:716                    p.x += 1717                    p.y -= 1718                events = self.post(uhdev, p, button)719                self.validate_transitions(720                    cur_state, p, evdev, events, allow_intermediate_states, button721                )722                cur_state = p.current_state723 724        @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        )729        def test_valid_pen_states(self, state_list, scribble):730            """This is the first half of the Windows Pen Implementation state machine:731            we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.732            https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states733            """734            self._test_states(state_list, scribble, allow_intermediate_states=False)735 736        @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])737        @pytest.mark.parametrize(738            "state_list",739            [740                pytest.param(v, id=k)741                for k, v in PenState.tolerated_transitions().items()742            ],743        )744        def test_tolerated_pen_states(self, state_list, scribble):745            """This is not adhering to the Windows Pen Implementation state machine746            but we should expect the kernel to behave properly, mostly for historical747            reasons."""748            self._test_states(state_list, scribble, allow_intermediate_states=True)749 750        @pytest.mark.skip_if_uhdev(751            lambda 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            [758                pytest.param(v, id=k)759                for k, v in PenState.legal_transitions_with_button().items()760            ],761        )762        def test_valid_primary_button_pen_states(self, state_list, scribble):763            """Rework the transition state machine by adding the primary button."""764            self._test_states(765                state_list,766                scribble,767                allow_intermediate_states=False,768                button=BtnPressed.PRIMARY_PRESSED,769            )770 771        @pytest.mark.skip_if_uhdev(772            lambda 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            [779                pytest.param(v, id=k)780                for k, v in PenState.legal_transitions_with_button().items()781            ],782        )783        def test_valid_secondary_button_pen_states(self, state_list, scribble):784            """Rework the transition state machine by adding the secondary button."""785            self._test_states(786                state_list,787                scribble,788                allow_intermediate_states=False,789                button=BtnPressed.SECONDARY_PRESSED,790            )791 792        @pytest.mark.skip_if_uhdev(793            lambda 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            [800                pytest.param(v, id=k)801                for k, v in PenState.legal_transitions_with_button().items()802            ],803        )804        def test_valid_third_button_pen_states(self, state_list, scribble):805            """Rework the transition state machine by adding the secondary button."""806            self._test_states(807                state_list,808                scribble,809                allow_intermediate_states=False,810                button=BtnPressed.THIRD_PRESSED,811            )812 813        @pytest.mark.skip_if_uhdev(814            lambda 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            [821                pytest.param(v, id=k)822                for k, v in PenState.legal_transitions_with_invert().items()823            ],824        )825        def test_valid_invert_pen_states(self, state_list, scribble):826            """This is the second half of the Windows Pen Implementation state machine:827            we now have Invert and Erase bits, so move in/out or proximity with the intend828            to erase.829            https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states830            """831            self._test_states(state_list, scribble, allow_intermediate_states=False)832 833        @pytest.mark.skip_if_uhdev(834            lambda 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            [841                pytest.param(v, id=k)842                for k, v in PenState.tolerated_transitions_with_invert().items()843            ],844        )845        def test_tolerated_invert_pen_states(self, state_list, scribble):846            """This is the second half of the Windows Pen Implementation state machine:847            we now have Invert and Erase bits, so move in/out or proximity with the intend848            to erase.849            https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states850            """851            self._test_states(state_list, scribble, allow_intermediate_states=True)852 853        @pytest.mark.skip_if_uhdev(854            lambda 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        )862        def test_tolerated_broken_pen_states(self, state_list, scribble):863            """Those tests are definitely not part of the Windows specification.864            However, a half broken device might export those transitions.865            For example, a pen that has the eraser button might wobble between866            touching and erasing if the tablet doesn't enforce the Windows867            state machine."""868            self._test_states(state_list, scribble, allow_intermediate_states=True)869 870 871class GXTP_pen(PenDigitizer):872    def event(self, pen, test_button):873        if not hasattr(self, "prev_tip_state"):874            self.prev_tip_state = False875 876        internal_pen = copy.copy(pen)877 878        # 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 0881        if pen.tipswitch and self.prev_tip_state:882            internal_pen.inrange = False883 884        self.prev_tip_state = pen.tipswitch885 886        # 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 released890        if pen.eraser:891            internal_pen.invert = False892 893        return super().event(internal_pen, test_button)894 895 896class USIPen(PenDigitizer):897    pass898 899 900class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):901    """902    Pen with two buttons and a rubber end, but which reports903    the second button as an eraser904    """905 906    def __init__(907        self,908        name,909        rdesc_str=None,910        rdesc=None,911        application="Pen",912        physical="Stylus",913        input_info=(BusType.USB, 0x28BD, 0x095B),914        evdev_name_suffix=None,915    ):916        super().__init__(917            name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix918        )919        self.fields.append("Secondary Barrel Switch")920 921    def move_to(self, pen, state, button):922        # fill in the previous values923        if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:924            pen.restore()925 926        print(f"\n  *** pen is moving to {state} ***")927 928        if state == PenState.PEN_IS_OUT_OF_RANGE:929            pen.backup()930            pen.x = 0931            pen.y = 0932            pen.tipswitch = False933            pen.tippressure = 0934            pen.azimuth = 0935            pen.inrange = False936            pen.width = 0937            pen.height = 0938            pen.invert = False939            pen.eraser = False940            pen.xtilt = 0941            pen.ytilt = 0942            pen.twist = 0943            pen.barrelswitch = False944        elif state == PenState.PEN_IS_IN_RANGE:945            pen.tipswitch = False946            pen.inrange = True947            pen.invert = False948            pen.eraser = False949            pen.barrelswitch = False950        elif state == PenState.PEN_IS_IN_CONTACT:951            pen.tipswitch = True952            pen.inrange = True953            pen.invert = False954            pen.eraser = False955            pen.barrelswitch = False956        elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:957            pen.tipswitch = False958            pen.inrange = True959            pen.invert = False960            assert button is not None961            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED962            pen.eraser = button == BtnPressed.SECONDARY_PRESSED963        elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:964            pen.tipswitch = True965            pen.inrange = True966            pen.invert = False967            assert button is not None968            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED969            pen.eraser = button == BtnPressed.SECONDARY_PRESSED970        elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:971            pen.tipswitch = False972            pen.inrange = True973            pen.invert = True974            pen.eraser = False975            pen.barrelswitch = False976        elif state == PenState.PEN_IS_ERASING:977            pen.tipswitch = True978            pen.inrange = True979            pen.invert = True980            pen.eraser = False981            pen.barrelswitch = False982 983        pen.current_state = state984 985    def event(self, pen, test_button):986        import math987 988        pen_copy = copy.copy(pen)989        width = 13.567990        height = 8.480991        tip_height = 0.055677699992        hx = tip_height * (32767 / width)993        hy = tip_height * (32767 / height)994        if pen_copy.xtilt != 0:995            pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))996        if pen_copy.ytilt != 0:997            pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))998 999        return super().event(pen_copy, test_button)1000 1001 1002class XPPen_Artist24_28bd_093a(PenDigitizer):1003    """1004    Pen that reports secondary barrel switch through eraser1005    """1006 1007    def __init__(1008        self,1009        name,1010        rdesc_str=None,1011        rdesc=None,1012        application="Pen",1013        physical="Stylus",1014        input_info=(BusType.USB, 0x28BD, 0x093A),1015        evdev_name_suffix=None,1016    ):1017        super().__init__(1018            name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1019        )1020        self.fields.append("Secondary Barrel Switch")1021        self.previous_state = PenState.PEN_IS_OUT_OF_RANGE1022 1023    def move_to(self, pen, state, button, debug=True):1024        # fill in the previous values1025        if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1026            pen.restore()1027 1028        if debug:1029            print(f"\n  *** pen is moving to {state} ***")1030 1031        if state == PenState.PEN_IS_OUT_OF_RANGE:1032            pen.backup()1033            pen.tipswitch = False1034            pen.tippressure = 01035            pen.azimuth = 01036            pen.inrange = False1037            pen.width = 01038            pen.height = 01039            pen.invert = False1040            pen.eraser = False1041            pen.xtilt = 01042            pen.ytilt = 01043            pen.twist = 01044            pen.barrelswitch = False1045        elif state == PenState.PEN_IS_IN_RANGE:1046            pen.tipswitch = False1047            pen.inrange = True1048            pen.invert = False1049            pen.eraser = False1050            pen.barrelswitch = False1051        elif state == PenState.PEN_IS_IN_CONTACT:1052            pen.tipswitch = True1053            pen.inrange = True1054            pen.invert = False1055            pen.eraser = False1056            pen.barrelswitch = False1057        elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1058            pen.tipswitch = False1059            pen.inrange = True1060            pen.invert = False1061            assert button is not None1062            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1063            pen.eraser = button == BtnPressed.SECONDARY_PRESSED1064        elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1065            pen.tipswitch = True1066            pen.inrange = True1067            pen.invert = False1068            assert button is not None1069            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1070            pen.eraser = button == BtnPressed.SECONDARY_PRESSED1071 1072        pen.current_state = state1073 1074    def send_intermediate_state(self, pen, state, button):1075        intermediate_pen = copy.copy(pen)1076        self.move_to(intermediate_pen, state, button, debug=False)1077        return super().event(intermediate_pen, button)1078 1079    def event(self, pen, button):1080        rs = []1081 1082        # the pen reliably sends in-range events in a normal case (non emulation of eraser mode)1083        if self.previous_state == PenState.PEN_IS_IN_CONTACT:1084            if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1085                rs.extend(1086                    self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1087                )1088 1089        if button == BtnPressed.SECONDARY_PRESSED:1090            if self.previous_state == PenState.PEN_IS_IN_RANGE:1091                if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1092                    rs.extend(1093                        self.send_intermediate_state(1094                            pen, PenState.PEN_IS_OUT_OF_RANGE, button1095                        )1096                    )1097 1098            if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1099                if pen.current_state == PenState.PEN_IS_IN_RANGE:1100                    rs.extend(1101                        self.send_intermediate_state(1102                            pen, PenState.PEN_IS_OUT_OF_RANGE, button1103                        )1104                    )1105 1106            if self.previous_state == PenState.PEN_IS_IN_CONTACT:1107                if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1108                    rs.extend(1109                        self.send_intermediate_state(1110                            pen, PenState.PEN_IS_OUT_OF_RANGE, button1111                        )1112                    )1113                    rs.extend(1114                        self.send_intermediate_state(1115                            pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button1116                        )1117                    )1118 1119            if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1120                if pen.current_state == PenState.PEN_IS_IN_CONTACT:1121                    rs.extend(1122                        self.send_intermediate_state(1123                            pen, PenState.PEN_IS_OUT_OF_RANGE, button1124                        )1125                    )1126                    rs.extend(1127                        self.send_intermediate_state(1128                            pen, PenState.PEN_IS_IN_RANGE, button1129                        )1130                    )1131 1132        rs.extend(super().event(pen, button))1133        self.previous_state = pen.current_state1134        return rs1135 1136 1137class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):1138    """1139    Pen that reports secondary barrel switch through secondary TipSwtich1140    and 3rd button through Invert1141    """1142 1143    def __init__(1144        self,1145        name,1146        rdesc_str=None,1147        rdesc=None,1148        application="Stylus",1149        physical=None,1150        input_info=(BusType.USB, 0x256C, 0x006B),1151        evdev_name_suffix=None,1152    ):1153        super().__init__(1154            name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1155        )1156        self.fields.append("Secondary Barrel Switch")1157        self.fields.append("Third Barrel Switch")1158        self.previous_state = PenState.PEN_IS_OUT_OF_RANGE1159 1160    def move_to(self, pen, state, button, debug=True):1161        # fill in the previous values1162        if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1163            pen.restore()1164 1165        if debug:1166            print(f"\n  *** pen is moving to {state} ***")1167 1168        if state == PenState.PEN_IS_OUT_OF_RANGE:1169            pen.backup()1170            pen.tipswitch = False1171            pen.tippressure = 01172            pen.azimuth = 01173            pen.inrange = False1174            pen.width = 01175            pen.height = 01176            pen.invert = False1177            pen.eraser = False1178            pen.xtilt = 01179            pen.ytilt = 01180            pen.twist = 01181            pen.barrelswitch = False1182            pen.secondarytipswitch = False1183        elif state == PenState.PEN_IS_IN_RANGE:1184            pen.tipswitch = False1185            pen.inrange = True1186            pen.invert = False1187            pen.eraser = False1188            pen.barrelswitch = False1189            pen.secondarytipswitch = False1190        elif state == PenState.PEN_IS_IN_CONTACT:1191            pen.tipswitch = True1192            pen.inrange = True1193            pen.invert = False1194            pen.eraser = False1195            pen.barrelswitch = False1196            pen.secondarytipswitch = False1197        elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1198            pen.tipswitch = False1199            pen.inrange = True1200            pen.eraser = False1201            assert button is not None1202            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1203            pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1204            pen.invert = button == BtnPressed.THIRD_PRESSED1205        elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1206            pen.tipswitch = True1207            pen.inrange = True1208            pen.eraser = False1209            assert button is not None1210            pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1211            pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1212            pen.invert = button == BtnPressed.THIRD_PRESSED1213        elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:1214            pen.tipswitch = False1215            pen.inrange = True1216            pen.invert = True1217            pen.eraser = False1218            pen.barrelswitch = False1219            pen.secondarytipswitch = False1220        elif state == PenState.PEN_IS_ERASING:1221            pen.tipswitch = False1222            pen.inrange = True1223            pen.invert = False1224            pen.eraser = True1225            pen.barrelswitch = False1226            pen.secondarytipswitch = False1227 1228        pen.current_state = state1229 1230    def call_input_event(self, report):1231        if report[0] == 0x0a:1232            # ensures the original second Eraser usage is null1233            report[1] &= 0xdf1234 1235            # ensures the original last bit is equal to bit 6 (In Range)1236            if report[1] & 0x40:1237                report[1] |= 0x801238 1239        super().call_input_event(report)1240 1241    def send_intermediate_state(self, pen, state, test_button):1242        intermediate_pen = copy.copy(pen)1243        self.move_to(intermediate_pen, state, test_button, debug=False)1244        return super().event(intermediate_pen, test_button)1245 1246    def event(self, pen, button):1247        rs = []1248 1249        # 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 pen1252        if self.previous_state in (1253            PenState.PEN_IS_IN_RANGE,1254            PenState.PEN_IS_IN_RANGE_WITH_BUTTON,1255            PenState.PEN_IS_IN_CONTACT,1256            PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,1257        ) and pen.current_state in (1258            PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,1259            PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,1260            PenState.PEN_IS_ERASING,1261            PenState.PEN_IS_ERASING_WITH_BUTTON,1262        ):1263            rs.extend(1264                self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1265            )1266 1267        # same than above except from eraser to normal1268        if self.previous_state in (1269            PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,1270            PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,1271            PenState.PEN_IS_ERASING,1272            PenState.PEN_IS_ERASING_WITH_BUTTON,1273        ) and pen.current_state in (1274            PenState.PEN_IS_IN_RANGE,1275            PenState.PEN_IS_IN_RANGE_WITH_BUTTON,1276            PenState.PEN_IS_IN_CONTACT,1277            PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,1278        ):1279            rs.extend(1280                self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1281            )1282 1283        if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:1284            if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1285                rs.extend(1286                    self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1287                )1288 1289        rs.extend(super().event(pen, button))1290        self.previous_state = pen.current_state1291        return rs1292 1293 1294################################################################################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))1352 1353 1354class TestNexio_1870_0100(BaseTest.TestTablet):1355    def create_device(self):1356        return PenDigitizer(1357            "uhid test nexio_1870_0100",1358            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 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",1359            input_info=(BusType.USB, 0x1870, 0x0100),1360        )1361 1362 1363class TestNexio_1870_010d(BaseTest.TestTablet):1364    def create_device(self):1365        return PenDigitizer(1366            "uhid test nexio_1870_010d",1367            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 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",1368            input_info=(BusType.USB, 0x1870, 0x010D),1369        )1370 1371 1372class TestNexio_1870_0119(BaseTest.TestTablet):1373    def create_device(self):1374        return PenDigitizer(1375            "uhid test nexio_1870_0119",1376            rdesc="05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 95 06 81 03 75 08 09 51 95 01 81 02 05 01 26 ff 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",1377            input_info=(BusType.USB, 0x1870, 0x0119),1378        )1379 1380 1381################################################################################1382#1383# Windows 8 compatible devices1384#1385################################################################################1386 1387# 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')1391 1392 1393class Testatmel_03eb_840b(BaseTest.TestTablet):1394    def create_device(self):1395        return PenDigitizer(1396            "uhid test atmel_03eb_840b",1397            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 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        )1399 1400 1401class Testn_trig_1b96_0c01(BaseTest.TestTablet):1402    def create_device(self):1403        return PenDigitizer(1404            "uhid test n_trig_1b96_0c01",1405            rdesc="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        )1407 1408 1409class Testn_trig_1b96_0c03(BaseTest.TestTablet):1410    def create_device(self):1411        return PenDigitizer(1412            "uhid test n_trig_1b96_0c03",1413            rdesc="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        )1415 1416 1417class Testn_trig_1b96_0f00(BaseTest.TestTablet):1418    def create_device(self):1419        return PenDigitizer(1420            "uhid test n_trig_1b96_0f00",1421            rdesc="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        )1423 1424 1425class Testn_trig_1b96_0f04(BaseTest.TestTablet):1426    def create_device(self):1427        return PenDigitizer(1428            "uhid test n_trig_1b96_0f04",1429            rdesc="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        )1431 1432 1433class Testn_trig_1b96_1000(BaseTest.TestTablet):1434    def create_device(self):1435        return PenDigitizer(1436            "uhid test n_trig_1b96_1000",1437            rdesc="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        )1439 1440 1441class TestGXTP_27c6_0113(BaseTest.TestTablet):1442    def create_device(self):1443        return GXTP_pen(1444            "uhid test GXTP_27c6_0113",1445            rdesc="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        )1447 1448 1449################################################################################1450#1451# Windows 8 compatible devices with USI Pen1452#1453################################################################################1454 1455 1456class TestElan_04f3_2A49(BaseTest.TestTablet):1457    def create_device(self):1458        return USIPen(1459            "uhid test Elan_04f3_2A49",1460            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 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",1461            input_info=(BusType.I2C, 0x04F3, 0x2A49),1462        )1463 1464 1465class TestGoodix_27c6_0e00(BaseTest.TestTablet):1466    def create_device(self):1467        return USIPen(1468            "uhid test Elan_04f3_2A49",1469            rdesc="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",1470            input_info=(BusType.I2C, 0x27C6, 0x0E00),1471        )1472 1473 1474class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):1475    hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)]1476 1477    def create_device(self):1478        dev = XPPen_ArtistPro16Gen2_28bd_095b(1479            "uhid test XPPen Artist Pro 16 Gen2 28bd 095b",1480            rdesc="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",1481            input_info=(BusType.USB, 0x28BD, 0x095B),1482        )1483        return dev1484 1485 1486class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):1487    hid_bpfs = [("XPPen__Artist24.bpf.o", True)]1488 1489    def create_device(self):1490        return XPPen_Artist24_28bd_093a(1491            "uhid test XPPen Artist 24 28bd 093a",1492            rdesc="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",1493            input_info=(BusType.USB, 0x28BD, 0x093A),1494        )1495 1496 1497class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):1498    hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)]1499 1500    def create_device(self):1501        return Huion_Kamvas_Pro_19_256c_006b(1502            "uhid test HUION Huion Tablet_GT1902",1503            rdesc="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",1504            input_info=(BusType.USB, 0x256C, 0x006B),1505        )1506