Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3# -*- coding: utf-8 -*-
4#
5# Copyright (c) 2021 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6# Copyright (c) 2021 Red Hat, Inc.
7#
8
9from . import base
10import copy
11from enum import Enum
12from hidtools.util import BusType
13from .base import HidBpf
14import libevdev
15import logging
16import pytest
17from typing import Dict, List, Optional, Tuple
18
19logger = logging.getLogger("hidtools.test.tablet")
20
21
22class BtnTouch(Enum):
23 """Represents whether the BTN_TOUCH event is set to True or False"""
24
25 DOWN = True
26 UP = False
27
28
29class ToolType(Enum):
30 PEN = libevdev.EV_KEY.BTN_TOOL_PEN
31 RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER
32
33
34class 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
42class 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
451class 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
518class 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
650class 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
872class 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
897class USIPen(PenDigitizer):
898 pass
899
900
901class 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
1003class 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
1138class 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
1355class 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
1364class 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
1373class 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
1394class 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
1402class 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
1410class 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
1418class 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
1426class 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
1434class 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
1442class 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
1457class 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
1466class 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
1475class 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
1487class 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
1498class 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 )