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