Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/hid/tests/test_tablet.py
26308 views
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
from .base import HidBpf
14
import libevdev
15
import logging
16
import pytest
17
from typing import Dict, List, Optional, Tuple
18
19
logger = logging.getLogger("hidtools.test.tablet")
20
21
22
class BtnTouch(Enum):
23
"""Represents whether the BTN_TOUCH event is set to True or False"""
24
25
DOWN = True
26
UP = False
27
28
29
class ToolType(Enum):
30
PEN = libevdev.EV_KEY.BTN_TOOL_PEN
31
RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER
32
33
34
class BtnPressed(Enum):
35
"""Represents whether a button is pressed on the stylus"""
36
37
PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS
38
SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2
39
THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS3
40
41
42
class PenState(Enum):
43
"""Pen states according to Microsoft reference:
44
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
45
46
We extend it with the various buttons when we need to check them.
47
"""
48
49
PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False
50
PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False
51
PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True
52
PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False
53
PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True
54
PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False
55
PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True
56
PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False
57
PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True
58
59
def __init__(
60
self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]
61
):
62
self.touch = touch # type: ignore
63
self.tool = tool # type: ignore
64
self.button = button # type: ignore
65
66
@classmethod
67
def from_evdev(cls, evdev, test_button) -> "PenState":
68
touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
69
tool = None
70
button = False
71
if (
72
evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
73
and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
74
):
75
tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)
76
elif (
77
evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
78
and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
79
):
80
tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)
81
elif (
82
evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
83
or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
84
):
85
raise ValueError("2 tools are not allowed")
86
87
# we take only the provided button into account
88
if test_button is not None:
89
button = bool(evdev.value[test_button.value])
90
91
# the kernel tends to insert an EV_SYN once removing the tool, so
92
# the button will be released after
93
if tool is None:
94
button = False
95
96
return cls((touch, tool, button)) # type: ignore
97
98
def apply(
99
self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed
100
) -> "PenState":
101
if libevdev.EV_SYN.SYN_REPORT in events:
102
raise ValueError("EV_SYN is in the event sequence")
103
touch = self.touch
104
touch_found = False
105
tool = self.tool
106
tool_found = False
107
button = self.button
108
button_found = False
109
110
for ev in events:
111
if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):
112
if touch_found:
113
raise ValueError(f"duplicated BTN_TOUCH in {events}")
114
touch_found = True
115
touch = BtnTouch(ev.value)
116
elif ev in (
117
libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),
118
libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),
119
):
120
if tool_found:
121
raise ValueError(f"duplicated BTN_TOOL_* in {events}")
122
tool_found = True
123
tool = ToolType(ev.code) if ev.value else None
124
elif test_button is not None and ev in (test_button.value,):
125
if button_found:
126
raise ValueError(f"duplicated BTN_STYLUS* in {events}")
127
button_found = True
128
button = bool(ev.value)
129
130
# the kernel tends to insert an EV_SYN once removing the tool, so
131
# the button will be released after
132
if tool is None:
133
button = False
134
135
new_state = PenState((touch, tool, button)) # type: ignore
136
if strict:
137
assert (
138
new_state in self.valid_transitions()
139
), f"moving from {self} to {new_state} is forbidden"
140
else:
141
assert (
142
new_state in self.historically_tolerated_transitions()
143
), f"moving from {self} to {new_state} is forbidden"
144
145
return new_state
146
147
def valid_transitions(self) -> Tuple["PenState", ...]:
148
"""Following the state machine in the URL above.
149
150
Note that those transitions are from the evdev point of view, not HID"""
151
if self == PenState.PEN_IS_OUT_OF_RANGE:
152
return (
153
PenState.PEN_IS_OUT_OF_RANGE,
154
PenState.PEN_IS_IN_RANGE,
155
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
156
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
157
PenState.PEN_IS_IN_CONTACT,
158
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
159
PenState.PEN_IS_ERASING,
160
)
161
162
if self == PenState.PEN_IS_IN_RANGE:
163
return (
164
PenState.PEN_IS_IN_RANGE,
165
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
166
PenState.PEN_IS_OUT_OF_RANGE,
167
PenState.PEN_IS_IN_CONTACT,
168
)
169
170
if self == PenState.PEN_IS_IN_CONTACT:
171
return (
172
PenState.PEN_IS_IN_CONTACT,
173
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
174
PenState.PEN_IS_IN_RANGE,
175
)
176
177
if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
178
return (
179
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
180
PenState.PEN_IS_OUT_OF_RANGE,
181
PenState.PEN_IS_ERASING,
182
)
183
184
if self == PenState.PEN_IS_ERASING:
185
return (
186
PenState.PEN_IS_ERASING,
187
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
188
)
189
190
if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
191
return (
192
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
193
PenState.PEN_IS_IN_RANGE,
194
PenState.PEN_IS_OUT_OF_RANGE,
195
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
196
)
197
198
if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
199
return (
200
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
201
PenState.PEN_IS_IN_CONTACT,
202
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
203
)
204
205
return tuple()
206
207
def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:
208
"""Following the state machine in the URL above, with a couple of addition
209
for skipping the in-range state, due to historical reasons.
210
211
Note that those transitions are from the evdev point of view, not HID"""
212
if self == PenState.PEN_IS_OUT_OF_RANGE:
213
return (
214
PenState.PEN_IS_OUT_OF_RANGE,
215
PenState.PEN_IS_IN_RANGE,
216
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
217
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
218
PenState.PEN_IS_IN_CONTACT,
219
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
220
PenState.PEN_IS_ERASING,
221
)
222
223
if self == PenState.PEN_IS_IN_RANGE:
224
return (
225
PenState.PEN_IS_IN_RANGE,
226
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
227
PenState.PEN_IS_OUT_OF_RANGE,
228
PenState.PEN_IS_IN_CONTACT,
229
)
230
231
if self == PenState.PEN_IS_IN_CONTACT:
232
return (
233
PenState.PEN_IS_IN_CONTACT,
234
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
235
PenState.PEN_IS_IN_RANGE,
236
PenState.PEN_IS_OUT_OF_RANGE,
237
)
238
239
if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
240
return (
241
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
242
PenState.PEN_IS_OUT_OF_RANGE,
243
PenState.PEN_IS_ERASING,
244
)
245
246
if self == PenState.PEN_IS_ERASING:
247
return (
248
PenState.PEN_IS_ERASING,
249
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
250
PenState.PEN_IS_OUT_OF_RANGE,
251
)
252
253
if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
254
return (
255
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
256
PenState.PEN_IS_IN_RANGE,
257
PenState.PEN_IS_OUT_OF_RANGE,
258
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
259
)
260
261
if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
262
return (
263
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
264
PenState.PEN_IS_IN_CONTACT,
265
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
266
PenState.PEN_IS_OUT_OF_RANGE,
267
)
268
269
return tuple()
270
271
@staticmethod
272
def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:
273
"""This is the first half of the Windows Pen Implementation state machine:
274
we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
275
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
276
"""
277
return {
278
"in-range": (PenState.PEN_IS_IN_RANGE,),
279
"in-range -> out-of-range": (
280
PenState.PEN_IS_IN_RANGE,
281
PenState.PEN_IS_OUT_OF_RANGE,
282
),
283
"in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT),
284
"in-range -> touch -> release": (
285
PenState.PEN_IS_IN_RANGE,
286
PenState.PEN_IS_IN_CONTACT,
287
PenState.PEN_IS_IN_RANGE,
288
),
289
"in-range -> touch -> release -> out-of-range": (
290
PenState.PEN_IS_IN_RANGE,
291
PenState.PEN_IS_IN_CONTACT,
292
PenState.PEN_IS_IN_RANGE,
293
PenState.PEN_IS_OUT_OF_RANGE,
294
),
295
}
296
297
@staticmethod
298
def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
299
"""This is the second half of the Windows Pen Implementation state machine:
300
we now have Invert and Erase bits, so move in/out or proximity with the intend
301
to erase.
302
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
303
"""
304
return {
305
"hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,),
306
"hover-erasing -> out-of-range": (
307
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
308
PenState.PEN_IS_OUT_OF_RANGE,
309
),
310
"hover-erasing -> erase": (
311
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
312
PenState.PEN_IS_ERASING,
313
),
314
"hover-erasing -> erase -> release": (
315
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
316
PenState.PEN_IS_ERASING,
317
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
318
),
319
"hover-erasing -> erase -> release -> out-of-range": (
320
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
321
PenState.PEN_IS_ERASING,
322
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
323
PenState.PEN_IS_OUT_OF_RANGE,
324
),
325
"hover-erasing -> in-range": (
326
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
327
PenState.PEN_IS_IN_RANGE,
328
),
329
"in-range -> hover-erasing": (
330
PenState.PEN_IS_IN_RANGE,
331
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
332
),
333
}
334
335
@staticmethod
336
def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:
337
"""We revisit the Windows Pen Implementation state machine:
338
we now have a button.
339
"""
340
return {
341
"hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),
342
"hover-button -> out-of-range": (
343
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
344
PenState.PEN_IS_OUT_OF_RANGE,
345
),
346
"in-range -> button-press": (
347
PenState.PEN_IS_IN_RANGE,
348
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
349
),
350
"in-range -> button-press -> button-release": (
351
PenState.PEN_IS_IN_RANGE,
352
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
353
PenState.PEN_IS_IN_RANGE,
354
),
355
"in-range -> touch -> button-press -> button-release": (
356
PenState.PEN_IS_IN_RANGE,
357
PenState.PEN_IS_IN_CONTACT,
358
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
359
PenState.PEN_IS_IN_CONTACT,
360
),
361
"in-range -> touch -> button-press -> release -> button-release": (
362
PenState.PEN_IS_IN_RANGE,
363
PenState.PEN_IS_IN_CONTACT,
364
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
365
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
366
PenState.PEN_IS_IN_RANGE,
367
),
368
"in-range -> button-press -> touch -> release -> button-release": (
369
PenState.PEN_IS_IN_RANGE,
370
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
371
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
372
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
373
PenState.PEN_IS_IN_RANGE,
374
),
375
"in-range -> button-press -> touch -> button-release -> release": (
376
PenState.PEN_IS_IN_RANGE,
377
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
378
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
379
PenState.PEN_IS_IN_CONTACT,
380
PenState.PEN_IS_IN_RANGE,
381
),
382
}
383
384
@staticmethod
385
def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:
386
"""This is not adhering to the Windows Pen Implementation state machine
387
but we should expect the kernel to behave properly, mostly for historical
388
reasons."""
389
return {
390
"direct-in-contact": (PenState.PEN_IS_IN_CONTACT,),
391
"direct-in-contact -> out-of-range": (
392
PenState.PEN_IS_IN_CONTACT,
393
PenState.PEN_IS_OUT_OF_RANGE,
394
),
395
}
396
397
@staticmethod
398
def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
399
"""This is the second half of the Windows Pen Implementation state machine:
400
we now have Invert and Erase bits, so move in/out or proximity with the intend
401
to erase.
402
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
403
"""
404
return {
405
"direct-erase": (PenState.PEN_IS_ERASING,),
406
"direct-erase -> out-of-range": (
407
PenState.PEN_IS_ERASING,
408
PenState.PEN_IS_OUT_OF_RANGE,
409
),
410
}
411
412
@staticmethod
413
def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:
414
"""Those tests are definitely not part of the Windows specification.
415
However, a half broken device might export those transitions.
416
For example, a pen that has the eraser button might wobble between
417
touching and erasing if the tablet doesn't enforce the Windows
418
state machine."""
419
return {
420
"in-range -> touch -> erase -> hover-erase": (
421
PenState.PEN_IS_IN_RANGE,
422
PenState.PEN_IS_IN_CONTACT,
423
PenState.PEN_IS_ERASING,
424
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
425
),
426
"in-range -> erase -> hover-erase": (
427
PenState.PEN_IS_IN_RANGE,
428
PenState.PEN_IS_ERASING,
429
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
430
),
431
"hover-erase -> erase -> touch -> in-range": (
432
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
433
PenState.PEN_IS_ERASING,
434
PenState.PEN_IS_IN_CONTACT,
435
PenState.PEN_IS_IN_RANGE,
436
),
437
"hover-erase -> touch -> in-range": (
438
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
439
PenState.PEN_IS_IN_CONTACT,
440
PenState.PEN_IS_IN_RANGE,
441
),
442
"touch -> erase -> touch -> erase": (
443
PenState.PEN_IS_IN_CONTACT,
444
PenState.PEN_IS_ERASING,
445
PenState.PEN_IS_IN_CONTACT,
446
PenState.PEN_IS_ERASING,
447
),
448
}
449
450
451
class Pen(object):
452
def __init__(self, x, y):
453
self.x = x
454
self.y = y
455
self.tipswitch = False
456
self.tippressure = 15
457
self.azimuth = 0
458
self.inrange = False
459
self.width = 10
460
self.height = 10
461
self.barrelswitch = False
462
self.secondarybarrelswitch = False
463
self.invert = False
464
self.eraser = False
465
self.xtilt = 1
466
self.ytilt = 1
467
self.twist = 1
468
self._old_values = None
469
self.current_state = None
470
471
def restore(self):
472
if self._old_values is not None:
473
for i in [
474
"x",
475
"y",
476
"tippressure",
477
"azimuth",
478
"width",
479
"height",
480
"twist",
481
"xtilt",
482
"ytilt",
483
]:
484
setattr(self, i, getattr(self._old_values, i))
485
486
def backup(self):
487
self._old_values = copy.copy(self)
488
489
def __assert_axis(self, evdev, axis, value):
490
if (
491
axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
492
and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
493
):
494
return
495
496
assert (
497
evdev.value[axis] == value
498
), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
499
500
def assert_expected_input_events(self, evdev, button):
501
assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
502
assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
503
504
# assert no other buttons than the tested ones are set
505
buttons = [
506
BtnPressed.PRIMARY_PRESSED,
507
BtnPressed.SECONDARY_PRESSED,
508
BtnPressed.THIRD_PRESSED,
509
]
510
if button is not None:
511
buttons.remove(button)
512
for b in buttons:
513
assert evdev.value[b.value] is None or evdev.value[b.value] == False
514
515
assert self.current_state == PenState.from_evdev(evdev, button)
516
517
518
class PenDigitizer(base.UHIDTestDevice):
519
def __init__(
520
self,
521
name,
522
rdesc_str=None,
523
rdesc=None,
524
application="Pen",
525
physical="Stylus",
526
input_info=(BusType.USB, 1, 2),
527
evdev_name_suffix=None,
528
):
529
super().__init__(name, application, rdesc_str, rdesc, input_info)
530
self.physical = physical
531
self.cur_application = application
532
if evdev_name_suffix is not None:
533
self.name += evdev_name_suffix
534
535
self.fields = []
536
for r in self.parsed_rdesc.input_reports.values():
537
if r.application_name == self.application:
538
physicals = [f.physical_name for f in r]
539
if self.physical not in physicals and None not in physicals:
540
continue
541
self.fields = [f.usage_name for f in r]
542
543
def move_to(self, pen, state, button):
544
# fill in the previous values
545
if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
546
pen.restore()
547
548
print(f"\n *** pen is moving to {state} ***")
549
550
if state == PenState.PEN_IS_OUT_OF_RANGE:
551
pen.backup()
552
pen.x = 0
553
pen.y = 0
554
pen.tipswitch = False
555
pen.tippressure = 0
556
pen.azimuth = 0
557
pen.inrange = False
558
pen.width = 0
559
pen.height = 0
560
pen.invert = False
561
pen.eraser = False
562
pen.xtilt = 0
563
pen.ytilt = 0
564
pen.twist = 0
565
pen.barrelswitch = False
566
pen.secondarybarrelswitch = False
567
elif state == PenState.PEN_IS_IN_RANGE:
568
pen.tipswitch = False
569
pen.inrange = True
570
pen.invert = False
571
pen.eraser = False
572
pen.barrelswitch = False
573
pen.secondarybarrelswitch = False
574
elif state == PenState.PEN_IS_IN_CONTACT:
575
pen.tipswitch = True
576
pen.inrange = True
577
pen.invert = False
578
pen.eraser = False
579
pen.barrelswitch = False
580
pen.secondarybarrelswitch = False
581
elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
582
pen.tipswitch = False
583
pen.inrange = True
584
pen.invert = False
585
pen.eraser = False
586
assert button is not None
587
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
588
pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
589
elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
590
pen.tipswitch = True
591
pen.inrange = True
592
pen.invert = False
593
pen.eraser = False
594
assert button is not None
595
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
596
pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
597
elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
598
pen.tipswitch = False
599
pen.inrange = True
600
pen.invert = True
601
pen.eraser = False
602
pen.barrelswitch = False
603
pen.secondarybarrelswitch = False
604
elif state == PenState.PEN_IS_ERASING:
605
pen.tipswitch = False
606
pen.inrange = True
607
pen.invert = False
608
pen.eraser = True
609
pen.barrelswitch = False
610
pen.secondarybarrelswitch = False
611
612
pen.current_state = state
613
614
def event(self, pen, button):
615
rs = []
616
r = self.create_report(application=self.cur_application, data=pen)
617
self.call_input_event(r)
618
rs.append(r)
619
return rs
620
621
def get_report(self, req, rnum, rtype):
622
if rtype != self.UHID_FEATURE_REPORT:
623
return (1, [])
624
625
rdesc = None
626
for v in self.parsed_rdesc.feature_reports.values():
627
if v.report_ID == rnum:
628
rdesc = v
629
630
if rdesc is None:
631
return (1, [])
632
633
return (1, [])
634
635
def set_report(self, req, rnum, rtype, data):
636
if rtype != self.UHID_FEATURE_REPORT:
637
return 1
638
639
rdesc = None
640
for v in self.parsed_rdesc.feature_reports.values():
641
if v.report_ID == rnum:
642
rdesc = v
643
644
if rdesc is None:
645
return 1
646
647
return 1
648
649
650
class BaseTest:
651
class TestTablet(base.BaseTestCase.TestUhid):
652
def create_device(self):
653
raise Exception("please reimplement me in subclasses")
654
655
def post(self, uhdev, pen, test_button):
656
r = uhdev.event(pen, test_button)
657
events = uhdev.next_sync_events()
658
self.debug_reports(r, uhdev, events)
659
return events
660
661
def validate_transitions(
662
self, from_state, pen, evdev, events, allow_intermediate_states, button
663
):
664
# check that the final state is correct
665
pen.assert_expected_input_events(evdev, button)
666
667
state = from_state
668
669
# check that the transitions are valid
670
sync_events = []
671
while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:
672
# split the first EV_SYN from the list
673
idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))
674
sync_events = events[:idx]
675
events = events[idx + 1 :]
676
677
# now check for a valid transition
678
state = state.apply(sync_events, not allow_intermediate_states, button)
679
680
if events:
681
state = state.apply(sync_events, not allow_intermediate_states, button)
682
683
def _test_states(
684
self, state_list, scribble, allow_intermediate_states, button=None
685
):
686
"""Internal method to test against a list of
687
transition between states.
688
state_list is a list of PenState objects
689
scribble is a boolean which tells if we need
690
to wobble a little the X,Y coordinates of the pen
691
between each state transition."""
692
uhdev = self.uhdev
693
evdev = uhdev.get_evdev()
694
695
cur_state = PenState.PEN_IS_OUT_OF_RANGE
696
697
p = Pen(50, 60)
698
uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)
699
events = self.post(uhdev, p, button)
700
self.validate_transitions(
701
cur_state, p, evdev, events, allow_intermediate_states, button
702
)
703
704
cur_state = p.current_state
705
706
for state in state_list:
707
if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:
708
p.x += 1
709
p.y -= 1
710
events = self.post(uhdev, p, button)
711
self.validate_transitions(
712
cur_state, p, evdev, events, allow_intermediate_states, button
713
)
714
assert len(events) >= 3 # X, Y, SYN
715
uhdev.move_to(p, state, button)
716
if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
717
p.x += 1
718
p.y -= 1
719
events = self.post(uhdev, p, button)
720
self.validate_transitions(
721
cur_state, p, evdev, events, allow_intermediate_states, button
722
)
723
cur_state = p.current_state
724
725
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
726
@pytest.mark.parametrize(
727
"state_list",
728
[pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
729
)
730
def test_valid_pen_states(self, state_list, scribble):
731
"""This is the first half of the Windows Pen Implementation state machine:
732
we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
733
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
734
"""
735
self._test_states(state_list, scribble, allow_intermediate_states=False)
736
737
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
738
@pytest.mark.parametrize(
739
"state_list",
740
[
741
pytest.param(v, id=k)
742
for k, v in PenState.tolerated_transitions().items()
743
],
744
)
745
def test_tolerated_pen_states(self, state_list, scribble):
746
"""This is not adhering to the Windows Pen Implementation state machine
747
but we should expect the kernel to behave properly, mostly for historical
748
reasons."""
749
self._test_states(state_list, scribble, allow_intermediate_states=True)
750
751
@pytest.mark.skip_if_uhdev(
752
lambda uhdev: "Barrel Switch" not in uhdev.fields,
753
"Device not compatible, missing Barrel Switch usage",
754
)
755
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
756
@pytest.mark.parametrize(
757
"state_list",
758
[
759
pytest.param(v, id=k)
760
for k, v in PenState.legal_transitions_with_button().items()
761
],
762
)
763
def test_valid_primary_button_pen_states(self, state_list, scribble):
764
"""Rework the transition state machine by adding the primary button."""
765
self._test_states(
766
state_list,
767
scribble,
768
allow_intermediate_states=False,
769
button=BtnPressed.PRIMARY_PRESSED,
770
)
771
772
@pytest.mark.skip_if_uhdev(
773
lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,
774
"Device not compatible, missing Secondary Barrel Switch usage",
775
)
776
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
777
@pytest.mark.parametrize(
778
"state_list",
779
[
780
pytest.param(v, id=k)
781
for k, v in PenState.legal_transitions_with_button().items()
782
],
783
)
784
def test_valid_secondary_button_pen_states(self, state_list, scribble):
785
"""Rework the transition state machine by adding the secondary button."""
786
self._test_states(
787
state_list,
788
scribble,
789
allow_intermediate_states=False,
790
button=BtnPressed.SECONDARY_PRESSED,
791
)
792
793
@pytest.mark.skip_if_uhdev(
794
lambda uhdev: "Third Barrel Switch" not in uhdev.fields,
795
"Device not compatible, missing Third Barrel Switch usage",
796
)
797
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
798
@pytest.mark.parametrize(
799
"state_list",
800
[
801
pytest.param(v, id=k)
802
for k, v in PenState.legal_transitions_with_button().items()
803
],
804
)
805
def test_valid_third_button_pen_states(self, state_list, scribble):
806
"""Rework the transition state machine by adding the secondary button."""
807
self._test_states(
808
state_list,
809
scribble,
810
allow_intermediate_states=False,
811
button=BtnPressed.THIRD_PRESSED,
812
)
813
814
@pytest.mark.skip_if_uhdev(
815
lambda uhdev: "Invert" not in uhdev.fields,
816
"Device not compatible, missing Invert usage",
817
)
818
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
819
@pytest.mark.parametrize(
820
"state_list",
821
[
822
pytest.param(v, id=k)
823
for k, v in PenState.legal_transitions_with_invert().items()
824
],
825
)
826
def test_valid_invert_pen_states(self, state_list, scribble):
827
"""This is the second half of the Windows Pen Implementation state machine:
828
we now have Invert and Erase bits, so move in/out or proximity with the intend
829
to erase.
830
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
831
"""
832
self._test_states(state_list, scribble, allow_intermediate_states=False)
833
834
@pytest.mark.skip_if_uhdev(
835
lambda uhdev: "Invert" not in uhdev.fields,
836
"Device not compatible, missing Invert usage",
837
)
838
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
839
@pytest.mark.parametrize(
840
"state_list",
841
[
842
pytest.param(v, id=k)
843
for k, v in PenState.tolerated_transitions_with_invert().items()
844
],
845
)
846
def test_tolerated_invert_pen_states(self, state_list, scribble):
847
"""This is the second half of the Windows Pen Implementation state machine:
848
we now have Invert and Erase bits, so move in/out or proximity with the intend
849
to erase.
850
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
851
"""
852
self._test_states(state_list, scribble, allow_intermediate_states=True)
853
854
@pytest.mark.skip_if_uhdev(
855
lambda uhdev: "Invert" not in uhdev.fields,
856
"Device not compatible, missing Invert usage",
857
)
858
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
859
@pytest.mark.parametrize(
860
"state_list",
861
[pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],
862
)
863
def test_tolerated_broken_pen_states(self, state_list, scribble):
864
"""Those tests are definitely not part of the Windows specification.
865
However, a half broken device might export those transitions.
866
For example, a pen that has the eraser button might wobble between
867
touching and erasing if the tablet doesn't enforce the Windows
868
state machine."""
869
self._test_states(state_list, scribble, allow_intermediate_states=True)
870
871
872
class GXTP_pen(PenDigitizer):
873
def event(self, pen, test_button):
874
if not hasattr(self, "prev_tip_state"):
875
self.prev_tip_state = False
876
877
internal_pen = copy.copy(pen)
878
879
# bug in the controller: when the pen touches the
880
# surface, in-range stays to 1, but when
881
# the pen moves in-range gets reverted to 0
882
if pen.tipswitch and self.prev_tip_state:
883
internal_pen.inrange = False
884
885
self.prev_tip_state = pen.tipswitch
886
887
# another bug in the controller: when the pen is
888
# inverted, invert is set to 1, but as soon as
889
# the pen touches the surface, eraser is correctly
890
# set to 1 but invert is released
891
if pen.eraser:
892
internal_pen.invert = False
893
894
return super().event(internal_pen, test_button)
895
896
897
class USIPen(PenDigitizer):
898
pass
899
900
901
class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):
902
"""
903
Pen with two buttons and a rubber end, but which reports
904
the second button as an eraser
905
"""
906
907
def __init__(
908
self,
909
name,
910
rdesc_str=None,
911
rdesc=None,
912
application="Pen",
913
physical="Stylus",
914
input_info=(BusType.USB, 0x28BD, 0x095B),
915
evdev_name_suffix=None,
916
):
917
super().__init__(
918
name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
919
)
920
self.fields.append("Secondary Barrel Switch")
921
922
def move_to(self, pen, state, button):
923
# fill in the previous values
924
if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
925
pen.restore()
926
927
print(f"\n *** pen is moving to {state} ***")
928
929
if state == PenState.PEN_IS_OUT_OF_RANGE:
930
pen.backup()
931
pen.x = 0
932
pen.y = 0
933
pen.tipswitch = False
934
pen.tippressure = 0
935
pen.azimuth = 0
936
pen.inrange = False
937
pen.width = 0
938
pen.height = 0
939
pen.invert = False
940
pen.eraser = False
941
pen.xtilt = 0
942
pen.ytilt = 0
943
pen.twist = 0
944
pen.barrelswitch = False
945
elif state == PenState.PEN_IS_IN_RANGE:
946
pen.tipswitch = False
947
pen.inrange = True
948
pen.invert = False
949
pen.eraser = False
950
pen.barrelswitch = False
951
elif state == PenState.PEN_IS_IN_CONTACT:
952
pen.tipswitch = True
953
pen.inrange = True
954
pen.invert = False
955
pen.eraser = False
956
pen.barrelswitch = False
957
elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
958
pen.tipswitch = False
959
pen.inrange = True
960
pen.invert = False
961
assert button is not None
962
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
963
pen.eraser = button == BtnPressed.SECONDARY_PRESSED
964
elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
965
pen.tipswitch = True
966
pen.inrange = True
967
pen.invert = False
968
assert button is not None
969
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
970
pen.eraser = button == BtnPressed.SECONDARY_PRESSED
971
elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
972
pen.tipswitch = False
973
pen.inrange = True
974
pen.invert = True
975
pen.eraser = False
976
pen.barrelswitch = False
977
elif state == PenState.PEN_IS_ERASING:
978
pen.tipswitch = True
979
pen.inrange = True
980
pen.invert = True
981
pen.eraser = False
982
pen.barrelswitch = False
983
984
pen.current_state = state
985
986
def event(self, pen, test_button):
987
import math
988
989
pen_copy = copy.copy(pen)
990
width = 13.567
991
height = 8.480
992
tip_height = 0.055677699
993
hx = tip_height * (32767 / width)
994
hy = tip_height * (32767 / height)
995
if pen_copy.xtilt != 0:
996
pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))
997
if pen_copy.ytilt != 0:
998
pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))
999
1000
return super().event(pen_copy, test_button)
1001
1002
1003
class XPPen_Artist24_28bd_093a(PenDigitizer):
1004
"""
1005
Pen that reports secondary barrel switch through eraser
1006
"""
1007
1008
def __init__(
1009
self,
1010
name,
1011
rdesc_str=None,
1012
rdesc=None,
1013
application="Pen",
1014
physical="Stylus",
1015
input_info=(BusType.USB, 0x28BD, 0x093A),
1016
evdev_name_suffix=None,
1017
):
1018
super().__init__(
1019
name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1020
)
1021
self.fields.append("Secondary Barrel Switch")
1022
self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1023
1024
def move_to(self, pen, state, button, debug=True):
1025
# fill in the previous values
1026
if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1027
pen.restore()
1028
1029
if debug:
1030
print(f"\n *** pen is moving to {state} ***")
1031
1032
if state == PenState.PEN_IS_OUT_OF_RANGE:
1033
pen.backup()
1034
pen.tipswitch = False
1035
pen.tippressure = 0
1036
pen.azimuth = 0
1037
pen.inrange = False
1038
pen.width = 0
1039
pen.height = 0
1040
pen.invert = False
1041
pen.eraser = False
1042
pen.xtilt = 0
1043
pen.ytilt = 0
1044
pen.twist = 0
1045
pen.barrelswitch = False
1046
elif state == PenState.PEN_IS_IN_RANGE:
1047
pen.tipswitch = False
1048
pen.inrange = True
1049
pen.invert = False
1050
pen.eraser = False
1051
pen.barrelswitch = False
1052
elif state == PenState.PEN_IS_IN_CONTACT:
1053
pen.tipswitch = True
1054
pen.inrange = True
1055
pen.invert = False
1056
pen.eraser = False
1057
pen.barrelswitch = False
1058
elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1059
pen.tipswitch = False
1060
pen.inrange = True
1061
pen.invert = False
1062
assert button is not None
1063
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1064
pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1065
elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1066
pen.tipswitch = True
1067
pen.inrange = True
1068
pen.invert = False
1069
assert button is not None
1070
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1071
pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1072
1073
pen.current_state = state
1074
1075
def send_intermediate_state(self, pen, state, button):
1076
intermediate_pen = copy.copy(pen)
1077
self.move_to(intermediate_pen, state, button, debug=False)
1078
return super().event(intermediate_pen, button)
1079
1080
def event(self, pen, button):
1081
rs = []
1082
1083
# the pen reliably sends in-range events in a normal case (non emulation of eraser mode)
1084
if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1085
if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1086
rs.extend(
1087
self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1088
)
1089
1090
if button == BtnPressed.SECONDARY_PRESSED:
1091
if self.previous_state == PenState.PEN_IS_IN_RANGE:
1092
if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1093
rs.extend(
1094
self.send_intermediate_state(
1095
pen, PenState.PEN_IS_OUT_OF_RANGE, button
1096
)
1097
)
1098
1099
if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1100
if pen.current_state == PenState.PEN_IS_IN_RANGE:
1101
rs.extend(
1102
self.send_intermediate_state(
1103
pen, PenState.PEN_IS_OUT_OF_RANGE, button
1104
)
1105
)
1106
1107
if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1108
if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1109
rs.extend(
1110
self.send_intermediate_state(
1111
pen, PenState.PEN_IS_OUT_OF_RANGE, button
1112
)
1113
)
1114
rs.extend(
1115
self.send_intermediate_state(
1116
pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button
1117
)
1118
)
1119
1120
if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1121
if pen.current_state == PenState.PEN_IS_IN_CONTACT:
1122
rs.extend(
1123
self.send_intermediate_state(
1124
pen, PenState.PEN_IS_OUT_OF_RANGE, button
1125
)
1126
)
1127
rs.extend(
1128
self.send_intermediate_state(
1129
pen, PenState.PEN_IS_IN_RANGE, button
1130
)
1131
)
1132
1133
rs.extend(super().event(pen, button))
1134
self.previous_state = pen.current_state
1135
return rs
1136
1137
1138
class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):
1139
"""
1140
Pen that reports secondary barrel switch through secondary TipSwtich
1141
and 3rd button through Invert
1142
"""
1143
1144
def __init__(
1145
self,
1146
name,
1147
rdesc_str=None,
1148
rdesc=None,
1149
application="Stylus",
1150
physical=None,
1151
input_info=(BusType.USB, 0x256C, 0x006B),
1152
evdev_name_suffix=None,
1153
):
1154
super().__init__(
1155
name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1156
)
1157
self.fields.append("Secondary Barrel Switch")
1158
self.fields.append("Third Barrel Switch")
1159
self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1160
1161
def move_to(self, pen, state, button, debug=True):
1162
# fill in the previous values
1163
if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1164
pen.restore()
1165
1166
if debug:
1167
print(f"\n *** pen is moving to {state} ***")
1168
1169
if state == PenState.PEN_IS_OUT_OF_RANGE:
1170
pen.backup()
1171
pen.tipswitch = False
1172
pen.tippressure = 0
1173
pen.azimuth = 0
1174
pen.inrange = False
1175
pen.width = 0
1176
pen.height = 0
1177
pen.invert = False
1178
pen.eraser = False
1179
pen.xtilt = 0
1180
pen.ytilt = 0
1181
pen.twist = 0
1182
pen.barrelswitch = False
1183
pen.secondarytipswitch = False
1184
elif state == PenState.PEN_IS_IN_RANGE:
1185
pen.tipswitch = False
1186
pen.inrange = True
1187
pen.invert = False
1188
pen.eraser = False
1189
pen.barrelswitch = False
1190
pen.secondarytipswitch = False
1191
elif state == PenState.PEN_IS_IN_CONTACT:
1192
pen.tipswitch = True
1193
pen.inrange = True
1194
pen.invert = False
1195
pen.eraser = False
1196
pen.barrelswitch = False
1197
pen.secondarytipswitch = False
1198
elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1199
pen.tipswitch = False
1200
pen.inrange = True
1201
pen.eraser = False
1202
assert button is not None
1203
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1204
pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1205
pen.invert = button == BtnPressed.THIRD_PRESSED
1206
elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1207
pen.tipswitch = True
1208
pen.inrange = True
1209
pen.eraser = False
1210
assert button is not None
1211
pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1212
pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1213
pen.invert = button == BtnPressed.THIRD_PRESSED
1214
elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
1215
pen.tipswitch = False
1216
pen.inrange = True
1217
pen.invert = True
1218
pen.eraser = False
1219
pen.barrelswitch = False
1220
pen.secondarytipswitch = False
1221
elif state == PenState.PEN_IS_ERASING:
1222
pen.tipswitch = False
1223
pen.inrange = True
1224
pen.invert = False
1225
pen.eraser = True
1226
pen.barrelswitch = False
1227
pen.secondarytipswitch = False
1228
1229
pen.current_state = state
1230
1231
def call_input_event(self, report):
1232
if report[0] == 0x0A:
1233
# ensures the original second Eraser usage is null
1234
report[1] &= 0xDF
1235
1236
# ensures the original last bit is equal to bit 6 (In Range)
1237
if report[1] & 0x40:
1238
report[1] |= 0x80
1239
1240
super().call_input_event(report)
1241
1242
def send_intermediate_state(self, pen, state, test_button):
1243
intermediate_pen = copy.copy(pen)
1244
self.move_to(intermediate_pen, state, test_button, debug=False)
1245
return super().event(intermediate_pen, test_button)
1246
1247
def event(self, pen, button):
1248
rs = []
1249
1250
# it's not possible to go between eraser mode or not without
1251
# going out-of-prox: the eraser mode is activated by presenting
1252
# the tail of the pen
1253
if self.previous_state in (
1254
PenState.PEN_IS_IN_RANGE,
1255
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1256
PenState.PEN_IS_IN_CONTACT,
1257
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1258
) and pen.current_state in (
1259
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1260
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1261
PenState.PEN_IS_ERASING,
1262
PenState.PEN_IS_ERASING_WITH_BUTTON,
1263
):
1264
rs.extend(
1265
self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1266
)
1267
1268
# same than above except from eraser to normal
1269
if self.previous_state in (
1270
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1271
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1272
PenState.PEN_IS_ERASING,
1273
PenState.PEN_IS_ERASING_WITH_BUTTON,
1274
) and pen.current_state in (
1275
PenState.PEN_IS_IN_RANGE,
1276
PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1277
PenState.PEN_IS_IN_CONTACT,
1278
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1279
):
1280
rs.extend(
1281
self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1282
)
1283
1284
if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:
1285
if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1286
rs.extend(
1287
self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1288
)
1289
1290
rs.extend(super().event(pen, button))
1291
self.previous_state = pen.current_state
1292
return rs
1293
1294
1295
################################################################################
1296
#
1297
# Windows 7 compatible devices
1298
#
1299
################################################################################
1300
# class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):
1301
# def create_device(self):
1302
# return PenDigitizer('uhid test egalax-capacitive_0eef_7224',
1303
# 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',
1304
# input_info=(BusType.USB, 0x0eef, 0x7224),
1305
# evdev_name_suffix=' Touchscreen')
1306
#
1307
#
1308
# class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):
1309
# def create_device(self):
1310
# return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',
1311
# 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',
1312
# input_info=(BusType.USB, 0x0eef, 0x72fa),
1313
# evdev_name_suffix=' Touchscreen')
1314
#
1315
#
1316
# class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):
1317
# def create_device(self):
1318
# return PenDigitizer('uhid test egalax-capacitive_0eef_7336',
1319
# 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',
1320
# input_info=(BusType.USB, 0x0eef, 0x7336),
1321
# evdev_name_suffix=' Touchscreen')
1322
#
1323
#
1324
# class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):
1325
# def create_device(self):
1326
# return PenDigitizer('uhid test egalax-capacitive_0eef_7337',
1327
# 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',
1328
# input_info=(BusType.USB, 0x0eef, 0x7337),
1329
# evdev_name_suffix=' Touchscreen')
1330
#
1331
#
1332
# class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):
1333
# def create_device(self):
1334
# return PenDigitizer('uhid test egalax-capacitive_0eef_7349',
1335
# 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',
1336
# input_info=(BusType.USB, 0x0eef, 0x7349),
1337
# evdev_name_suffix=' Touchscreen')
1338
#
1339
#
1340
# class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):
1341
# def create_device(self):
1342
# return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',
1343
# 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',
1344
# input_info=(BusType.USB, 0x0eef, 0x73f4),
1345
# evdev_name_suffix=' Touchscreen')
1346
#
1347
# bogus: BTN_TOOL_PEN is not emitted
1348
# class TestIrtouch_6615_0070(BaseTest.TestTablet):
1349
# def create_device(self):
1350
# return PenDigitizer('uhid test irtouch_6615_0070',
1351
# 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',
1352
# input_info=(BusType.USB, 0x6615, 0x0070))
1353
1354
1355
class TestNexio_1870_0100(BaseTest.TestTablet):
1356
def create_device(self):
1357
return PenDigitizer(
1358
"uhid test nexio_1870_0100",
1359
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",
1360
input_info=(BusType.USB, 0x1870, 0x0100),
1361
)
1362
1363
1364
class TestNexio_1870_010d(BaseTest.TestTablet):
1365
def create_device(self):
1366
return PenDigitizer(
1367
"uhid test nexio_1870_010d",
1368
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",
1369
input_info=(BusType.USB, 0x1870, 0x010D),
1370
)
1371
1372
1373
class TestNexio_1870_0119(BaseTest.TestTablet):
1374
def create_device(self):
1375
return PenDigitizer(
1376
"uhid test nexio_1870_0119",
1377
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",
1378
input_info=(BusType.USB, 0x1870, 0x0119),
1379
)
1380
1381
1382
################################################################################
1383
#
1384
# Windows 8 compatible devices
1385
#
1386
################################################################################
1387
1388
# bogus: application is 'undefined'
1389
# class Testatmel_03eb_8409(BaseTest.TestTablet):
1390
# def create_device(self):
1391
# 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')
1392
1393
1394
class Testatmel_03eb_840b(BaseTest.TestTablet):
1395
def create_device(self):
1396
return PenDigitizer(
1397
"uhid test atmel_03eb_840b",
1398
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",
1399
)
1400
1401
1402
class Testn_trig_1b96_0c01(BaseTest.TestTablet):
1403
def create_device(self):
1404
return PenDigitizer(
1405
"uhid test n_trig_1b96_0c01",
1406
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",
1407
)
1408
1409
1410
class Testn_trig_1b96_0c03(BaseTest.TestTablet):
1411
def create_device(self):
1412
return PenDigitizer(
1413
"uhid test n_trig_1b96_0c03",
1414
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",
1415
)
1416
1417
1418
class Testn_trig_1b96_0f00(BaseTest.TestTablet):
1419
def create_device(self):
1420
return PenDigitizer(
1421
"uhid test n_trig_1b96_0f00",
1422
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",
1423
)
1424
1425
1426
class Testn_trig_1b96_0f04(BaseTest.TestTablet):
1427
def create_device(self):
1428
return PenDigitizer(
1429
"uhid test n_trig_1b96_0f04",
1430
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",
1431
)
1432
1433
1434
class Testn_trig_1b96_1000(BaseTest.TestTablet):
1435
def create_device(self):
1436
return PenDigitizer(
1437
"uhid test n_trig_1b96_1000",
1438
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",
1439
)
1440
1441
1442
class TestGXTP_27c6_0113(BaseTest.TestTablet):
1443
def create_device(self):
1444
return GXTP_pen(
1445
"uhid test GXTP_27c6_0113",
1446
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",
1447
)
1448
1449
1450
################################################################################
1451
#
1452
# Windows 8 compatible devices with USI Pen
1453
#
1454
################################################################################
1455
1456
1457
class TestElan_04f3_2A49(BaseTest.TestTablet):
1458
def create_device(self):
1459
return USIPen(
1460
"uhid test Elan_04f3_2A49",
1461
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",
1462
input_info=(BusType.I2C, 0x04F3, 0x2A49),
1463
)
1464
1465
1466
class TestGoodix_27c6_0e00(BaseTest.TestTablet):
1467
def create_device(self):
1468
return USIPen(
1469
"uhid test Elan_04f3_2A49",
1470
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",
1471
input_info=(BusType.I2C, 0x27C6, 0x0E00),
1472
)
1473
1474
1475
class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
1476
hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]
1477
1478
def create_device(self):
1479
dev = XPPen_ArtistPro16Gen2_28bd_095b(
1480
"uhid test XPPen Artist Pro 16 Gen2 28bd 095b",
1481
rdesc="05 0d 09 02 a1 01 85 07 09 20 a1 00 09 42 09 44 09 45 09 3c 15 00 25 01 75 01 95 04 81 02 95 01 81 03 09 32 15 00 25 01 95 01 81 02 95 02 81 03 75 10 95 01 35 00 a4 05 01 09 30 65 13 55 0d 46 ff 34 26 ff 7f 81 02 09 31 46 20 21 26 ff 7f 81 02 b4 09 30 45 00 26 ff 3f 81 42 09 3d 15 81 25 7f 75 08 95 01 81 02 09 3e 15 81 25 7f 81 02 c0 c0",
1482
input_info=(BusType.USB, 0x28BD, 0x095B),
1483
)
1484
return dev
1485
1486
1487
class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
1488
hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]
1489
1490
def create_device(self):
1491
return XPPen_Artist24_28bd_093a(
1492
"uhid test XPPen Artist 24 28bd 093a",
1493
rdesc="05 0d 09 02 a1 01 85 07 09 20 a1 00 09 42 09 44 09 45 15 00 25 01 75 01 95 03 81 02 95 02 81 03 09 32 95 01 81 02 95 02 81 03 75 10 95 01 35 00 a4 05 01 09 30 65 13 55 0d 46 f0 50 26 ff 7f 81 02 09 31 46 91 2d 26 ff 7f 81 02 b4 09 30 45 00 26 ff 1f 81 42 09 3d 15 81 25 7f 75 08 95 01 81 02 09 3e 15 81 25 7f 81 02 c0 c0",
1494
input_info=(BusType.USB, 0x28BD, 0x093A),
1495
)
1496
1497
1498
class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
1499
hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]
1500
1501
def create_device(self):
1502
return Huion_Kamvas_Pro_19_256c_006b(
1503
"uhid test HUION Huion Tablet_GT1902",
1504
rdesc="05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0",
1505
input_info=(BusType.USB, 0x256C, 0x006B),
1506
)
1507
1508