xref: /openbmc/linux/tools/testing/selftests/hid/tests/test_tablet.py (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1*0bb3ed71SBenjamin Tissoires#!/bin/env python3
2*0bb3ed71SBenjamin Tissoires# SPDX-License-Identifier: GPL-2.0
3*0bb3ed71SBenjamin Tissoires# -*- coding: utf-8 -*-
4*0bb3ed71SBenjamin Tissoires#
5*0bb3ed71SBenjamin Tissoires# Copyright (c) 2021 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6*0bb3ed71SBenjamin Tissoires# Copyright (c) 2021 Red Hat, Inc.
7*0bb3ed71SBenjamin Tissoires#
8*0bb3ed71SBenjamin Tissoires
9*0bb3ed71SBenjamin Tissoiresfrom . import base
10*0bb3ed71SBenjamin Tissoiresimport copy
11*0bb3ed71SBenjamin Tissoiresfrom enum import Enum
12*0bb3ed71SBenjamin Tissoiresfrom hidtools.util import BusType
13*0bb3ed71SBenjamin Tissoiresimport libevdev
14*0bb3ed71SBenjamin Tissoiresimport logging
15*0bb3ed71SBenjamin Tissoiresimport pytest
16*0bb3ed71SBenjamin Tissoiresfrom typing import Dict, Tuple
17*0bb3ed71SBenjamin Tissoires
18*0bb3ed71SBenjamin Tissoireslogger = logging.getLogger("hidtools.test.tablet")
19*0bb3ed71SBenjamin Tissoires
20*0bb3ed71SBenjamin Tissoires
21*0bb3ed71SBenjamin Tissoiresclass PenState(Enum):
22*0bb3ed71SBenjamin Tissoires    """Pen states according to Microsoft reference:
23*0bb3ed71SBenjamin Tissoires    https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
24*0bb3ed71SBenjamin Tissoires    """
25*0bb3ed71SBenjamin Tissoires
26*0bb3ed71SBenjamin Tissoires    PEN_IS_OUT_OF_RANGE = (False, None)
27*0bb3ed71SBenjamin Tissoires    PEN_IS_IN_RANGE = (False, libevdev.EV_KEY.BTN_TOOL_PEN)
28*0bb3ed71SBenjamin Tissoires    PEN_IS_IN_CONTACT = (True, libevdev.EV_KEY.BTN_TOOL_PEN)
29*0bb3ed71SBenjamin Tissoires    PEN_IS_IN_RANGE_WITH_ERASING_INTENT = (False, libevdev.EV_KEY.BTN_TOOL_RUBBER)
30*0bb3ed71SBenjamin Tissoires    PEN_IS_ERASING = (True, libevdev.EV_KEY.BTN_TOOL_RUBBER)
31*0bb3ed71SBenjamin Tissoires
32*0bb3ed71SBenjamin Tissoires    def __init__(self, touch, tool):
33*0bb3ed71SBenjamin Tissoires        self.touch = touch
34*0bb3ed71SBenjamin Tissoires        self.tool = tool
35*0bb3ed71SBenjamin Tissoires
36*0bb3ed71SBenjamin Tissoires    @classmethod
37*0bb3ed71SBenjamin Tissoires    def from_evdev(cls, evdev) -> "PenState":
38*0bb3ed71SBenjamin Tissoires        touch = bool(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
39*0bb3ed71SBenjamin Tissoires        tool = None
40*0bb3ed71SBenjamin Tissoires        if (
41*0bb3ed71SBenjamin Tissoires            evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
42*0bb3ed71SBenjamin Tissoires            and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
43*0bb3ed71SBenjamin Tissoires        ):
44*0bb3ed71SBenjamin Tissoires            tool = libevdev.EV_KEY.BTN_TOOL_RUBBER
45*0bb3ed71SBenjamin Tissoires        elif (
46*0bb3ed71SBenjamin Tissoires            evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
47*0bb3ed71SBenjamin Tissoires            and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
48*0bb3ed71SBenjamin Tissoires        ):
49*0bb3ed71SBenjamin Tissoires            tool = libevdev.EV_KEY.BTN_TOOL_PEN
50*0bb3ed71SBenjamin Tissoires        elif (
51*0bb3ed71SBenjamin Tissoires            evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
52*0bb3ed71SBenjamin Tissoires            or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
53*0bb3ed71SBenjamin Tissoires        ):
54*0bb3ed71SBenjamin Tissoires            raise ValueError("2 tools are not allowed")
55*0bb3ed71SBenjamin Tissoires
56*0bb3ed71SBenjamin Tissoires        return cls((touch, tool))
57*0bb3ed71SBenjamin Tissoires
58*0bb3ed71SBenjamin Tissoires    def apply(self, events) -> "PenState":
59*0bb3ed71SBenjamin Tissoires        if libevdev.EV_SYN.SYN_REPORT in events:
60*0bb3ed71SBenjamin Tissoires            raise ValueError("EV_SYN is in the event sequence")
61*0bb3ed71SBenjamin Tissoires        touch = self.touch
62*0bb3ed71SBenjamin Tissoires        touch_found = False
63*0bb3ed71SBenjamin Tissoires        tool = self.tool
64*0bb3ed71SBenjamin Tissoires        tool_found = False
65*0bb3ed71SBenjamin Tissoires
66*0bb3ed71SBenjamin Tissoires        for ev in events:
67*0bb3ed71SBenjamin Tissoires            if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):
68*0bb3ed71SBenjamin Tissoires                if touch_found:
69*0bb3ed71SBenjamin Tissoires                    raise ValueError(f"duplicated BTN_TOUCH in {events}")
70*0bb3ed71SBenjamin Tissoires                touch_found = True
71*0bb3ed71SBenjamin Tissoires                touch = bool(ev.value)
72*0bb3ed71SBenjamin Tissoires            elif ev in (
73*0bb3ed71SBenjamin Tissoires                libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),
74*0bb3ed71SBenjamin Tissoires                libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),
75*0bb3ed71SBenjamin Tissoires            ):
76*0bb3ed71SBenjamin Tissoires                if tool_found:
77*0bb3ed71SBenjamin Tissoires                    raise ValueError(f"duplicated BTN_TOOL_* in {events}")
78*0bb3ed71SBenjamin Tissoires                tool_found = True
79*0bb3ed71SBenjamin Tissoires                if ev.value:
80*0bb3ed71SBenjamin Tissoires                    tool = ev.code
81*0bb3ed71SBenjamin Tissoires                else:
82*0bb3ed71SBenjamin Tissoires                    tool = None
83*0bb3ed71SBenjamin Tissoires
84*0bb3ed71SBenjamin Tissoires        new_state = PenState((touch, tool))
85*0bb3ed71SBenjamin Tissoires        assert (
86*0bb3ed71SBenjamin Tissoires            new_state in self.valid_transitions()
87*0bb3ed71SBenjamin Tissoires        ), f"moving from {self} to {new_state} is forbidden"
88*0bb3ed71SBenjamin Tissoires
89*0bb3ed71SBenjamin Tissoires        return new_state
90*0bb3ed71SBenjamin Tissoires
91*0bb3ed71SBenjamin Tissoires    def valid_transitions(self) -> Tuple["PenState", ...]:
92*0bb3ed71SBenjamin Tissoires        """Following the state machine in the URL above, with a couple of addition
93*0bb3ed71SBenjamin Tissoires        for skipping the in-range state, due to historical reasons.
94*0bb3ed71SBenjamin Tissoires
95*0bb3ed71SBenjamin Tissoires        Note that those transitions are from the evdev point of view, not HID"""
96*0bb3ed71SBenjamin Tissoires        if self == PenState.PEN_IS_OUT_OF_RANGE:
97*0bb3ed71SBenjamin Tissoires            return (
98*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
99*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
100*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
101*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
102*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
103*0bb3ed71SBenjamin Tissoires            )
104*0bb3ed71SBenjamin Tissoires
105*0bb3ed71SBenjamin Tissoires        if self == PenState.PEN_IS_IN_RANGE:
106*0bb3ed71SBenjamin Tissoires            return (
107*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
108*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
109*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
110*0bb3ed71SBenjamin Tissoires            )
111*0bb3ed71SBenjamin Tissoires
112*0bb3ed71SBenjamin Tissoires        if self == PenState.PEN_IS_IN_CONTACT:
113*0bb3ed71SBenjamin Tissoires            return (
114*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
115*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
116*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
117*0bb3ed71SBenjamin Tissoires            )
118*0bb3ed71SBenjamin Tissoires
119*0bb3ed71SBenjamin Tissoires        if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
120*0bb3ed71SBenjamin Tissoires            return (
121*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
122*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
123*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
124*0bb3ed71SBenjamin Tissoires            )
125*0bb3ed71SBenjamin Tissoires
126*0bb3ed71SBenjamin Tissoires        if self == PenState.PEN_IS_ERASING:
127*0bb3ed71SBenjamin Tissoires            return (
128*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
129*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
130*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
131*0bb3ed71SBenjamin Tissoires            )
132*0bb3ed71SBenjamin Tissoires
133*0bb3ed71SBenjamin Tissoires        return tuple()
134*0bb3ed71SBenjamin Tissoires
135*0bb3ed71SBenjamin Tissoires
136*0bb3ed71SBenjamin Tissoiresclass Data(object):
137*0bb3ed71SBenjamin Tissoires    pass
138*0bb3ed71SBenjamin Tissoires
139*0bb3ed71SBenjamin Tissoires
140*0bb3ed71SBenjamin Tissoiresclass Pen(object):
141*0bb3ed71SBenjamin Tissoires    def __init__(self, x, y):
142*0bb3ed71SBenjamin Tissoires        self.x = x
143*0bb3ed71SBenjamin Tissoires        self.y = y
144*0bb3ed71SBenjamin Tissoires        self.tipswitch = False
145*0bb3ed71SBenjamin Tissoires        self.tippressure = 15
146*0bb3ed71SBenjamin Tissoires        self.azimuth = 0
147*0bb3ed71SBenjamin Tissoires        self.inrange = False
148*0bb3ed71SBenjamin Tissoires        self.width = 10
149*0bb3ed71SBenjamin Tissoires        self.height = 10
150*0bb3ed71SBenjamin Tissoires        self.barrelswitch = False
151*0bb3ed71SBenjamin Tissoires        self.invert = False
152*0bb3ed71SBenjamin Tissoires        self.eraser = False
153*0bb3ed71SBenjamin Tissoires        self.x_tilt = 0
154*0bb3ed71SBenjamin Tissoires        self.y_tilt = 0
155*0bb3ed71SBenjamin Tissoires        self.twist = 0
156*0bb3ed71SBenjamin Tissoires        self._old_values = None
157*0bb3ed71SBenjamin Tissoires        self.current_state = None
158*0bb3ed71SBenjamin Tissoires
159*0bb3ed71SBenjamin Tissoires    def _restore(self):
160*0bb3ed71SBenjamin Tissoires        if self._old_values is not None:
161*0bb3ed71SBenjamin Tissoires            for i in [
162*0bb3ed71SBenjamin Tissoires                "x",
163*0bb3ed71SBenjamin Tissoires                "y",
164*0bb3ed71SBenjamin Tissoires                "tippressure",
165*0bb3ed71SBenjamin Tissoires                "azimuth",
166*0bb3ed71SBenjamin Tissoires                "width",
167*0bb3ed71SBenjamin Tissoires                "height",
168*0bb3ed71SBenjamin Tissoires                "twist",
169*0bb3ed71SBenjamin Tissoires                "x_tilt",
170*0bb3ed71SBenjamin Tissoires                "y_tilt",
171*0bb3ed71SBenjamin Tissoires            ]:
172*0bb3ed71SBenjamin Tissoires                setattr(self, i, getattr(self._old_values, i))
173*0bb3ed71SBenjamin Tissoires
174*0bb3ed71SBenjamin Tissoires    def move_to(self, state):
175*0bb3ed71SBenjamin Tissoires        # fill in the previous values
176*0bb3ed71SBenjamin Tissoires        if self.current_state == PenState.PEN_IS_OUT_OF_RANGE:
177*0bb3ed71SBenjamin Tissoires            self._restore()
178*0bb3ed71SBenjamin Tissoires
179*0bb3ed71SBenjamin Tissoires        print(f"\n  *** pen is moving to {state} ***")
180*0bb3ed71SBenjamin Tissoires
181*0bb3ed71SBenjamin Tissoires        if state == PenState.PEN_IS_OUT_OF_RANGE:
182*0bb3ed71SBenjamin Tissoires            self._old_values = copy.copy(self)
183*0bb3ed71SBenjamin Tissoires            self.x = 0
184*0bb3ed71SBenjamin Tissoires            self.y = 0
185*0bb3ed71SBenjamin Tissoires            self.tipswitch = False
186*0bb3ed71SBenjamin Tissoires            self.tippressure = 0
187*0bb3ed71SBenjamin Tissoires            self.azimuth = 0
188*0bb3ed71SBenjamin Tissoires            self.inrange = False
189*0bb3ed71SBenjamin Tissoires            self.width = 0
190*0bb3ed71SBenjamin Tissoires            self.height = 0
191*0bb3ed71SBenjamin Tissoires            self.invert = False
192*0bb3ed71SBenjamin Tissoires            self.eraser = False
193*0bb3ed71SBenjamin Tissoires            self.x_tilt = 0
194*0bb3ed71SBenjamin Tissoires            self.y_tilt = 0
195*0bb3ed71SBenjamin Tissoires            self.twist = 0
196*0bb3ed71SBenjamin Tissoires        elif state == PenState.PEN_IS_IN_RANGE:
197*0bb3ed71SBenjamin Tissoires            self.tipswitch = False
198*0bb3ed71SBenjamin Tissoires            self.inrange = True
199*0bb3ed71SBenjamin Tissoires            self.invert = False
200*0bb3ed71SBenjamin Tissoires            self.eraser = False
201*0bb3ed71SBenjamin Tissoires        elif state == PenState.PEN_IS_IN_CONTACT:
202*0bb3ed71SBenjamin Tissoires            self.tipswitch = True
203*0bb3ed71SBenjamin Tissoires            self.inrange = True
204*0bb3ed71SBenjamin Tissoires            self.invert = False
205*0bb3ed71SBenjamin Tissoires            self.eraser = False
206*0bb3ed71SBenjamin Tissoires        elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
207*0bb3ed71SBenjamin Tissoires            self.tipswitch = False
208*0bb3ed71SBenjamin Tissoires            self.inrange = True
209*0bb3ed71SBenjamin Tissoires            self.invert = True
210*0bb3ed71SBenjamin Tissoires            self.eraser = False
211*0bb3ed71SBenjamin Tissoires        elif state == PenState.PEN_IS_ERASING:
212*0bb3ed71SBenjamin Tissoires            self.tipswitch = False
213*0bb3ed71SBenjamin Tissoires            self.inrange = True
214*0bb3ed71SBenjamin Tissoires            self.invert = True
215*0bb3ed71SBenjamin Tissoires            self.eraser = True
216*0bb3ed71SBenjamin Tissoires
217*0bb3ed71SBenjamin Tissoires        self.current_state = state
218*0bb3ed71SBenjamin Tissoires
219*0bb3ed71SBenjamin Tissoires    def __assert_axis(self, evdev, axis, value):
220*0bb3ed71SBenjamin Tissoires        if (
221*0bb3ed71SBenjamin Tissoires            axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
222*0bb3ed71SBenjamin Tissoires            and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
223*0bb3ed71SBenjamin Tissoires        ):
224*0bb3ed71SBenjamin Tissoires            return
225*0bb3ed71SBenjamin Tissoires
226*0bb3ed71SBenjamin Tissoires        assert (
227*0bb3ed71SBenjamin Tissoires            evdev.value[axis] == value
228*0bb3ed71SBenjamin Tissoires        ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
229*0bb3ed71SBenjamin Tissoires
230*0bb3ed71SBenjamin Tissoires    def assert_expected_input_events(self, evdev):
231*0bb3ed71SBenjamin Tissoires        assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
232*0bb3ed71SBenjamin Tissoires        assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
233*0bb3ed71SBenjamin Tissoires        assert self.current_state == PenState.from_evdev(evdev)
234*0bb3ed71SBenjamin Tissoires
235*0bb3ed71SBenjamin Tissoires    @staticmethod
236*0bb3ed71SBenjamin Tissoires    def legal_transitions() -> Dict[str, Tuple[PenState, ...]]:
237*0bb3ed71SBenjamin Tissoires        """This is the first half of the Windows Pen Implementation state machine:
238*0bb3ed71SBenjamin Tissoires        we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
239*0bb3ed71SBenjamin Tissoires        https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
240*0bb3ed71SBenjamin Tissoires        """
241*0bb3ed71SBenjamin Tissoires        return {
242*0bb3ed71SBenjamin Tissoires            "in-range": (PenState.PEN_IS_IN_RANGE,),
243*0bb3ed71SBenjamin Tissoires            "in-range -> out-of-range": (
244*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
245*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
246*0bb3ed71SBenjamin Tissoires            ),
247*0bb3ed71SBenjamin Tissoires            "in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT),
248*0bb3ed71SBenjamin Tissoires            "in-range -> touch -> release": (
249*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
250*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
251*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
252*0bb3ed71SBenjamin Tissoires            ),
253*0bb3ed71SBenjamin Tissoires            "in-range -> touch -> release -> out-of-range": (
254*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
255*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
256*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
257*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
258*0bb3ed71SBenjamin Tissoires            ),
259*0bb3ed71SBenjamin Tissoires        }
260*0bb3ed71SBenjamin Tissoires
261*0bb3ed71SBenjamin Tissoires    @staticmethod
262*0bb3ed71SBenjamin Tissoires    def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
263*0bb3ed71SBenjamin Tissoires        """This is the second half of the Windows Pen Implementation state machine:
264*0bb3ed71SBenjamin Tissoires        we now have Invert and Erase bits, so move in/out or proximity with the intend
265*0bb3ed71SBenjamin Tissoires        to erase.
266*0bb3ed71SBenjamin Tissoires        https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
267*0bb3ed71SBenjamin Tissoires        """
268*0bb3ed71SBenjamin Tissoires        return {
269*0bb3ed71SBenjamin Tissoires            "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,),
270*0bb3ed71SBenjamin Tissoires            "hover-erasing -> out-of-range": (
271*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
272*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
273*0bb3ed71SBenjamin Tissoires            ),
274*0bb3ed71SBenjamin Tissoires            "hover-erasing -> erase": (
275*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
276*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
277*0bb3ed71SBenjamin Tissoires            ),
278*0bb3ed71SBenjamin Tissoires            "hover-erasing -> erase -> release": (
279*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
280*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
281*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
282*0bb3ed71SBenjamin Tissoires            ),
283*0bb3ed71SBenjamin Tissoires            "hover-erasing -> erase -> release -> out-of-range": (
284*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
285*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
286*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
287*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
288*0bb3ed71SBenjamin Tissoires            ),
289*0bb3ed71SBenjamin Tissoires            "hover-erasing -> in-range": (
290*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
291*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
292*0bb3ed71SBenjamin Tissoires            ),
293*0bb3ed71SBenjamin Tissoires            "in-range -> hover-erasing": (
294*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
295*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
296*0bb3ed71SBenjamin Tissoires            ),
297*0bb3ed71SBenjamin Tissoires        }
298*0bb3ed71SBenjamin Tissoires
299*0bb3ed71SBenjamin Tissoires    @staticmethod
300*0bb3ed71SBenjamin Tissoires    def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]:
301*0bb3ed71SBenjamin Tissoires        """This is not adhering to the Windows Pen Implementation state machine
302*0bb3ed71SBenjamin Tissoires        but we should expect the kernel to behave properly, mostly for historical
303*0bb3ed71SBenjamin Tissoires        reasons."""
304*0bb3ed71SBenjamin Tissoires        return {
305*0bb3ed71SBenjamin Tissoires            "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,),
306*0bb3ed71SBenjamin Tissoires            "direct-in-contact -> out-of-range": (
307*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
308*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
309*0bb3ed71SBenjamin Tissoires            ),
310*0bb3ed71SBenjamin Tissoires        }
311*0bb3ed71SBenjamin Tissoires
312*0bb3ed71SBenjamin Tissoires    @staticmethod
313*0bb3ed71SBenjamin Tissoires    def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
314*0bb3ed71SBenjamin Tissoires        """This is the second half of the Windows Pen Implementation state machine:
315*0bb3ed71SBenjamin Tissoires        we now have Invert and Erase bits, so move in/out or proximity with the intend
316*0bb3ed71SBenjamin Tissoires        to erase.
317*0bb3ed71SBenjamin Tissoires        https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
318*0bb3ed71SBenjamin Tissoires        """
319*0bb3ed71SBenjamin Tissoires        return {
320*0bb3ed71SBenjamin Tissoires            "direct-erase": (PenState.PEN_IS_ERASING,),
321*0bb3ed71SBenjamin Tissoires            "direct-erase -> out-of-range": (
322*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
323*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_OUT_OF_RANGE,
324*0bb3ed71SBenjamin Tissoires            ),
325*0bb3ed71SBenjamin Tissoires        }
326*0bb3ed71SBenjamin Tissoires
327*0bb3ed71SBenjamin Tissoires    @staticmethod
328*0bb3ed71SBenjamin Tissoires    def broken_transitions() -> Dict[str, Tuple[PenState, ...]]:
329*0bb3ed71SBenjamin Tissoires        """Those tests are definitely not part of the Windows specification.
330*0bb3ed71SBenjamin Tissoires        However, a half broken device might export those transitions.
331*0bb3ed71SBenjamin Tissoires        For example, a pen that has the eraser button might wobble between
332*0bb3ed71SBenjamin Tissoires        touching and erasing if the tablet doesn't enforce the Windows
333*0bb3ed71SBenjamin Tissoires        state machine."""
334*0bb3ed71SBenjamin Tissoires        return {
335*0bb3ed71SBenjamin Tissoires            "in-range -> touch -> erase -> hover-erase": (
336*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
337*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
338*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
339*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
340*0bb3ed71SBenjamin Tissoires            ),
341*0bb3ed71SBenjamin Tissoires            "in-range -> erase -> hover-erase": (
342*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
343*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
344*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
345*0bb3ed71SBenjamin Tissoires            ),
346*0bb3ed71SBenjamin Tissoires            "hover-erase -> erase -> touch -> in-range": (
347*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
348*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
349*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
350*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
351*0bb3ed71SBenjamin Tissoires            ),
352*0bb3ed71SBenjamin Tissoires            "hover-erase -> touch -> in-range": (
353*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
354*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
355*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_RANGE,
356*0bb3ed71SBenjamin Tissoires            ),
357*0bb3ed71SBenjamin Tissoires            "touch -> erase -> touch -> erase": (
358*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
359*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
360*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_IN_CONTACT,
361*0bb3ed71SBenjamin Tissoires                PenState.PEN_IS_ERASING,
362*0bb3ed71SBenjamin Tissoires            ),
363*0bb3ed71SBenjamin Tissoires        }
364*0bb3ed71SBenjamin Tissoires
365*0bb3ed71SBenjamin Tissoires
366*0bb3ed71SBenjamin Tissoiresclass PenDigitizer(base.UHIDTestDevice):
367*0bb3ed71SBenjamin Tissoires    def __init__(
368*0bb3ed71SBenjamin Tissoires        self,
369*0bb3ed71SBenjamin Tissoires        name,
370*0bb3ed71SBenjamin Tissoires        rdesc_str=None,
371*0bb3ed71SBenjamin Tissoires        rdesc=None,
372*0bb3ed71SBenjamin Tissoires        application="Pen",
373*0bb3ed71SBenjamin Tissoires        physical="Stylus",
374*0bb3ed71SBenjamin Tissoires        input_info=(BusType.USB, 1, 2),
375*0bb3ed71SBenjamin Tissoires        evdev_name_suffix=None,
376*0bb3ed71SBenjamin Tissoires    ):
377*0bb3ed71SBenjamin Tissoires        super().__init__(name, application, rdesc_str, rdesc, input_info)
378*0bb3ed71SBenjamin Tissoires        self.physical = physical
379*0bb3ed71SBenjamin Tissoires        self.cur_application = application
380*0bb3ed71SBenjamin Tissoires        if evdev_name_suffix is not None:
381*0bb3ed71SBenjamin Tissoires            self.name += evdev_name_suffix
382*0bb3ed71SBenjamin Tissoires
383*0bb3ed71SBenjamin Tissoires        self.fields = []
384*0bb3ed71SBenjamin Tissoires        for r in self.parsed_rdesc.input_reports.values():
385*0bb3ed71SBenjamin Tissoires            if r.application_name == self.application:
386*0bb3ed71SBenjamin Tissoires                physicals = [f.physical_name for f in r]
387*0bb3ed71SBenjamin Tissoires                if self.physical not in physicals and None not in physicals:
388*0bb3ed71SBenjamin Tissoires                    continue
389*0bb3ed71SBenjamin Tissoires                self.fields = [f.usage_name for f in r]
390*0bb3ed71SBenjamin Tissoires
391*0bb3ed71SBenjamin Tissoires    def event(self, pen):
392*0bb3ed71SBenjamin Tissoires        rs = []
393*0bb3ed71SBenjamin Tissoires        r = self.create_report(application=self.cur_application, data=pen)
394*0bb3ed71SBenjamin Tissoires        self.call_input_event(r)
395*0bb3ed71SBenjamin Tissoires        rs.append(r)
396*0bb3ed71SBenjamin Tissoires        return rs
397*0bb3ed71SBenjamin Tissoires
398*0bb3ed71SBenjamin Tissoires    def get_report(self, req, rnum, rtype):
399*0bb3ed71SBenjamin Tissoires        if rtype != self.UHID_FEATURE_REPORT:
400*0bb3ed71SBenjamin Tissoires            return (1, [])
401*0bb3ed71SBenjamin Tissoires
402*0bb3ed71SBenjamin Tissoires        rdesc = None
403*0bb3ed71SBenjamin Tissoires        for v in self.parsed_rdesc.feature_reports.values():
404*0bb3ed71SBenjamin Tissoires            if v.report_ID == rnum:
405*0bb3ed71SBenjamin Tissoires                rdesc = v
406*0bb3ed71SBenjamin Tissoires
407*0bb3ed71SBenjamin Tissoires        if rdesc is None:
408*0bb3ed71SBenjamin Tissoires            return (1, [])
409*0bb3ed71SBenjamin Tissoires
410*0bb3ed71SBenjamin Tissoires        return (1, [])
411*0bb3ed71SBenjamin Tissoires
412*0bb3ed71SBenjamin Tissoires    def set_report(self, req, rnum, rtype, data):
413*0bb3ed71SBenjamin Tissoires        if rtype != self.UHID_FEATURE_REPORT:
414*0bb3ed71SBenjamin Tissoires            return 1
415*0bb3ed71SBenjamin Tissoires
416*0bb3ed71SBenjamin Tissoires        rdesc = None
417*0bb3ed71SBenjamin Tissoires        for v in self.parsed_rdesc.feature_reports.values():
418*0bb3ed71SBenjamin Tissoires            if v.report_ID == rnum:
419*0bb3ed71SBenjamin Tissoires                rdesc = v
420*0bb3ed71SBenjamin Tissoires
421*0bb3ed71SBenjamin Tissoires        if rdesc is None:
422*0bb3ed71SBenjamin Tissoires            return 1
423*0bb3ed71SBenjamin Tissoires
424*0bb3ed71SBenjamin Tissoires        return 1
425*0bb3ed71SBenjamin Tissoires
426*0bb3ed71SBenjamin Tissoires
427*0bb3ed71SBenjamin Tissoiresclass BaseTest:
428*0bb3ed71SBenjamin Tissoires    class TestTablet(base.BaseTestCase.TestUhid):
429*0bb3ed71SBenjamin Tissoires        def create_device(self):
430*0bb3ed71SBenjamin Tissoires            raise Exception("please reimplement me in subclasses")
431*0bb3ed71SBenjamin Tissoires
432*0bb3ed71SBenjamin Tissoires        def post(self, uhdev, pen):
433*0bb3ed71SBenjamin Tissoires            r = uhdev.event(pen)
434*0bb3ed71SBenjamin Tissoires            events = uhdev.next_sync_events()
435*0bb3ed71SBenjamin Tissoires            self.debug_reports(r, uhdev, events)
436*0bb3ed71SBenjamin Tissoires            return events
437*0bb3ed71SBenjamin Tissoires
438*0bb3ed71SBenjamin Tissoires        def validate_transitions(self, from_state, pen, evdev, events):
439*0bb3ed71SBenjamin Tissoires            # check that the final state is correct
440*0bb3ed71SBenjamin Tissoires            pen.assert_expected_input_events(evdev)
441*0bb3ed71SBenjamin Tissoires
442*0bb3ed71SBenjamin Tissoires            # check that the transitions are valid
443*0bb3ed71SBenjamin Tissoires            sync_events = []
444*0bb3ed71SBenjamin Tissoires            while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:
445*0bb3ed71SBenjamin Tissoires                # split the first EV_SYN from the list
446*0bb3ed71SBenjamin Tissoires                idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))
447*0bb3ed71SBenjamin Tissoires                sync_events = events[:idx]
448*0bb3ed71SBenjamin Tissoires                events = events[idx + 1 :]
449*0bb3ed71SBenjamin Tissoires
450*0bb3ed71SBenjamin Tissoires                # now check for a valid transition
451*0bb3ed71SBenjamin Tissoires                from_state = from_state.apply(sync_events)
452*0bb3ed71SBenjamin Tissoires
453*0bb3ed71SBenjamin Tissoires            if events:
454*0bb3ed71SBenjamin Tissoires                from_state = from_state.apply(sync_events)
455*0bb3ed71SBenjamin Tissoires
456*0bb3ed71SBenjamin Tissoires        def _test_states(self, state_list, scribble):
457*0bb3ed71SBenjamin Tissoires            """Internal method to test against a list of
458*0bb3ed71SBenjamin Tissoires            transition between states.
459*0bb3ed71SBenjamin Tissoires            state_list is a list of PenState objects
460*0bb3ed71SBenjamin Tissoires            scribble is a boolean which tells if we need
461*0bb3ed71SBenjamin Tissoires            to wobble a little the X,Y coordinates of the pen
462*0bb3ed71SBenjamin Tissoires            between each state transition."""
463*0bb3ed71SBenjamin Tissoires            uhdev = self.uhdev
464*0bb3ed71SBenjamin Tissoires            evdev = uhdev.get_evdev()
465*0bb3ed71SBenjamin Tissoires
466*0bb3ed71SBenjamin Tissoires            cur_state = PenState.PEN_IS_OUT_OF_RANGE
467*0bb3ed71SBenjamin Tissoires
468*0bb3ed71SBenjamin Tissoires            p = Pen(50, 60)
469*0bb3ed71SBenjamin Tissoires            p.move_to(PenState.PEN_IS_OUT_OF_RANGE)
470*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
471*0bb3ed71SBenjamin Tissoires            self.validate_transitions(cur_state, p, evdev, events)
472*0bb3ed71SBenjamin Tissoires
473*0bb3ed71SBenjamin Tissoires            cur_state = p.current_state
474*0bb3ed71SBenjamin Tissoires
475*0bb3ed71SBenjamin Tissoires            for state in state_list:
476*0bb3ed71SBenjamin Tissoires                if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:
477*0bb3ed71SBenjamin Tissoires                    p.x += 1
478*0bb3ed71SBenjamin Tissoires                    p.y -= 1
479*0bb3ed71SBenjamin Tissoires                    events = self.post(uhdev, p)
480*0bb3ed71SBenjamin Tissoires                    self.validate_transitions(cur_state, p, evdev, events)
481*0bb3ed71SBenjamin Tissoires                    assert len(events) >= 3  # X, Y, SYN
482*0bb3ed71SBenjamin Tissoires                p.move_to(state)
483*0bb3ed71SBenjamin Tissoires                if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
484*0bb3ed71SBenjamin Tissoires                    p.x += 1
485*0bb3ed71SBenjamin Tissoires                    p.y -= 1
486*0bb3ed71SBenjamin Tissoires                events = self.post(uhdev, p)
487*0bb3ed71SBenjamin Tissoires                self.validate_transitions(cur_state, p, evdev, events)
488*0bb3ed71SBenjamin Tissoires                cur_state = p.current_state
489*0bb3ed71SBenjamin Tissoires
490*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
491*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize(
492*0bb3ed71SBenjamin Tissoires            "state_list",
493*0bb3ed71SBenjamin Tissoires            [pytest.param(v, id=k) for k, v in Pen.legal_transitions().items()],
494*0bb3ed71SBenjamin Tissoires        )
495*0bb3ed71SBenjamin Tissoires        def test_valid_pen_states(self, state_list, scribble):
496*0bb3ed71SBenjamin Tissoires            """This is the first half of the Windows Pen Implementation state machine:
497*0bb3ed71SBenjamin Tissoires            we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
498*0bb3ed71SBenjamin Tissoires            https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
499*0bb3ed71SBenjamin Tissoires            """
500*0bb3ed71SBenjamin Tissoires            self._test_states(state_list, scribble)
501*0bb3ed71SBenjamin Tissoires
502*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
503*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize(
504*0bb3ed71SBenjamin Tissoires            "state_list",
505*0bb3ed71SBenjamin Tissoires            [pytest.param(v, id=k) for k, v in Pen.tolerated_transitions().items()],
506*0bb3ed71SBenjamin Tissoires        )
507*0bb3ed71SBenjamin Tissoires        def test_tolerated_pen_states(self, state_list, scribble):
508*0bb3ed71SBenjamin Tissoires            """This is not adhering to the Windows Pen Implementation state machine
509*0bb3ed71SBenjamin Tissoires            but we should expect the kernel to behave properly, mostly for historical
510*0bb3ed71SBenjamin Tissoires            reasons."""
511*0bb3ed71SBenjamin Tissoires            self._test_states(state_list, scribble)
512*0bb3ed71SBenjamin Tissoires
513*0bb3ed71SBenjamin Tissoires        @pytest.mark.skip_if_uhdev(
514*0bb3ed71SBenjamin Tissoires            lambda uhdev: "Invert" not in uhdev.fields,
515*0bb3ed71SBenjamin Tissoires            "Device not compatible, missing Invert usage",
516*0bb3ed71SBenjamin Tissoires        )
517*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
518*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize(
519*0bb3ed71SBenjamin Tissoires            "state_list",
520*0bb3ed71SBenjamin Tissoires            [
521*0bb3ed71SBenjamin Tissoires                pytest.param(v, id=k)
522*0bb3ed71SBenjamin Tissoires                for k, v in Pen.legal_transitions_with_invert().items()
523*0bb3ed71SBenjamin Tissoires            ],
524*0bb3ed71SBenjamin Tissoires        )
525*0bb3ed71SBenjamin Tissoires        def test_valid_invert_pen_states(self, state_list, scribble):
526*0bb3ed71SBenjamin Tissoires            """This is the second half of the Windows Pen Implementation state machine:
527*0bb3ed71SBenjamin Tissoires            we now have Invert and Erase bits, so move in/out or proximity with the intend
528*0bb3ed71SBenjamin Tissoires            to erase.
529*0bb3ed71SBenjamin Tissoires            https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
530*0bb3ed71SBenjamin Tissoires            """
531*0bb3ed71SBenjamin Tissoires            self._test_states(state_list, scribble)
532*0bb3ed71SBenjamin Tissoires
533*0bb3ed71SBenjamin Tissoires        @pytest.mark.skip_if_uhdev(
534*0bb3ed71SBenjamin Tissoires            lambda uhdev: "Invert" not in uhdev.fields,
535*0bb3ed71SBenjamin Tissoires            "Device not compatible, missing Invert usage",
536*0bb3ed71SBenjamin Tissoires        )
537*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
538*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize(
539*0bb3ed71SBenjamin Tissoires            "state_list",
540*0bb3ed71SBenjamin Tissoires            [
541*0bb3ed71SBenjamin Tissoires                pytest.param(v, id=k)
542*0bb3ed71SBenjamin Tissoires                for k, v in Pen.tolerated_transitions_with_invert().items()
543*0bb3ed71SBenjamin Tissoires            ],
544*0bb3ed71SBenjamin Tissoires        )
545*0bb3ed71SBenjamin Tissoires        def test_tolerated_invert_pen_states(self, state_list, scribble):
546*0bb3ed71SBenjamin Tissoires            """This is the second half of the Windows Pen Implementation state machine:
547*0bb3ed71SBenjamin Tissoires            we now have Invert and Erase bits, so move in/out or proximity with the intend
548*0bb3ed71SBenjamin Tissoires            to erase.
549*0bb3ed71SBenjamin Tissoires            https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
550*0bb3ed71SBenjamin Tissoires            """
551*0bb3ed71SBenjamin Tissoires            self._test_states(state_list, scribble)
552*0bb3ed71SBenjamin Tissoires
553*0bb3ed71SBenjamin Tissoires        @pytest.mark.skip_if_uhdev(
554*0bb3ed71SBenjamin Tissoires            lambda uhdev: "Invert" not in uhdev.fields,
555*0bb3ed71SBenjamin Tissoires            "Device not compatible, missing Invert usage",
556*0bb3ed71SBenjamin Tissoires        )
557*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
558*0bb3ed71SBenjamin Tissoires        @pytest.mark.parametrize(
559*0bb3ed71SBenjamin Tissoires            "state_list",
560*0bb3ed71SBenjamin Tissoires            [pytest.param(v, id=k) for k, v in Pen.broken_transitions().items()],
561*0bb3ed71SBenjamin Tissoires        )
562*0bb3ed71SBenjamin Tissoires        def test_tolerated_broken_pen_states(self, state_list, scribble):
563*0bb3ed71SBenjamin Tissoires            """Those tests are definitely not part of the Windows specification.
564*0bb3ed71SBenjamin Tissoires            However, a half broken device might export those transitions.
565*0bb3ed71SBenjamin Tissoires            For example, a pen that has the eraser button might wobble between
566*0bb3ed71SBenjamin Tissoires            touching and erasing if the tablet doesn't enforce the Windows
567*0bb3ed71SBenjamin Tissoires            state machine."""
568*0bb3ed71SBenjamin Tissoires            self._test_states(state_list, scribble)
569*0bb3ed71SBenjamin Tissoires
570*0bb3ed71SBenjamin Tissoires        @pytest.mark.skip_if_uhdev(
571*0bb3ed71SBenjamin Tissoires            lambda uhdev: "Barrel Switch" not in uhdev.fields,
572*0bb3ed71SBenjamin Tissoires            "Device not compatible, missing Barrel Switch usage",
573*0bb3ed71SBenjamin Tissoires        )
574*0bb3ed71SBenjamin Tissoires        def test_primary_button(self):
575*0bb3ed71SBenjamin Tissoires            """Primary button (stylus) pressed, reports as pressed even while hovering.
576*0bb3ed71SBenjamin Tissoires            Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN):
577*0bb3ed71SBenjamin Tissoires              { 0, 0, 1 } <- hover
578*0bb3ed71SBenjamin Tissoires              { 0, 1, 1 } <- primary button pressed
579*0bb3ed71SBenjamin Tissoires              { 0, 1, 1 } <- liftoff
580*0bb3ed71SBenjamin Tissoires              { 0, 0, 0 } <- leaves
581*0bb3ed71SBenjamin Tissoires            """
582*0bb3ed71SBenjamin Tissoires
583*0bb3ed71SBenjamin Tissoires            uhdev = self.uhdev
584*0bb3ed71SBenjamin Tissoires            evdev = uhdev.get_evdev()
585*0bb3ed71SBenjamin Tissoires
586*0bb3ed71SBenjamin Tissoires            p = Pen(50, 60)
587*0bb3ed71SBenjamin Tissoires            p.inrange = True
588*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
589*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events
590*0bb3ed71SBenjamin Tissoires            assert evdev.value[libevdev.EV_ABS.ABS_X] == 50
591*0bb3ed71SBenjamin Tissoires            assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60
592*0bb3ed71SBenjamin Tissoires            assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS]
593*0bb3ed71SBenjamin Tissoires
594*0bb3ed71SBenjamin Tissoires            p.barrelswitch = True
595*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
596*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events
597*0bb3ed71SBenjamin Tissoires
598*0bb3ed71SBenjamin Tissoires            p.x += 1
599*0bb3ed71SBenjamin Tissoires            p.y -= 1
600*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
601*0bb3ed71SBenjamin Tissoires            assert len(events) == 3  # X, Y, SYN
602*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events
603*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events
604*0bb3ed71SBenjamin Tissoires
605*0bb3ed71SBenjamin Tissoires            p.barrelswitch = False
606*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
607*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events
608*0bb3ed71SBenjamin Tissoires
609*0bb3ed71SBenjamin Tissoires            p.inrange = False
610*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
611*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events
612*0bb3ed71SBenjamin Tissoires
613*0bb3ed71SBenjamin Tissoires        @pytest.mark.skip_if_uhdev(
614*0bb3ed71SBenjamin Tissoires            lambda uhdev: "Barrel Switch" not in uhdev.fields,
615*0bb3ed71SBenjamin Tissoires            "Device not compatible, missing Barrel Switch usage",
616*0bb3ed71SBenjamin Tissoires        )
617*0bb3ed71SBenjamin Tissoires        def test_contact_primary_button(self):
618*0bb3ed71SBenjamin Tissoires            """Primary button (stylus) pressed, reports as pressed even while hovering.
619*0bb3ed71SBenjamin Tissoires            Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN):
620*0bb3ed71SBenjamin Tissoires              { 0, 0, 1 } <- hover
621*0bb3ed71SBenjamin Tissoires              { 0, 1, 1 } <- primary button pressed
622*0bb3ed71SBenjamin Tissoires              { 1, 1, 1 } <- touch-down
623*0bb3ed71SBenjamin Tissoires              { 1, 1, 1 } <- still touch, scribble on the screen
624*0bb3ed71SBenjamin Tissoires              { 0, 1, 1 } <- liftoff
625*0bb3ed71SBenjamin Tissoires              { 0, 0, 0 } <- leaves
626*0bb3ed71SBenjamin Tissoires            """
627*0bb3ed71SBenjamin Tissoires
628*0bb3ed71SBenjamin Tissoires            uhdev = self.uhdev
629*0bb3ed71SBenjamin Tissoires            evdev = uhdev.get_evdev()
630*0bb3ed71SBenjamin Tissoires
631*0bb3ed71SBenjamin Tissoires            p = Pen(50, 60)
632*0bb3ed71SBenjamin Tissoires            p.inrange = True
633*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
634*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events
635*0bb3ed71SBenjamin Tissoires            assert evdev.value[libevdev.EV_ABS.ABS_X] == 50
636*0bb3ed71SBenjamin Tissoires            assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60
637*0bb3ed71SBenjamin Tissoires            assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS]
638*0bb3ed71SBenjamin Tissoires
639*0bb3ed71SBenjamin Tissoires            p.barrelswitch = True
640*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
641*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events
642*0bb3ed71SBenjamin Tissoires
643*0bb3ed71SBenjamin Tissoires            p.tipswitch = True
644*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
645*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
646*0bb3ed71SBenjamin Tissoires            assert evdev.value[libevdev.EV_KEY.BTN_STYLUS]
647*0bb3ed71SBenjamin Tissoires
648*0bb3ed71SBenjamin Tissoires            p.x += 1
649*0bb3ed71SBenjamin Tissoires            p.y -= 1
650*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
651*0bb3ed71SBenjamin Tissoires            assert len(events) == 3  # X, Y, SYN
652*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events
653*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events
654*0bb3ed71SBenjamin Tissoires
655*0bb3ed71SBenjamin Tissoires            p.tipswitch = False
656*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
657*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
658*0bb3ed71SBenjamin Tissoires
659*0bb3ed71SBenjamin Tissoires            p.barrelswitch = False
660*0bb3ed71SBenjamin Tissoires            p.inrange = False
661*0bb3ed71SBenjamin Tissoires            events = self.post(uhdev, p)
662*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events
663*0bb3ed71SBenjamin Tissoires            assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events
664*0bb3ed71SBenjamin Tissoires
665*0bb3ed71SBenjamin Tissoires
666*0bb3ed71SBenjamin Tissoiresclass GXTP_pen(PenDigitizer):
667*0bb3ed71SBenjamin Tissoires    def event(self, pen):
668*0bb3ed71SBenjamin Tissoires        if not hasattr(self, "prev_tip_state"):
669*0bb3ed71SBenjamin Tissoires            self.prev_tip_state = False
670*0bb3ed71SBenjamin Tissoires
671*0bb3ed71SBenjamin Tissoires        internal_pen = copy.copy(pen)
672*0bb3ed71SBenjamin Tissoires
673*0bb3ed71SBenjamin Tissoires        # bug in the controller: when the pen touches the
674*0bb3ed71SBenjamin Tissoires        # surface, in-range stays to 1, but when
675*0bb3ed71SBenjamin Tissoires        # the pen moves in-range gets reverted to 0
676*0bb3ed71SBenjamin Tissoires        if pen.tipswitch and self.prev_tip_state:
677*0bb3ed71SBenjamin Tissoires            internal_pen.inrange = False
678*0bb3ed71SBenjamin Tissoires
679*0bb3ed71SBenjamin Tissoires        self.prev_tip_state = pen.tipswitch
680*0bb3ed71SBenjamin Tissoires
681*0bb3ed71SBenjamin Tissoires        # another bug in the controller: when the pen is
682*0bb3ed71SBenjamin Tissoires        # inverted, invert is set to 1, but as soon as
683*0bb3ed71SBenjamin Tissoires        # the pen touches the surface, eraser is correctly
684*0bb3ed71SBenjamin Tissoires        # set to 1 but invert is released
685*0bb3ed71SBenjamin Tissoires        if pen.eraser:
686*0bb3ed71SBenjamin Tissoires            internal_pen.invert = False
687*0bb3ed71SBenjamin Tissoires
688*0bb3ed71SBenjamin Tissoires        return super().event(internal_pen)
689*0bb3ed71SBenjamin Tissoires
690*0bb3ed71SBenjamin Tissoires
691*0bb3ed71SBenjamin Tissoiresclass USIPen(PenDigitizer):
692*0bb3ed71SBenjamin Tissoires    pass
693*0bb3ed71SBenjamin Tissoires
694*0bb3ed71SBenjamin Tissoires
695*0bb3ed71SBenjamin Tissoires################################################################################
696*0bb3ed71SBenjamin Tissoires#
697*0bb3ed71SBenjamin Tissoires# Windows 7 compatible devices
698*0bb3ed71SBenjamin Tissoires#
699*0bb3ed71SBenjamin Tissoires################################################################################
700*0bb3ed71SBenjamin Tissoires# class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):
701*0bb3ed71SBenjamin Tissoires#     def create_device(self):
702*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test egalax-capacitive_0eef_7224',
703*0bb3ed71SBenjamin Tissoires#                             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',
704*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x0eef, 0x7224),
705*0bb3ed71SBenjamin Tissoires#                             evdev_name_suffix=' Touchscreen')
706*0bb3ed71SBenjamin Tissoires#
707*0bb3ed71SBenjamin Tissoires#
708*0bb3ed71SBenjamin Tissoires# class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):
709*0bb3ed71SBenjamin Tissoires#     def create_device(self):
710*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',
711*0bb3ed71SBenjamin Tissoires#                             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',
712*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x0eef, 0x72fa),
713*0bb3ed71SBenjamin Tissoires#                             evdev_name_suffix=' Touchscreen')
714*0bb3ed71SBenjamin Tissoires#
715*0bb3ed71SBenjamin Tissoires#
716*0bb3ed71SBenjamin Tissoires# class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):
717*0bb3ed71SBenjamin Tissoires#     def create_device(self):
718*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test egalax-capacitive_0eef_7336',
719*0bb3ed71SBenjamin Tissoires#                             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',
720*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x0eef, 0x7336),
721*0bb3ed71SBenjamin Tissoires#                             evdev_name_suffix=' Touchscreen')
722*0bb3ed71SBenjamin Tissoires#
723*0bb3ed71SBenjamin Tissoires#
724*0bb3ed71SBenjamin Tissoires# class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):
725*0bb3ed71SBenjamin Tissoires#     def create_device(self):
726*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test egalax-capacitive_0eef_7337',
727*0bb3ed71SBenjamin Tissoires#                             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',
728*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x0eef, 0x7337),
729*0bb3ed71SBenjamin Tissoires#                             evdev_name_suffix=' Touchscreen')
730*0bb3ed71SBenjamin Tissoires#
731*0bb3ed71SBenjamin Tissoires#
732*0bb3ed71SBenjamin Tissoires# class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):
733*0bb3ed71SBenjamin Tissoires#     def create_device(self):
734*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test egalax-capacitive_0eef_7349',
735*0bb3ed71SBenjamin Tissoires#                             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',
736*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x0eef, 0x7349),
737*0bb3ed71SBenjamin Tissoires#                             evdev_name_suffix=' Touchscreen')
738*0bb3ed71SBenjamin Tissoires#
739*0bb3ed71SBenjamin Tissoires#
740*0bb3ed71SBenjamin Tissoires# class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):
741*0bb3ed71SBenjamin Tissoires#     def create_device(self):
742*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',
743*0bb3ed71SBenjamin Tissoires#                             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',
744*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x0eef, 0x73f4),
745*0bb3ed71SBenjamin Tissoires#                             evdev_name_suffix=' Touchscreen')
746*0bb3ed71SBenjamin Tissoires#
747*0bb3ed71SBenjamin Tissoires#  bogus: BTN_TOOL_PEN is not emitted
748*0bb3ed71SBenjamin Tissoires# class TestIrtouch_6615_0070(BaseTest.TestTablet):
749*0bb3ed71SBenjamin Tissoires#     def create_device(self):
750*0bb3ed71SBenjamin Tissoires#         return PenDigitizer('uhid test irtouch_6615_0070',
751*0bb3ed71SBenjamin Tissoires#                             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',
752*0bb3ed71SBenjamin Tissoires#                             input_info=(BusType.USB, 0x6615, 0x0070))
753*0bb3ed71SBenjamin Tissoires
754*0bb3ed71SBenjamin Tissoires
755*0bb3ed71SBenjamin Tissoiresclass TestNexio_1870_0100(BaseTest.TestTablet):
756*0bb3ed71SBenjamin Tissoires    def create_device(self):
757*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
758*0bb3ed71SBenjamin Tissoires            "uhid test nexio_1870_0100",
759*0bb3ed71SBenjamin Tissoires            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",
760*0bb3ed71SBenjamin Tissoires            input_info=(BusType.USB, 0x1870, 0x0100),
761*0bb3ed71SBenjamin Tissoires        )
762*0bb3ed71SBenjamin Tissoires
763*0bb3ed71SBenjamin Tissoires
764*0bb3ed71SBenjamin Tissoiresclass TestNexio_1870_010d(BaseTest.TestTablet):
765*0bb3ed71SBenjamin Tissoires    def create_device(self):
766*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
767*0bb3ed71SBenjamin Tissoires            "uhid test nexio_1870_010d",
768*0bb3ed71SBenjamin Tissoires            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",
769*0bb3ed71SBenjamin Tissoires            input_info=(BusType.USB, 0x1870, 0x010D),
770*0bb3ed71SBenjamin Tissoires        )
771*0bb3ed71SBenjamin Tissoires
772*0bb3ed71SBenjamin Tissoires
773*0bb3ed71SBenjamin Tissoiresclass TestNexio_1870_0119(BaseTest.TestTablet):
774*0bb3ed71SBenjamin Tissoires    def create_device(self):
775*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
776*0bb3ed71SBenjamin Tissoires            "uhid test nexio_1870_0119",
777*0bb3ed71SBenjamin Tissoires            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",
778*0bb3ed71SBenjamin Tissoires            input_info=(BusType.USB, 0x1870, 0x0119),
779*0bb3ed71SBenjamin Tissoires        )
780*0bb3ed71SBenjamin Tissoires
781*0bb3ed71SBenjamin Tissoires
782*0bb3ed71SBenjamin Tissoires################################################################################
783*0bb3ed71SBenjamin Tissoires#
784*0bb3ed71SBenjamin Tissoires# Windows 8 compatible devices
785*0bb3ed71SBenjamin Tissoires#
786*0bb3ed71SBenjamin Tissoires################################################################################
787*0bb3ed71SBenjamin Tissoires
788*0bb3ed71SBenjamin Tissoires# bogus: application is 'undefined'
789*0bb3ed71SBenjamin Tissoires# class Testatmel_03eb_8409(BaseTest.TestTablet):
790*0bb3ed71SBenjamin Tissoires#     def create_device(self):
791*0bb3ed71SBenjamin Tissoires#         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')
792*0bb3ed71SBenjamin Tissoires
793*0bb3ed71SBenjamin Tissoires
794*0bb3ed71SBenjamin Tissoiresclass Testatmel_03eb_840b(BaseTest.TestTablet):
795*0bb3ed71SBenjamin Tissoires    def create_device(self):
796*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
797*0bb3ed71SBenjamin Tissoires            "uhid test atmel_03eb_840b",
798*0bb3ed71SBenjamin Tissoires            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",
799*0bb3ed71SBenjamin Tissoires        )
800*0bb3ed71SBenjamin Tissoires
801*0bb3ed71SBenjamin Tissoires
802*0bb3ed71SBenjamin Tissoiresclass Testn_trig_1b96_0c01(BaseTest.TestTablet):
803*0bb3ed71SBenjamin Tissoires    def create_device(self):
804*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
805*0bb3ed71SBenjamin Tissoires            "uhid test n_trig_1b96_0c01",
806*0bb3ed71SBenjamin Tissoires            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",
807*0bb3ed71SBenjamin Tissoires        )
808*0bb3ed71SBenjamin Tissoires
809*0bb3ed71SBenjamin Tissoires
810*0bb3ed71SBenjamin Tissoiresclass Testn_trig_1b96_0c03(BaseTest.TestTablet):
811*0bb3ed71SBenjamin Tissoires    def create_device(self):
812*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
813*0bb3ed71SBenjamin Tissoires            "uhid test n_trig_1b96_0c03",
814*0bb3ed71SBenjamin Tissoires            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",
815*0bb3ed71SBenjamin Tissoires        )
816*0bb3ed71SBenjamin Tissoires
817*0bb3ed71SBenjamin Tissoires
818*0bb3ed71SBenjamin Tissoiresclass Testn_trig_1b96_0f00(BaseTest.TestTablet):
819*0bb3ed71SBenjamin Tissoires    def create_device(self):
820*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
821*0bb3ed71SBenjamin Tissoires            "uhid test n_trig_1b96_0f00",
822*0bb3ed71SBenjamin Tissoires            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",
823*0bb3ed71SBenjamin Tissoires        )
824*0bb3ed71SBenjamin Tissoires
825*0bb3ed71SBenjamin Tissoires
826*0bb3ed71SBenjamin Tissoiresclass Testn_trig_1b96_0f04(BaseTest.TestTablet):
827*0bb3ed71SBenjamin Tissoires    def create_device(self):
828*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
829*0bb3ed71SBenjamin Tissoires            "uhid test n_trig_1b96_0f04",
830*0bb3ed71SBenjamin Tissoires            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",
831*0bb3ed71SBenjamin Tissoires        )
832*0bb3ed71SBenjamin Tissoires
833*0bb3ed71SBenjamin Tissoires
834*0bb3ed71SBenjamin Tissoiresclass Testn_trig_1b96_1000(BaseTest.TestTablet):
835*0bb3ed71SBenjamin Tissoires    def create_device(self):
836*0bb3ed71SBenjamin Tissoires        return PenDigitizer(
837*0bb3ed71SBenjamin Tissoires            "uhid test n_trig_1b96_1000",
838*0bb3ed71SBenjamin Tissoires            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",
839*0bb3ed71SBenjamin Tissoires        )
840*0bb3ed71SBenjamin Tissoires
841*0bb3ed71SBenjamin Tissoires
842*0bb3ed71SBenjamin Tissoiresclass TestGXTP_27c6_0113(BaseTest.TestTablet):
843*0bb3ed71SBenjamin Tissoires    def create_device(self):
844*0bb3ed71SBenjamin Tissoires        return GXTP_pen(
845*0bb3ed71SBenjamin Tissoires            "uhid test GXTP_27c6_0113",
846*0bb3ed71SBenjamin Tissoires            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",
847*0bb3ed71SBenjamin Tissoires        )
848*0bb3ed71SBenjamin Tissoires
849*0bb3ed71SBenjamin Tissoires
850*0bb3ed71SBenjamin Tissoires################################################################################
851*0bb3ed71SBenjamin Tissoires#
852*0bb3ed71SBenjamin Tissoires# Windows 8 compatible devices with USI Pen
853*0bb3ed71SBenjamin Tissoires#
854*0bb3ed71SBenjamin Tissoires################################################################################
855*0bb3ed71SBenjamin Tissoires
856*0bb3ed71SBenjamin Tissoires
857*0bb3ed71SBenjamin Tissoiresclass TestElan_04f3_2A49(BaseTest.TestTablet):
858*0bb3ed71SBenjamin Tissoires    def create_device(self):
859*0bb3ed71SBenjamin Tissoires        return USIPen(
860*0bb3ed71SBenjamin Tissoires            "uhid test Elan_04f3_2A49",
861*0bb3ed71SBenjamin Tissoires            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",
862*0bb3ed71SBenjamin Tissoires            input_info=(BusType.I2C, 0x04F3, 0x2A49),
863*0bb3ed71SBenjamin Tissoires        )
864*0bb3ed71SBenjamin Tissoires
865*0bb3ed71SBenjamin Tissoires
866*0bb3ed71SBenjamin Tissoiresclass TestGoodix_27c6_0e00(BaseTest.TestTablet):
867*0bb3ed71SBenjamin Tissoires    def create_device(self):
868*0bb3ed71SBenjamin Tissoires        return USIPen(
869*0bb3ed71SBenjamin Tissoires            "uhid test Elan_04f3_2A49",
870*0bb3ed71SBenjamin Tissoires            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",
871*0bb3ed71SBenjamin Tissoires            input_info=(BusType.I2C, 0x27C6, 0x0E00),
872*0bb3ed71SBenjamin Tissoires        )
873