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.distance = -10
456 self.tipswitch = False
457 self.tippressure = 15
458 self.azimuth = 0
459 self.inrange = False
460 self.width = 10
461 self.height = 10
462 self.barrelswitch = False
463 self.secondarybarrelswitch = False
464 self.invert = False
465 self.eraser = False
466 self.xtilt = 1
467 self.ytilt = 1
468 self.twist = 1
469 self._old_values = None
470 self.current_state = None
471
472 def restore(self):
473 if self._old_values is not None:
474 for i in [
475 "x",
476 "y",
477 "distance",
478 "tippressure",
479 "azimuth",
480 "width",
481 "height",
482 "twist",
483 "xtilt",
484 "ytilt",
485 ]:
486 setattr(self, i, getattr(self._old_values, i))
487
488 def backup(self):
489 self._old_values = copy.copy(self)
490
491 def __assert_axis(self, evdev, axis, value):
492 if (
493 axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
494 and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
495 ):
496 return
497
498 assert (
499 evdev.value[axis] == value
500 ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
501
502 def assert_expected_input_events(self, evdev, button):
503 assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
504 assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
505
506 # assert no other buttons than the tested ones are set
507 buttons = [
508 BtnPressed.PRIMARY_PRESSED,
509 BtnPressed.SECONDARY_PRESSED,
510 BtnPressed.THIRD_PRESSED,
511 ]
512 if button is not None:
513 buttons.remove(button)
514 for b in buttons:
515 assert evdev.value[b.value] is None or evdev.value[b.value] == False
516
517 assert self.current_state == PenState.from_evdev(evdev, button)
518
519
520class PenDigitizer(base.UHIDTestDevice):
521 def __init__(
522 self,
523 name,
524 rdesc_str=None,
525 rdesc=None,
526 application="Pen",
527 physical="Stylus",
528 input_info=(BusType.USB, 1, 2),
529 evdev_name_suffix=None,
530 ):
531 super().__init__(name, application, rdesc_str, rdesc, input_info)
532 self.physical = physical
533 self.cur_application = application
534 if evdev_name_suffix is not None:
535 self.name += evdev_name_suffix
536
537 self.fields = []
538 for r in self.parsed_rdesc.input_reports.values():
539 if r.application_name == self.application:
540 physicals = [f.physical_name for f in r]
541 if self.physical not in physicals and None not in physicals:
542 continue
543 self.fields = [f.usage_name for f in r]
544
545 def move_to(self, pen, state, button):
546 # fill in the previous values
547 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
548 pen.restore()
549
550 print(f"\n *** pen is moving to {state} ***")
551
552 if state == PenState.PEN_IS_OUT_OF_RANGE:
553 pen.backup()
554 pen.x = 0
555 pen.y = 0
556 pen.tipswitch = False
557 pen.tippressure = 0
558 pen.azimuth = 0
559 pen.distance = 0
560 pen.inrange = False
561 pen.width = 0
562 pen.height = 0
563 pen.invert = False
564 pen.eraser = False
565 pen.xtilt = 0
566 pen.ytilt = 0
567 pen.twist = 0
568 pen.barrelswitch = False
569 pen.secondarybarrelswitch = False
570 elif state == PenState.PEN_IS_IN_RANGE:
571 pen.tipswitch = False
572 pen.inrange = True
573 pen.invert = False
574 pen.eraser = False
575 pen.barrelswitch = False
576 pen.secondarybarrelswitch = False
577 elif state == PenState.PEN_IS_IN_CONTACT:
578 pen.tipswitch = True
579 pen.inrange = True
580 pen.invert = False
581 pen.eraser = False
582 pen.barrelswitch = False
583 pen.secondarybarrelswitch = False
584 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
585 pen.tipswitch = False
586 pen.inrange = True
587 pen.invert = False
588 pen.eraser = False
589 assert button is not None
590 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
591 pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
592 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
593 pen.tipswitch = True
594 pen.inrange = True
595 pen.invert = False
596 pen.eraser = False
597 assert button is not None
598 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
599 pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
600 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
601 pen.tipswitch = False
602 pen.inrange = True
603 pen.invert = True
604 pen.eraser = False
605 pen.barrelswitch = False
606 pen.secondarybarrelswitch = False
607 elif state == PenState.PEN_IS_ERASING:
608 pen.tipswitch = False
609 pen.inrange = True
610 pen.invert = False
611 pen.eraser = True
612 pen.barrelswitch = False
613 pen.secondarybarrelswitch = False
614
615 pen.current_state = state
616
617 def event(self, pen, button):
618 rs = []
619 r = self.create_report(application=self.cur_application, data=pen)
620 self.call_input_event(r)
621 rs.append(r)
622 return rs
623
624 def get_report(self, req, rnum, rtype):
625 if rtype != self.UHID_FEATURE_REPORT:
626 return (1, [])
627
628 rdesc = None
629 for v in self.parsed_rdesc.feature_reports.values():
630 if v.report_ID == rnum:
631 rdesc = v
632
633 if rdesc is None:
634 return (1, [])
635
636 return (1, [])
637
638 def set_report(self, req, rnum, rtype, data):
639 if rtype != self.UHID_FEATURE_REPORT:
640 return 1
641
642 rdesc = None
643 for v in self.parsed_rdesc.feature_reports.values():
644 if v.report_ID == rnum:
645 rdesc = v
646
647 if rdesc is None:
648 return 1
649
650 return 1
651
652
653class BaseTest:
654 class TestTablet(base.BaseTestCase.TestUhid):
655 def create_device(self):
656 raise Exception("please reimplement me in subclasses")
657
658 def post(self, uhdev, pen, test_button):
659 r = uhdev.event(pen, test_button)
660 events = uhdev.next_sync_events()
661 self.debug_reports(r, uhdev, events)
662 return events
663
664 def validate_transitions(
665 self, from_state, pen, evdev, events, allow_intermediate_states, button
666 ):
667 # check that the final state is correct
668 pen.assert_expected_input_events(evdev, button)
669
670 state = from_state
671
672 # check that the transitions are valid
673 sync_events = []
674 while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:
675 # split the first EV_SYN from the list
676 idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))
677 sync_events = events[:idx]
678 events = events[idx + 1 :]
679
680 # now check for a valid transition
681 state = state.apply(sync_events, not allow_intermediate_states, button)
682
683 if events:
684 state = state.apply(sync_events, not allow_intermediate_states, button)
685
686 def _test_states(
687 self, state_list, scribble, allow_intermediate_states, button=None
688 ):
689 """Internal method to test against a list of
690 transition between states.
691 state_list is a list of PenState objects
692 scribble is a boolean which tells if we need
693 to wobble a little the X,Y coordinates of the pen
694 between each state transition."""
695 uhdev = self.uhdev
696 evdev = uhdev.get_evdev()
697
698 cur_state = PenState.PEN_IS_OUT_OF_RANGE
699
700 p = Pen(50, 60)
701 uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)
702 events = self.post(uhdev, p, button)
703 self.validate_transitions(
704 cur_state, p, evdev, events, allow_intermediate_states, button
705 )
706
707 cur_state = p.current_state
708
709 for state in state_list:
710 if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:
711 p.x += 1
712 p.y -= 1
713 events = self.post(uhdev, p, button)
714 self.validate_transitions(
715 cur_state, p, evdev, events, allow_intermediate_states, button
716 )
717 assert len(events) >= 3 # X, Y, SYN
718 uhdev.move_to(p, state, button)
719 if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
720 p.x += 1
721 p.y -= 1
722 events = self.post(uhdev, p, button)
723 self.validate_transitions(
724 cur_state, p, evdev, events, allow_intermediate_states, button
725 )
726 cur_state = p.current_state
727
728 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
729 @pytest.mark.parametrize(
730 "state_list",
731 [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
732 )
733 def test_valid_pen_states(self, state_list, scribble):
734 """This is the first half of the Windows Pen Implementation state machine:
735 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
736 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
737 """
738 self._test_states(state_list, scribble, allow_intermediate_states=False)
739
740 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
741 @pytest.mark.parametrize(
742 "state_list",
743 [
744 pytest.param(v, id=k)
745 for k, v in PenState.tolerated_transitions().items()
746 ],
747 )
748 def test_tolerated_pen_states(self, state_list, scribble):
749 """This is not adhering to the Windows Pen Implementation state machine
750 but we should expect the kernel to behave properly, mostly for historical
751 reasons."""
752 self._test_states(state_list, scribble, allow_intermediate_states=True)
753
754 @pytest.mark.skip_if_uhdev(
755 lambda uhdev: "Barrel Switch" not in uhdev.fields,
756 "Device not compatible, missing Barrel Switch usage",
757 )
758 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
759 @pytest.mark.parametrize(
760 "state_list",
761 [
762 pytest.param(v, id=k)
763 for k, v in PenState.legal_transitions_with_button().items()
764 ],
765 )
766 def test_valid_primary_button_pen_states(self, state_list, scribble):
767 """Rework the transition state machine by adding the primary button."""
768 self._test_states(
769 state_list,
770 scribble,
771 allow_intermediate_states=False,
772 button=BtnPressed.PRIMARY_PRESSED,
773 )
774
775 @pytest.mark.skip_if_uhdev(
776 lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,
777 "Device not compatible, missing Secondary Barrel Switch usage",
778 )
779 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
780 @pytest.mark.parametrize(
781 "state_list",
782 [
783 pytest.param(v, id=k)
784 for k, v in PenState.legal_transitions_with_button().items()
785 ],
786 )
787 def test_valid_secondary_button_pen_states(self, state_list, scribble):
788 """Rework the transition state machine by adding the secondary button."""
789 self._test_states(
790 state_list,
791 scribble,
792 allow_intermediate_states=False,
793 button=BtnPressed.SECONDARY_PRESSED,
794 )
795
796 @pytest.mark.skip_if_uhdev(
797 lambda uhdev: "Third Barrel Switch" not in uhdev.fields,
798 "Device not compatible, missing Third Barrel Switch usage",
799 )
800 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
801 @pytest.mark.parametrize(
802 "state_list",
803 [
804 pytest.param(v, id=k)
805 for k, v in PenState.legal_transitions_with_button().items()
806 ],
807 )
808 def test_valid_third_button_pen_states(self, state_list, scribble):
809 """Rework the transition state machine by adding the secondary button."""
810 self._test_states(
811 state_list,
812 scribble,
813 allow_intermediate_states=False,
814 button=BtnPressed.THIRD_PRESSED,
815 )
816
817 @pytest.mark.skip_if_uhdev(
818 lambda uhdev: "Invert" not in uhdev.fields,
819 "Device not compatible, missing Invert usage",
820 )
821 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
822 @pytest.mark.parametrize(
823 "state_list",
824 [
825 pytest.param(v, id=k)
826 for k, v in PenState.legal_transitions_with_invert().items()
827 ],
828 )
829 def test_valid_invert_pen_states(self, state_list, scribble):
830 """This is the second half of the Windows Pen Implementation state machine:
831 we now have Invert and Erase bits, so move in/out or proximity with the intend
832 to erase.
833 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
834 """
835 self._test_states(state_list, scribble, allow_intermediate_states=False)
836
837 @pytest.mark.skip_if_uhdev(
838 lambda uhdev: "Invert" not in uhdev.fields,
839 "Device not compatible, missing Invert usage",
840 )
841 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
842 @pytest.mark.parametrize(
843 "state_list",
844 [
845 pytest.param(v, id=k)
846 for k, v in PenState.tolerated_transitions_with_invert().items()
847 ],
848 )
849 def test_tolerated_invert_pen_states(self, state_list, scribble):
850 """This is the second half of the Windows Pen Implementation state machine:
851 we now have Invert and Erase bits, so move in/out or proximity with the intend
852 to erase.
853 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
854 """
855 self._test_states(state_list, scribble, allow_intermediate_states=True)
856
857 @pytest.mark.skip_if_uhdev(
858 lambda uhdev: "Invert" not in uhdev.fields,
859 "Device not compatible, missing Invert usage",
860 )
861 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
862 @pytest.mark.parametrize(
863 "state_list",
864 [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],
865 )
866 def test_tolerated_broken_pen_states(self, state_list, scribble):
867 """Those tests are definitely not part of the Windows specification.
868 However, a half broken device might export those transitions.
869 For example, a pen that has the eraser button might wobble between
870 touching and erasing if the tablet doesn't enforce the Windows
871 state machine."""
872 self._test_states(state_list, scribble, allow_intermediate_states=True)
873
874 @pytest.mark.skip_if_uhdev(
875 lambda uhdev: "Z" not in uhdev.fields,
876 "Device not compatible, missing Z usage",
877 )
878 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
879 @pytest.mark.parametrize(
880 "state_list",
881 [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
882 )
883 def test_z_reported_as_distance(self, state_list, scribble):
884 """Verify stylus Z values are reported as ABS_DISTANCE."""
885 self._test_states(state_list, scribble, allow_intermediate_states=False)
886
887 uhdev = self.uhdev
888 evdev = uhdev.get_evdev()
889 p = Pen(0, 0)
890 uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, None)
891 p = Pen(100, 200)
892 uhdev.move_to(p, PenState.PEN_IS_IN_RANGE, None)
893 p.distance = -1
894 events = self.post(uhdev, p, None)
895 assert evdev.value[libevdev.EV_ABS.ABS_DISTANCE] == -1
896
897
898class GXTP_pen(PenDigitizer):
899 def event(self, pen, test_button):
900 if not hasattr(self, "prev_tip_state"):
901 self.prev_tip_state = False
902
903 internal_pen = copy.copy(pen)
904
905 # bug in the controller: when the pen touches the
906 # surface, in-range stays to 1, but when
907 # the pen moves in-range gets reverted to 0
908 if pen.tipswitch and self.prev_tip_state:
909 internal_pen.inrange = False
910
911 self.prev_tip_state = pen.tipswitch
912
913 # another bug in the controller: when the pen is
914 # inverted, invert is set to 1, but as soon as
915 # the pen touches the surface, eraser is correctly
916 # set to 1 but invert is released
917 if pen.eraser:
918 internal_pen.invert = False
919
920 return super().event(internal_pen, test_button)
921
922
923class USIPen(PenDigitizer):
924 pass
925
926
927class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):
928 """
929 Pen with two buttons and a rubber end, but which reports
930 the second button as an eraser
931 """
932
933 def __init__(
934 self,
935 name,
936 rdesc_str=None,
937 rdesc=None,
938 application="Pen",
939 physical="Stylus",
940 input_info=(BusType.USB, 0x28BD, 0x095B),
941 evdev_name_suffix=None,
942 ):
943 super().__init__(
944 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
945 )
946 self.fields.append("Secondary Barrel Switch")
947
948 def move_to(self, pen, state, button):
949 # fill in the previous values
950 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
951 pen.restore()
952
953 print(f"\n *** pen is moving to {state} ***")
954
955 if state == PenState.PEN_IS_OUT_OF_RANGE:
956 pen.backup()
957 pen.x = 0
958 pen.y = 0
959 pen.tipswitch = False
960 pen.tippressure = 0
961 pen.azimuth = 0
962 pen.inrange = False
963 pen.width = 0
964 pen.height = 0
965 pen.invert = False
966 pen.eraser = False
967 pen.xtilt = 0
968 pen.ytilt = 0
969 pen.twist = 0
970 pen.barrelswitch = False
971 elif state == PenState.PEN_IS_IN_RANGE:
972 pen.tipswitch = False
973 pen.inrange = True
974 pen.invert = False
975 pen.eraser = False
976 pen.barrelswitch = False
977 elif state == PenState.PEN_IS_IN_CONTACT:
978 pen.tipswitch = True
979 pen.inrange = True
980 pen.invert = False
981 pen.eraser = False
982 pen.barrelswitch = False
983 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
984 pen.tipswitch = False
985 pen.inrange = True
986 pen.invert = False
987 assert button is not None
988 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
989 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
990 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
991 pen.tipswitch = True
992 pen.inrange = True
993 pen.invert = False
994 assert button is not None
995 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
996 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
997 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
998 pen.tipswitch = False
999 pen.inrange = True
1000 pen.invert = True
1001 pen.eraser = False
1002 pen.barrelswitch = False
1003 elif state == PenState.PEN_IS_ERASING:
1004 pen.tipswitch = True
1005 pen.inrange = True
1006 pen.invert = True
1007 pen.eraser = False
1008 pen.barrelswitch = False
1009
1010 pen.current_state = state
1011
1012 def event(self, pen, test_button):
1013 import math
1014
1015 pen_copy = copy.copy(pen)
1016 width = 13.567
1017 height = 8.480
1018 tip_height = 0.055677699
1019 hx = tip_height * (32767 / width)
1020 hy = tip_height * (32767 / height)
1021 if pen_copy.xtilt != 0:
1022 pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))
1023 if pen_copy.ytilt != 0:
1024 pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))
1025
1026 return super().event(pen_copy, test_button)
1027
1028
1029class XPPen_Artist24_28bd_093a(PenDigitizer):
1030 """
1031 Pen that reports secondary barrel switch through eraser
1032 """
1033
1034 def __init__(
1035 self,
1036 name,
1037 rdesc_str=None,
1038 rdesc=None,
1039 application="Pen",
1040 physical="Stylus",
1041 input_info=(BusType.USB, 0x28BD, 0x093A),
1042 evdev_name_suffix=None,
1043 ):
1044 super().__init__(
1045 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1046 )
1047 self.fields.append("Secondary Barrel Switch")
1048 self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1049
1050 def move_to(self, pen, state, button, debug=True):
1051 # fill in the previous values
1052 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1053 pen.restore()
1054
1055 if debug:
1056 print(f"\n *** pen is moving to {state} ***")
1057
1058 if state == PenState.PEN_IS_OUT_OF_RANGE:
1059 pen.backup()
1060 pen.tipswitch = False
1061 pen.tippressure = 0
1062 pen.azimuth = 0
1063 pen.inrange = False
1064 pen.width = 0
1065 pen.height = 0
1066 pen.invert = False
1067 pen.eraser = False
1068 pen.xtilt = 0
1069 pen.ytilt = 0
1070 pen.twist = 0
1071 pen.barrelswitch = False
1072 elif state == PenState.PEN_IS_IN_RANGE:
1073 pen.tipswitch = False
1074 pen.inrange = True
1075 pen.invert = False
1076 pen.eraser = False
1077 pen.barrelswitch = False
1078 elif state == PenState.PEN_IS_IN_CONTACT:
1079 pen.tipswitch = True
1080 pen.inrange = True
1081 pen.invert = False
1082 pen.eraser = False
1083 pen.barrelswitch = False
1084 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1085 pen.tipswitch = False
1086 pen.inrange = True
1087 pen.invert = False
1088 assert button is not None
1089 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1090 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1091 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1092 pen.tipswitch = True
1093 pen.inrange = True
1094 pen.invert = False
1095 assert button is not None
1096 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1097 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1098
1099 pen.current_state = state
1100
1101 def send_intermediate_state(self, pen, state, button):
1102 intermediate_pen = copy.copy(pen)
1103 self.move_to(intermediate_pen, state, button, debug=False)
1104 return super().event(intermediate_pen, button)
1105
1106 def event(self, pen, button):
1107 rs = []
1108
1109 # the pen reliably sends in-range events in a normal case (non emulation of eraser mode)
1110 if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1111 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1112 rs.extend(
1113 self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1114 )
1115
1116 if button == BtnPressed.SECONDARY_PRESSED:
1117 if self.previous_state == PenState.PEN_IS_IN_RANGE:
1118 if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1119 rs.extend(
1120 self.send_intermediate_state(
1121 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1122 )
1123 )
1124
1125 if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1126 if pen.current_state == PenState.PEN_IS_IN_RANGE:
1127 rs.extend(
1128 self.send_intermediate_state(
1129 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1130 )
1131 )
1132
1133 if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1134 if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1135 rs.extend(
1136 self.send_intermediate_state(
1137 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1138 )
1139 )
1140 rs.extend(
1141 self.send_intermediate_state(
1142 pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button
1143 )
1144 )
1145
1146 if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1147 if pen.current_state == PenState.PEN_IS_IN_CONTACT:
1148 rs.extend(
1149 self.send_intermediate_state(
1150 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1151 )
1152 )
1153 rs.extend(
1154 self.send_intermediate_state(
1155 pen, PenState.PEN_IS_IN_RANGE, button
1156 )
1157 )
1158
1159 rs.extend(super().event(pen, button))
1160 self.previous_state = pen.current_state
1161 return rs
1162
1163
1164class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):
1165 """
1166 Pen that reports secondary barrel switch through secondary TipSwtich
1167 and 3rd button through Invert
1168 """
1169
1170 def __init__(
1171 self,
1172 name,
1173 rdesc_str=None,
1174 rdesc=None,
1175 application="Stylus",
1176 physical=None,
1177 input_info=(BusType.USB, 0x256C, 0x006B),
1178 evdev_name_suffix=None,
1179 ):
1180 super().__init__(
1181 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1182 )
1183 self.fields.append("Secondary Barrel Switch")
1184 self.fields.append("Third Barrel Switch")
1185 self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1186
1187 def move_to(self, pen, state, button, debug=True):
1188 # fill in the previous values
1189 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1190 pen.restore()
1191
1192 if debug:
1193 print(f"\n *** pen is moving to {state} ***")
1194
1195 if state == PenState.PEN_IS_OUT_OF_RANGE:
1196 pen.backup()
1197 pen.tipswitch = False
1198 pen.tippressure = 0
1199 pen.azimuth = 0
1200 pen.inrange = False
1201 pen.width = 0
1202 pen.height = 0
1203 pen.invert = False
1204 pen.eraser = False
1205 pen.xtilt = 0
1206 pen.ytilt = 0
1207 pen.twist = 0
1208 pen.barrelswitch = False
1209 pen.secondarytipswitch = False
1210 elif state == PenState.PEN_IS_IN_RANGE:
1211 pen.tipswitch = False
1212 pen.inrange = True
1213 pen.invert = False
1214 pen.eraser = False
1215 pen.barrelswitch = False
1216 pen.secondarytipswitch = False
1217 elif state == PenState.PEN_IS_IN_CONTACT:
1218 pen.tipswitch = True
1219 pen.inrange = True
1220 pen.invert = False
1221 pen.eraser = False
1222 pen.barrelswitch = False
1223 pen.secondarytipswitch = False
1224 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1225 pen.tipswitch = False
1226 pen.inrange = True
1227 pen.eraser = False
1228 assert button is not None
1229 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1230 pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1231 pen.invert = button == BtnPressed.THIRD_PRESSED
1232 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1233 pen.tipswitch = True
1234 pen.inrange = True
1235 pen.eraser = False
1236 assert button is not None
1237 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1238 pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1239 pen.invert = button == BtnPressed.THIRD_PRESSED
1240 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
1241 pen.tipswitch = False
1242 pen.inrange = True
1243 pen.invert = True
1244 pen.eraser = False
1245 pen.barrelswitch = False
1246 pen.secondarytipswitch = False
1247 elif state == PenState.PEN_IS_ERASING:
1248 pen.tipswitch = False
1249 pen.inrange = True
1250 pen.invert = False
1251 pen.eraser = True
1252 pen.barrelswitch = False
1253 pen.secondarytipswitch = False
1254
1255 pen.current_state = state
1256
1257 def call_input_event(self, report):
1258 if report[0] == 0x0A:
1259 # ensures the original second Eraser usage is null
1260 report[1] &= 0xDF
1261
1262 # ensures the original last bit is equal to bit 6 (In Range)
1263 if report[1] & 0x40:
1264 report[1] |= 0x80
1265
1266 super().call_input_event(report)
1267
1268 def send_intermediate_state(self, pen, state, test_button):
1269 intermediate_pen = copy.copy(pen)
1270 self.move_to(intermediate_pen, state, test_button, debug=False)
1271 return super().event(intermediate_pen, test_button)
1272
1273 def event(self, pen, button):
1274 rs = []
1275
1276 # it's not possible to go between eraser mode or not without
1277 # going out-of-prox: the eraser mode is activated by presenting
1278 # the tail of the pen
1279 if self.previous_state in (
1280 PenState.PEN_IS_IN_RANGE,
1281 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1282 PenState.PEN_IS_IN_CONTACT,
1283 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1284 ) and pen.current_state in (
1285 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1286 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1287 PenState.PEN_IS_ERASING,
1288 PenState.PEN_IS_ERASING_WITH_BUTTON,
1289 ):
1290 rs.extend(
1291 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1292 )
1293
1294 # same than above except from eraser to normal
1295 if self.previous_state in (
1296 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1297 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1298 PenState.PEN_IS_ERASING,
1299 PenState.PEN_IS_ERASING_WITH_BUTTON,
1300 ) and pen.current_state in (
1301 PenState.PEN_IS_IN_RANGE,
1302 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1303 PenState.PEN_IS_IN_CONTACT,
1304 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1305 ):
1306 rs.extend(
1307 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1308 )
1309
1310 if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:
1311 if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1312 rs.extend(
1313 self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1314 )
1315
1316 rs.extend(super().event(pen, button))
1317 self.previous_state = pen.current_state
1318 return rs
1319
1320
1321class Wacom_2d1f_014b(PenDigitizer):
1322 """
1323 Pen that reports distance values with HID_GD_Z usage.
1324 """
1325 def __init__(
1326 self,
1327 name,
1328 rdesc_str=None,
1329 rdesc=None,
1330 application="Pen",
1331 physical="Stylus",
1332 input_info=(BusType.USB, 0x2D1F, 0x014B),
1333 evdev_name_suffix=None,
1334 ):
1335 super().__init__(
1336 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1337 )
1338
1339 def match_evdev_rule(self, application, evdev):
1340 # there are 2 nodes created by the device, only one matters
1341 return evdev.name.endswith("Stylus")
1342
1343 def event(self, pen, test_button):
1344 # this device reports the distance through Z
1345 pen.z = pen.distance
1346
1347 return super().event(pen, test_button)
1348
1349
1350################################################################################
1351#
1352# Windows 7 compatible devices
1353#
1354################################################################################
1355# class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):
1356# def create_device(self):
1357# return PenDigitizer('uhid test egalax-capacitive_0eef_7224',
1358# 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',
1359# input_info=(BusType.USB, 0x0eef, 0x7224),
1360# evdev_name_suffix=' Touchscreen')
1361#
1362#
1363# class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):
1364# def create_device(self):
1365# return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',
1366# 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',
1367# input_info=(BusType.USB, 0x0eef, 0x72fa),
1368# evdev_name_suffix=' Touchscreen')
1369#
1370#
1371# class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):
1372# def create_device(self):
1373# return PenDigitizer('uhid test egalax-capacitive_0eef_7336',
1374# 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',
1375# input_info=(BusType.USB, 0x0eef, 0x7336),
1376# evdev_name_suffix=' Touchscreen')
1377#
1378#
1379# class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):
1380# def create_device(self):
1381# return PenDigitizer('uhid test egalax-capacitive_0eef_7337',
1382# 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',
1383# input_info=(BusType.USB, 0x0eef, 0x7337),
1384# evdev_name_suffix=' Touchscreen')
1385#
1386#
1387# class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):
1388# def create_device(self):
1389# return PenDigitizer('uhid test egalax-capacitive_0eef_7349',
1390# 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',
1391# input_info=(BusType.USB, 0x0eef, 0x7349),
1392# evdev_name_suffix=' Touchscreen')
1393#
1394#
1395# class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):
1396# def create_device(self):
1397# return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',
1398# 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',
1399# input_info=(BusType.USB, 0x0eef, 0x73f4),
1400# evdev_name_suffix=' Touchscreen')
1401#
1402# bogus: BTN_TOOL_PEN is not emitted
1403# class TestIrtouch_6615_0070(BaseTest.TestTablet):
1404# def create_device(self):
1405# return PenDigitizer('uhid test irtouch_6615_0070',
1406# 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',
1407# input_info=(BusType.USB, 0x6615, 0x0070))
1408
1409
1410class TestNexio_1870_0100(BaseTest.TestTablet):
1411 def create_device(self):
1412 return PenDigitizer(
1413 "uhid test nexio_1870_0100",
1414 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",
1415 input_info=(BusType.USB, 0x1870, 0x0100),
1416 )
1417
1418
1419class TestNexio_1870_010d(BaseTest.TestTablet):
1420 def create_device(self):
1421 return PenDigitizer(
1422 "uhid test nexio_1870_010d",
1423 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",
1424 input_info=(BusType.USB, 0x1870, 0x010D),
1425 )
1426
1427
1428class TestNexio_1870_0119(BaseTest.TestTablet):
1429 def create_device(self):
1430 return PenDigitizer(
1431 "uhid test nexio_1870_0119",
1432 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",
1433 input_info=(BusType.USB, 0x1870, 0x0119),
1434 )
1435
1436
1437################################################################################
1438#
1439# Windows 8 compatible devices
1440#
1441################################################################################
1442
1443# bogus: application is 'undefined'
1444# class Testatmel_03eb_8409(BaseTest.TestTablet):
1445# def create_device(self):
1446# 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')
1447
1448
1449class Testatmel_03eb_840b(BaseTest.TestTablet):
1450 def create_device(self):
1451 return PenDigitizer(
1452 "uhid test atmel_03eb_840b",
1453 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",
1454 )
1455
1456
1457class Testn_trig_1b96_0c01(BaseTest.TestTablet):
1458 def create_device(self):
1459 return PenDigitizer(
1460 "uhid test n_trig_1b96_0c01",
1461 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",
1462 )
1463
1464
1465class Testn_trig_1b96_0c03(BaseTest.TestTablet):
1466 def create_device(self):
1467 return PenDigitizer(
1468 "uhid test n_trig_1b96_0c03",
1469 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",
1470 )
1471
1472
1473class Testn_trig_1b96_0f00(BaseTest.TestTablet):
1474 def create_device(self):
1475 return PenDigitizer(
1476 "uhid test n_trig_1b96_0f00",
1477 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",
1478 )
1479
1480
1481class Testn_trig_1b96_0f04(BaseTest.TestTablet):
1482 def create_device(self):
1483 return PenDigitizer(
1484 "uhid test n_trig_1b96_0f04",
1485 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",
1486 )
1487
1488
1489class Testn_trig_1b96_1000(BaseTest.TestTablet):
1490 def create_device(self):
1491 return PenDigitizer(
1492 "uhid test n_trig_1b96_1000",
1493 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",
1494 )
1495
1496
1497class TestGXTP_27c6_0113(BaseTest.TestTablet):
1498 def create_device(self):
1499 return GXTP_pen(
1500 "uhid test GXTP_27c6_0113",
1501 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",
1502 )
1503
1504
1505################################################################################
1506#
1507# Windows 8 compatible devices with USI Pen
1508#
1509################################################################################
1510
1511
1512class TestElan_04f3_2A49(BaseTest.TestTablet):
1513 def create_device(self):
1514 return USIPen(
1515 "uhid test Elan_04f3_2A49",
1516 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",
1517 input_info=(BusType.I2C, 0x04F3, 0x2A49),
1518 )
1519
1520
1521class TestGoodix_27c6_0e00(BaseTest.TestTablet):
1522 def create_device(self):
1523 return USIPen(
1524 "uhid test Elan_04f3_2A49",
1525 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",
1526 input_info=(BusType.I2C, 0x27C6, 0x0E00),
1527 )
1528
1529
1530class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
1531 hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]
1532
1533 def create_device(self):
1534 dev = XPPen_ArtistPro16Gen2_28bd_095b(
1535 "uhid test XPPen Artist Pro 16 Gen2 28bd 095b",
1536 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",
1537 input_info=(BusType.USB, 0x28BD, 0x095B),
1538 )
1539 return dev
1540
1541
1542class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
1543 hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]
1544
1545 def create_device(self):
1546 return XPPen_Artist24_28bd_093a(
1547 "uhid test XPPen Artist 24 28bd 093a",
1548 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",
1549 input_info=(BusType.USB, 0x28BD, 0x093A),
1550 )
1551
1552
1553class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
1554 hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]
1555
1556 def create_device(self):
1557 return Huion_Kamvas_Pro_19_256c_006b(
1558 "uhid test HUION Huion Tablet_GT1902",
1559 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",
1560 input_info=(BusType.USB, 0x256C, 0x006B),
1561 )
1562
1563
1564################################################################################
1565#
1566# Devices Reporting Distance
1567#
1568################################################################################
1569
1570
1571class TestWacom_2d1f_014b(BaseTest.TestTablet):
1572 def create_device(self):
1573 return Wacom_2d1f_014b(
1574 "uhid test Wacom 2d1f_014b",
1575 rdesc="05 0d 09 02 a1 01 85 02 09 20 a1 00 09 42 09 44 09 45 09 3c 09 5a 09 32 15 00 25 01 75 01 95 06 81 02 95 02 81 03 05 01 09 30 26 88 3e 46 88 3e 65 11 55 0d 75 10 95 01 81 02 09 31 26 60 53 46 60 53 81 02 05 0d 09 30 26 ff 0f 45 00 65 00 55 00 81 02 06 00 ff 09 04 75 08 26 ff 00 46 ff 00 65 11 55 0e 81 02 05 0d 09 3d 75 10 16 d8 dc 26 28 23 36 d8 dc 46 28 23 65 14 81 02 09 3e 81 02 05 01 09 32 16 01 ff 25 00 36 01 ff 45 00 65 11 81 02 05 0d 09 56 15 00 27 ff ff 00 00 35 00 47 ff ff 00 00 66 01 10 55 0c 81 02 45 00 65 00 55 00 c0 09 00 75 08 26 ff 00 b1 12 85 03 09 00 95 12 b1 12 85 05 09 00 95 04 b1 02 85 06 09 00 95 24 b1 02 85 16 09 00 15 00 26 ff 00 95 06 b1 02 85 17 09 00 95 0c b1 02 85 19 09 00 95 01 b1 02 85 0a 09 00 75 08 95 01 15 10 26 ff 00 b1 02 85 1e 09 00 95 10 b1 02 c0 06 00 ff 09 00 a1 01 85 09 05 0d 09 20 a1 00 09 00 15 00 26 ff 00 75 08 95 10 81 02 c0 09 00 95 03 b1 12 c0 06 00 ff 09 02 a1 01 85 07 09 00 96 09 01 b1 02 85 08 09 00 95 03 81 02 09 00 b1 02 85 0e 09 00 96 0a 01 b1 02 c0 05 0d 09 02 a1 01 85 1a 09 20 a1 00 09 42 09 44 09 45 09 3c 09 5a 09 32 15 00 25 01 75 01 95 06 81 02 09 38 25 03 75 02 95 01 81 02 05 01 09 30 26 88 3e 46 88 3e 65 11 55 0d 75 10 95 01 81 02 09 31 26 60 53 46 60 53 81 02 05 0d 09 30 26 ff 0f 46 b0 0f 66 11 e1 55 02 81 02 06 00 ff 09 04 75 08 26 ff 00 46 ff 00 65 11 55 0e 81 02 05 0d 09 3d 75 10 16 d8 dc 26 28 23 36 d8 dc 46 28 23 65 14 81 02 09 3e 81 02 05 01 09 32 16 01 ff 25 00 36 01 ff 45 00 65 11 81 02 05 0d 09 56 15 00 27 ff ff 00 00 35 00 47 ff ff 00 00 66 01 10 55 0c 81 02 45 00 65 00 55 00 c0 c0 06 00 ff 09 00 a1 01 85 1b 05 0d 09 20 a1 00 09 00 26 ff 00 75 08 95 10 81 02 c0 c0",
1576 input_info=(BusType.USB, 0x2D1F, 0x014B),
1577 )