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