2 # SPDX-License-Identifier: GPL-2.0
3 # -*- coding: utf-8 -*-
6 # Copyright (c) 2021 Red Hat, Inc.
12 from hidtools.util import BusType
16 from typing import Dict, List, Optional, Tuple
18 logger = logging.getLogger("hidtools.test.tablet")
22 """Represents whether the BTN_TOUCH event is set to True or False"""
29 PEN = libevdev.EV_KEY.BTN_TOOL_PEN
30 RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER
33 class BtnPressed(Enum):
34 """Represents whether a button is pressed on the stylus"""
36 PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS
37 SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2
38 THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS3
42 """Pen states according to Microsoft reference:
43 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
45 We extend it with the various buttons when we need to check them.
48 PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False
49 PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False
50 PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True
51 PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False
52 PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True
53 PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False
54 PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True
55 PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False
56 PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True
59 self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]
61 self.touch = touch # type: ignore
62 self.tool = tool # type: ignore
63 self.button = button # type: ignore
66 def from_evdev(cls, evdev, test_button) -> "PenState":
67 touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
71 evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
72 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
74 tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)
76 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
77 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
79 tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)
81 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
82 or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
84 raise ValueError("2 tools are not allowed")
86 # we take only the provided button into account
87 if test_button is not None:
88 button = bool(evdev.value[test_button.value])
90 # the kernel tends to insert an EV_SYN once removing the tool, so
91 # the button will be released after
95 return cls((touch, tool, button)) # type: ignore
98 self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed
100 if libevdev.EV_SYN.SYN_REPORT in events:
101 raise ValueError("EV_SYN is in the event sequence")
110 if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):
112 raise ValueError(f"duplicated BTN_TOUCH in {events}")
114 touch = BtnTouch(ev.value)
116 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),
117 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),
120 raise ValueError(f"duplicated BTN_TOOL_* in {events}")
122 tool = ToolType(ev.code) if ev.value else None
123 elif test_button is not None and ev in (test_button.value,):
125 raise ValueError(f"duplicated BTN_STYLUS* in {events}")
127 button = bool(ev.value)
129 # the kernel tends to insert an EV_SYN once removing the tool, so
130 # the button will be released after
134 new_state = PenState((touch, tool, button)) # type: ignore
137 new_state in self.valid_transitions()
138 ), f"moving from {self} to {new_state} is forbidden"
141 new_state in self.historically_tolerated_transitions()
142 ), f"moving from {self} to {new_state} is forbidden"
146 def valid_transitions(self) -> Tuple["PenState", ...]:
147 """Following the state machine in the URL above.
149 Note that those transitions are from the evdev point of view, not HID"""
150 if self == PenState.PEN_IS_OUT_OF_RANGE:
152 PenState.PEN_IS_OUT_OF_RANGE,
153 PenState.PEN_IS_IN_RANGE,
154 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
155 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
156 PenState.PEN_IS_IN_CONTACT,
157 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
158 PenState.PEN_IS_ERASING,
161 if self == PenState.PEN_IS_IN_RANGE:
163 PenState.PEN_IS_IN_RANGE,
164 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
165 PenState.PEN_IS_OUT_OF_RANGE,
166 PenState.PEN_IS_IN_CONTACT,
169 if self == PenState.PEN_IS_IN_CONTACT:
171 PenState.PEN_IS_IN_CONTACT,
172 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
173 PenState.PEN_IS_IN_RANGE,
176 if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
178 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
179 PenState.PEN_IS_OUT_OF_RANGE,
180 PenState.PEN_IS_ERASING,
183 if self == PenState.PEN_IS_ERASING:
185 PenState.PEN_IS_ERASING,
186 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
189 if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
191 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
192 PenState.PEN_IS_IN_RANGE,
193 PenState.PEN_IS_OUT_OF_RANGE,
194 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
197 if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
199 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
200 PenState.PEN_IS_IN_CONTACT,
201 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
206 def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:
207 """Following the state machine in the URL above, with a couple of addition
208 for skipping the in-range state, due to historical reasons.
210 Note that those transitions are from the evdev point of view, not HID"""
211 if self == PenState.PEN_IS_OUT_OF_RANGE:
213 PenState.PEN_IS_OUT_OF_RANGE,
214 PenState.PEN_IS_IN_RANGE,
215 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
216 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
217 PenState.PEN_IS_IN_CONTACT,
218 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
219 PenState.PEN_IS_ERASING,
222 if self == PenState.PEN_IS_IN_RANGE:
224 PenState.PEN_IS_IN_RANGE,
225 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
226 PenState.PEN_IS_OUT_OF_RANGE,
227 PenState.PEN_IS_IN_CONTACT,
230 if self == PenState.PEN_IS_IN_CONTACT:
232 PenState.PEN_IS_IN_CONTACT,
233 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
234 PenState.PEN_IS_IN_RANGE,
235 PenState.PEN_IS_OUT_OF_RANGE,
238 if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
240 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
241 PenState.PEN_IS_OUT_OF_RANGE,
242 PenState.PEN_IS_ERASING,
245 if self == PenState.PEN_IS_ERASING:
247 PenState.PEN_IS_ERASING,
248 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
249 PenState.PEN_IS_OUT_OF_RANGE,
252 if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
254 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
255 PenState.PEN_IS_IN_RANGE,
256 PenState.PEN_IS_OUT_OF_RANGE,
257 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
260 if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
262 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
263 PenState.PEN_IS_IN_CONTACT,
264 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
265 PenState.PEN_IS_OUT_OF_RANGE,
271 def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:
272 """This is the first half of the Windows Pen Implementation state machine:
273 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
274 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
277 "in-range": (PenState.PEN_IS_IN_RANGE,),
278 "in-range -> out-of-range": (
279 PenState.PEN_IS_IN_RANGE,
280 PenState.PEN_IS_OUT_OF_RANGE,
282 "in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT),
283 "in-range -> touch -> release": (
284 PenState.PEN_IS_IN_RANGE,
285 PenState.PEN_IS_IN_CONTACT,
286 PenState.PEN_IS_IN_RANGE,
288 "in-range -> touch -> release -> out-of-range": (
289 PenState.PEN_IS_IN_RANGE,
290 PenState.PEN_IS_IN_CONTACT,
291 PenState.PEN_IS_IN_RANGE,
292 PenState.PEN_IS_OUT_OF_RANGE,
297 def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
298 """This is the second half of the Windows Pen Implementation state machine:
299 we now have Invert and Erase bits, so move in/out or proximity with the intend
301 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
304 "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,),
305 "hover-erasing -> out-of-range": (
306 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
307 PenState.PEN_IS_OUT_OF_RANGE,
309 "hover-erasing -> erase": (
310 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
311 PenState.PEN_IS_ERASING,
313 "hover-erasing -> erase -> release": (
314 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
315 PenState.PEN_IS_ERASING,
316 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
318 "hover-erasing -> erase -> release -> out-of-range": (
319 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
320 PenState.PEN_IS_ERASING,
321 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
322 PenState.PEN_IS_OUT_OF_RANGE,
324 "hover-erasing -> in-range": (
325 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
326 PenState.PEN_IS_IN_RANGE,
328 "in-range -> hover-erasing": (
329 PenState.PEN_IS_IN_RANGE,
330 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
335 def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:
336 """We revisit the Windows Pen Implementation state machine:
337 we now have a button.
340 "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),
341 "hover-button -> out-of-range": (
342 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
343 PenState.PEN_IS_OUT_OF_RANGE,
345 "in-range -> button-press": (
346 PenState.PEN_IS_IN_RANGE,
347 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
349 "in-range -> button-press -> button-release": (
350 PenState.PEN_IS_IN_RANGE,
351 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
352 PenState.PEN_IS_IN_RANGE,
354 "in-range -> touch -> button-press -> button-release": (
355 PenState.PEN_IS_IN_RANGE,
356 PenState.PEN_IS_IN_CONTACT,
357 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
358 PenState.PEN_IS_IN_CONTACT,
360 "in-range -> touch -> button-press -> release -> button-release": (
361 PenState.PEN_IS_IN_RANGE,
362 PenState.PEN_IS_IN_CONTACT,
363 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
364 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
365 PenState.PEN_IS_IN_RANGE,
367 "in-range -> button-press -> touch -> release -> button-release": (
368 PenState.PEN_IS_IN_RANGE,
369 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
370 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
371 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
372 PenState.PEN_IS_IN_RANGE,
374 "in-range -> button-press -> touch -> button-release -> release": (
375 PenState.PEN_IS_IN_RANGE,
376 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
377 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
378 PenState.PEN_IS_IN_CONTACT,
379 PenState.PEN_IS_IN_RANGE,
384 def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:
385 """This is not adhering to the Windows Pen Implementation state machine
386 but we should expect the kernel to behave properly, mostly for historical
389 "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,),
390 "direct-in-contact -> out-of-range": (
391 PenState.PEN_IS_IN_CONTACT,
392 PenState.PEN_IS_OUT_OF_RANGE,
397 def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
398 """This is the second half of the Windows Pen Implementation state machine:
399 we now have Invert and Erase bits, so move in/out or proximity with the intend
401 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
404 "direct-erase": (PenState.PEN_IS_ERASING,),
405 "direct-erase -> out-of-range": (
406 PenState.PEN_IS_ERASING,
407 PenState.PEN_IS_OUT_OF_RANGE,
412 def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:
413 """Those tests are definitely not part of the Windows specification.
414 However, a half broken device might export those transitions.
415 For example, a pen that has the eraser button might wobble between
416 touching and erasing if the tablet doesn't enforce the Windows
419 "in-range -> touch -> erase -> hover-erase": (
420 PenState.PEN_IS_IN_RANGE,
421 PenState.PEN_IS_IN_CONTACT,
422 PenState.PEN_IS_ERASING,
423 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
425 "in-range -> erase -> hover-erase": (
426 PenState.PEN_IS_IN_RANGE,
427 PenState.PEN_IS_ERASING,
428 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
430 "hover-erase -> erase -> touch -> in-range": (
431 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
432 PenState.PEN_IS_ERASING,
433 PenState.PEN_IS_IN_CONTACT,
434 PenState.PEN_IS_IN_RANGE,
436 "hover-erase -> touch -> in-range": (
437 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
438 PenState.PEN_IS_IN_CONTACT,
439 PenState.PEN_IS_IN_RANGE,
441 "touch -> erase -> touch -> erase": (
442 PenState.PEN_IS_IN_CONTACT,
443 PenState.PEN_IS_ERASING,
444 PenState.PEN_IS_IN_CONTACT,
445 PenState.PEN_IS_ERASING,
451 def __init__(self, x, y):
454 self.tipswitch = False
455 self.tippressure = 15
460 self.barrelswitch = False
461 self.secondarybarrelswitch = False
467 self._old_values = None
468 self.current_state = None
471 if self._old_values is not None:
483 setattr(self, i, getattr(self._old_values, i))
486 self._old_values = copy.copy(self)
488 def __assert_axis(self, evdev, axis, value):
490 axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
491 and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
496 evdev.value[axis] == value
497 ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
499 def assert_expected_input_events(self, evdev, button):
500 assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
501 assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
503 # assert no other buttons than the tested ones are set
505 BtnPressed.PRIMARY_PRESSED,
506 BtnPressed.SECONDARY_PRESSED,
507 BtnPressed.THIRD_PRESSED,
509 if button is not None:
510 buttons.remove(button)
512 assert evdev.value[b.value] is None or evdev.value[b.value] == False
514 assert self.current_state == PenState.from_evdev(evdev, button)
517 class PenDigitizer(base.UHIDTestDevice):
525 input_info=(BusType.USB, 1, 2),
526 evdev_name_suffix=None,
528 super().__init__(name, application, rdesc_str, rdesc, input_info)
529 self.physical = physical
530 self.cur_application = application
531 if evdev_name_suffix is not None:
532 self.name += evdev_name_suffix
535 for r in self.parsed_rdesc.input_reports.values():
536 if r.application_name == self.application:
537 physicals = [f.physical_name for f in r]
538 if self.physical not in physicals and None not in physicals:
540 self.fields = [f.usage_name for f in r]
542 def move_to(self, pen, state, button):
543 # fill in the previous values
544 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
547 print(f"\n *** pen is moving to {state} ***")
549 if state == PenState.PEN_IS_OUT_OF_RANGE:
553 pen.tipswitch = False
564 pen.barrelswitch = False
565 pen.secondarybarrelswitch = False
566 elif state == PenState.PEN_IS_IN_RANGE:
567 pen.tipswitch = False
571 pen.barrelswitch = False
572 pen.secondarybarrelswitch = False
573 elif state == PenState.PEN_IS_IN_CONTACT:
578 pen.barrelswitch = False
579 pen.secondarybarrelswitch = False
580 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
581 pen.tipswitch = False
585 assert button is not None
586 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
587 pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
588 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
593 assert button is not None
594 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
595 pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
596 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
597 pen.tipswitch = False
601 pen.barrelswitch = False
602 pen.secondarybarrelswitch = False
603 elif state == PenState.PEN_IS_ERASING:
604 pen.tipswitch = False
608 pen.barrelswitch = False
609 pen.secondarybarrelswitch = False
611 pen.current_state = state
613 def event(self, pen, button):
615 r = self.create_report(application=self.cur_application, data=pen)
616 self.call_input_event(r)
620 def get_report(self, req, rnum, rtype):
621 if rtype != self.UHID_FEATURE_REPORT:
625 for v in self.parsed_rdesc.feature_reports.values():
626 if v.report_ID == rnum:
634 def set_report(self, req, rnum, rtype, data):
635 if rtype != self.UHID_FEATURE_REPORT:
639 for v in self.parsed_rdesc.feature_reports.values():
640 if v.report_ID == rnum:
650 class TestTablet(base.BaseTestCase.TestUhid):
651 def create_device(self):
652 raise Exception("please reimplement me in subclasses")
654 def post(self, uhdev, pen, test_button):
655 r = uhdev.event(pen, test_button)
656 events = uhdev.next_sync_events()
657 self.debug_reports(r, uhdev, events)
660 def validate_transitions(
661 self, from_state, pen, evdev, events, allow_intermediate_states, button
663 # check that the final state is correct
664 pen.assert_expected_input_events(evdev, button)
668 # check that the transitions are valid
670 while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:
671 # split the first EV_SYN from the list
672 idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))
673 sync_events = events[:idx]
674 events = events[idx + 1 :]
676 # now check for a valid transition
677 state = state.apply(sync_events, not allow_intermediate_states, button)
680 state = state.apply(sync_events, not allow_intermediate_states, button)
683 self, state_list, scribble, allow_intermediate_states, button=None
685 """Internal method to test against a list of
686 transition between states.
687 state_list is a list of PenState objects
688 scribble is a boolean which tells if we need
689 to wobble a little the X,Y coordinates of the pen
690 between each state transition."""
692 evdev = uhdev.get_evdev()
694 cur_state = PenState.PEN_IS_OUT_OF_RANGE
697 uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)
698 events = self.post(uhdev, p, button)
699 self.validate_transitions(
700 cur_state, p, evdev, events, allow_intermediate_states, button
703 cur_state = p.current_state
705 for state in state_list:
706 if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:
709 events = self.post(uhdev, p, button)
710 self.validate_transitions(
711 cur_state, p, evdev, events, allow_intermediate_states, button
713 assert len(events) >= 3 # X, Y, SYN
714 uhdev.move_to(p, state, button)
715 if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
718 events = self.post(uhdev, p, button)
719 self.validate_transitions(
720 cur_state, p, evdev, events, allow_intermediate_states, button
722 cur_state = p.current_state
724 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
725 @pytest.mark.parametrize(
727 [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
729 def test_valid_pen_states(self, state_list, scribble):
730 """This is the first half of the Windows Pen Implementation state machine:
731 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
732 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
734 self._test_states(state_list, scribble, allow_intermediate_states=False)
736 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
737 @pytest.mark.parametrize(
740 pytest.param(v, id=k)
741 for k, v in PenState.tolerated_transitions().items()
744 def test_tolerated_pen_states(self, state_list, scribble):
745 """This is not adhering to the Windows Pen Implementation state machine
746 but we should expect the kernel to behave properly, mostly for historical
748 self._test_states(state_list, scribble, allow_intermediate_states=True)
750 @pytest.mark.skip_if_uhdev(
751 lambda uhdev: "Barrel Switch" not in uhdev.fields,
752 "Device not compatible, missing Barrel Switch usage",
754 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
755 @pytest.mark.parametrize(
758 pytest.param(v, id=k)
759 for k, v in PenState.legal_transitions_with_button().items()
762 def test_valid_primary_button_pen_states(self, state_list, scribble):
763 """Rework the transition state machine by adding the primary button."""
767 allow_intermediate_states=False,
768 button=BtnPressed.PRIMARY_PRESSED,
771 @pytest.mark.skip_if_uhdev(
772 lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,
773 "Device not compatible, missing Secondary Barrel Switch usage",
775 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
776 @pytest.mark.parametrize(
779 pytest.param(v, id=k)
780 for k, v in PenState.legal_transitions_with_button().items()
783 def test_valid_secondary_button_pen_states(self, state_list, scribble):
784 """Rework the transition state machine by adding the secondary button."""
788 allow_intermediate_states=False,
789 button=BtnPressed.SECONDARY_PRESSED,
792 @pytest.mark.skip_if_uhdev(
793 lambda uhdev: "Third Barrel Switch" not in uhdev.fields,
794 "Device not compatible, missing Third Barrel Switch usage",
796 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
797 @pytest.mark.parametrize(
800 pytest.param(v, id=k)
801 for k, v in PenState.legal_transitions_with_button().items()
804 def test_valid_third_button_pen_states(self, state_list, scribble):
805 """Rework the transition state machine by adding the secondary button."""
809 allow_intermediate_states=False,
810 button=BtnPressed.THIRD_PRESSED,
813 @pytest.mark.skip_if_uhdev(
814 lambda uhdev: "Invert" not in uhdev.fields,
815 "Device not compatible, missing Invert usage",
817 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
818 @pytest.mark.parametrize(
821 pytest.param(v, id=k)
822 for k, v in PenState.legal_transitions_with_invert().items()
825 def test_valid_invert_pen_states(self, state_list, scribble):
826 """This is the second half of the Windows Pen Implementation state machine:
827 we now have Invert and Erase bits, so move in/out or proximity with the intend
829 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
831 self._test_states(state_list, scribble, allow_intermediate_states=False)
833 @pytest.mark.skip_if_uhdev(
834 lambda uhdev: "Invert" not in uhdev.fields,
835 "Device not compatible, missing Invert usage",
837 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
838 @pytest.mark.parametrize(
841 pytest.param(v, id=k)
842 for k, v in PenState.tolerated_transitions_with_invert().items()
845 def test_tolerated_invert_pen_states(self, state_list, scribble):
846 """This is the second half of the Windows Pen Implementation state machine:
847 we now have Invert and Erase bits, so move in/out or proximity with the intend
849 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
851 self._test_states(state_list, scribble, allow_intermediate_states=True)
853 @pytest.mark.skip_if_uhdev(
854 lambda uhdev: "Invert" not in uhdev.fields,
855 "Device not compatible, missing Invert usage",
857 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
858 @pytest.mark.parametrize(
860 [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],
862 def test_tolerated_broken_pen_states(self, state_list, scribble):
863 """Those tests are definitely not part of the Windows specification.
864 However, a half broken device might export those transitions.
865 For example, a pen that has the eraser button might wobble between
866 touching and erasing if the tablet doesn't enforce the Windows
868 self._test_states(state_list, scribble, allow_intermediate_states=True)
871 class GXTP_pen(PenDigitizer):
872 def event(self, pen, test_button):
873 if not hasattr(self, "prev_tip_state"):
874 self.prev_tip_state = False
876 internal_pen = copy.copy(pen)
878 # bug in the controller: when the pen touches the
879 # surface, in-range stays to 1, but when
880 # the pen moves in-range gets reverted to 0
881 if pen.tipswitch and self.prev_tip_state:
882 internal_pen.inrange = False
884 self.prev_tip_state = pen.tipswitch
886 # another bug in the controller: when the pen is
887 # inverted, invert is set to 1, but as soon as
888 # the pen touches the surface, eraser is correctly
889 # set to 1 but invert is released
891 internal_pen.invert = False
893 return super().event(internal_pen, test_button)
896 class USIPen(PenDigitizer):
900 class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):
902 Pen with two buttons and a rubber end, but which reports
903 the second button as an eraser
913 input_info=(BusType.USB, 0x28BD, 0x095B),
914 evdev_name_suffix=None,
917 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
919 self.fields.append("Secondary Barrel Switch")
921 def move_to(self, pen, state, button):
922 # fill in the previous values
923 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
926 print(f"\n *** pen is moving to {state} ***")
928 if state == PenState.PEN_IS_OUT_OF_RANGE:
932 pen.tipswitch = False
943 pen.barrelswitch = False
944 elif state == PenState.PEN_IS_IN_RANGE:
945 pen.tipswitch = False
949 pen.barrelswitch = False
950 elif state == PenState.PEN_IS_IN_CONTACT:
955 pen.barrelswitch = False
956 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
957 pen.tipswitch = False
960 assert button is not None
961 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
962 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
963 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
967 assert button is not None
968 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
969 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
970 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
971 pen.tipswitch = False
975 pen.barrelswitch = False
976 elif state == PenState.PEN_IS_ERASING:
981 pen.barrelswitch = False
983 pen.current_state = state
985 def event(self, pen, test_button):
988 pen_copy = copy.copy(pen)
991 tip_height = 0.055677699
992 hx = tip_height * (32767 / width)
993 hy = tip_height * (32767 / height)
994 if pen_copy.xtilt != 0:
995 pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))
996 if pen_copy.ytilt != 0:
997 pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))
999 return super().event(pen_copy, test_button)
1002 class XPPen_Artist24_28bd_093a(PenDigitizer):
1004 Pen that reports secondary barrel switch through eraser
1014 input_info=(BusType.USB, 0x28BD, 0x093A),
1015 evdev_name_suffix=None,
1018 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1020 self.fields.append("Secondary Barrel Switch")
1021 self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1023 def move_to(self, pen, state, button, debug=True):
1024 # fill in the previous values
1025 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1029 print(f"\n *** pen is moving to {state} ***")
1031 if state == PenState.PEN_IS_OUT_OF_RANGE:
1033 pen.tipswitch = False
1044 pen.barrelswitch = False
1045 elif state == PenState.PEN_IS_IN_RANGE:
1046 pen.tipswitch = False
1050 pen.barrelswitch = False
1051 elif state == PenState.PEN_IS_IN_CONTACT:
1052 pen.tipswitch = True
1056 pen.barrelswitch = False
1057 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1058 pen.tipswitch = False
1061 assert button is not None
1062 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1063 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1064 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1065 pen.tipswitch = True
1068 assert button is not None
1069 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1070 pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1072 pen.current_state = state
1074 def send_intermediate_state(self, pen, state, button):
1075 intermediate_pen = copy.copy(pen)
1076 self.move_to(intermediate_pen, state, button, debug=False)
1077 return super().event(intermediate_pen, button)
1079 def event(self, pen, button):
1082 # the pen reliably sends in-range events in a normal case (non emulation of eraser mode)
1083 if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1084 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1086 self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1089 if button == BtnPressed.SECONDARY_PRESSED:
1090 if self.previous_state == PenState.PEN_IS_IN_RANGE:
1091 if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1093 self.send_intermediate_state(
1094 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1098 if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1099 if pen.current_state == PenState.PEN_IS_IN_RANGE:
1101 self.send_intermediate_state(
1102 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1106 if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1107 if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1109 self.send_intermediate_state(
1110 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1114 self.send_intermediate_state(
1115 pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button
1119 if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1120 if pen.current_state == PenState.PEN_IS_IN_CONTACT:
1122 self.send_intermediate_state(
1123 pen, PenState.PEN_IS_OUT_OF_RANGE, button
1127 self.send_intermediate_state(
1128 pen, PenState.PEN_IS_IN_RANGE, button
1132 rs.extend(super().event(pen, button))
1133 self.previous_state = pen.current_state
1137 class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):
1139 Pen that reports secondary barrel switch through secondary TipSwtich
1140 and 3rd button through Invert
1148 application="Stylus",
1150 input_info=(BusType.USB, 0x256C, 0x006B),
1151 evdev_name_suffix=None,
1154 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1156 self.fields.append("Secondary Barrel Switch")
1157 self.fields.append("Third Barrel Switch")
1158 self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1160 def move_to(self, pen, state, button, debug=True):
1161 # fill in the previous values
1162 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1166 print(f"\n *** pen is moving to {state} ***")
1168 if state == PenState.PEN_IS_OUT_OF_RANGE:
1170 pen.tipswitch = False
1181 pen.barrelswitch = False
1182 pen.secondarytipswitch = False
1183 elif state == PenState.PEN_IS_IN_RANGE:
1184 pen.tipswitch = False
1188 pen.barrelswitch = False
1189 pen.secondarytipswitch = False
1190 elif state == PenState.PEN_IS_IN_CONTACT:
1191 pen.tipswitch = True
1195 pen.barrelswitch = False
1196 pen.secondarytipswitch = False
1197 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1198 pen.tipswitch = False
1201 assert button is not None
1202 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1203 pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1204 pen.invert = button == BtnPressed.THIRD_PRESSED
1205 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1206 pen.tipswitch = True
1209 assert button is not None
1210 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1211 pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1212 pen.invert = button == BtnPressed.THIRD_PRESSED
1213 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
1214 pen.tipswitch = False
1218 pen.barrelswitch = False
1219 pen.secondarytipswitch = False
1220 elif state == PenState.PEN_IS_ERASING:
1221 pen.tipswitch = False
1225 pen.barrelswitch = False
1226 pen.secondarytipswitch = False
1228 pen.current_state = state
1230 def call_input_event(self, report):
1231 if report[0] == 0x0a:
1232 # ensures the original second Eraser usage is null
1235 # ensures the original last bit is equal to bit 6 (In Range)
1236 if report[1] & 0x40:
1239 super().call_input_event(report)
1241 def send_intermediate_state(self, pen, state, test_button):
1242 intermediate_pen = copy.copy(pen)
1243 self.move_to(intermediate_pen, state, test_button, debug=False)
1244 return super().event(intermediate_pen, test_button)
1246 def event(self, pen, button):
1249 # it's not possible to go between eraser mode or not without
1250 # going out-of-prox: the eraser mode is activated by presenting
1251 # the tail of the pen
1252 if self.previous_state in (
1253 PenState.PEN_IS_IN_RANGE,
1254 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1255 PenState.PEN_IS_IN_CONTACT,
1256 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1257 ) and pen.current_state in (
1258 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1259 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1260 PenState.PEN_IS_ERASING,
1261 PenState.PEN_IS_ERASING_WITH_BUTTON,
1264 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1267 # same than above except from eraser to normal
1268 if self.previous_state in (
1269 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1270 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1271 PenState.PEN_IS_ERASING,
1272 PenState.PEN_IS_ERASING_WITH_BUTTON,
1273 ) and pen.current_state in (
1274 PenState.PEN_IS_IN_RANGE,
1275 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1276 PenState.PEN_IS_IN_CONTACT,
1277 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1280 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1283 if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:
1284 if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1286 self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1289 rs.extend(super().event(pen, button))
1290 self.previous_state = pen.current_state
1294 ################################################################################
1296 # Windows 7 compatible devices
1298 ################################################################################
1299 # class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):
1300 # def create_device(self):
1301 # return PenDigitizer('uhid test egalax-capacitive_0eef_7224',
1302 # 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',
1303 # input_info=(BusType.USB, 0x0eef, 0x7224),
1304 # evdev_name_suffix=' Touchscreen')
1307 # class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):
1308 # def create_device(self):
1309 # return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',
1310 # 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',
1311 # input_info=(BusType.USB, 0x0eef, 0x72fa),
1312 # evdev_name_suffix=' Touchscreen')
1315 # class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):
1316 # def create_device(self):
1317 # return PenDigitizer('uhid test egalax-capacitive_0eef_7336',
1318 # 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',
1319 # input_info=(BusType.USB, 0x0eef, 0x7336),
1320 # evdev_name_suffix=' Touchscreen')
1323 # class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):
1324 # def create_device(self):
1325 # return PenDigitizer('uhid test egalax-capacitive_0eef_7337',
1326 # 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',
1327 # input_info=(BusType.USB, 0x0eef, 0x7337),
1328 # evdev_name_suffix=' Touchscreen')
1331 # class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):
1332 # def create_device(self):
1333 # return PenDigitizer('uhid test egalax-capacitive_0eef_7349',
1334 # 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',
1335 # input_info=(BusType.USB, 0x0eef, 0x7349),
1336 # evdev_name_suffix=' Touchscreen')
1339 # class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):
1340 # def create_device(self):
1341 # return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',
1342 # 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',
1343 # input_info=(BusType.USB, 0x0eef, 0x73f4),
1344 # evdev_name_suffix=' Touchscreen')
1346 # bogus: BTN_TOOL_PEN is not emitted
1347 # class TestIrtouch_6615_0070(BaseTest.TestTablet):
1348 # def create_device(self):
1349 # return PenDigitizer('uhid test irtouch_6615_0070',
1350 # 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',
1351 # input_info=(BusType.USB, 0x6615, 0x0070))
1354 class TestNexio_1870_0100(BaseTest.TestTablet):
1355 def create_device(self):
1356 return PenDigitizer(
1357 "uhid test nexio_1870_0100",
1358 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",
1359 input_info=(BusType.USB, 0x1870, 0x0100),
1363 class TestNexio_1870_010d(BaseTest.TestTablet):
1364 def create_device(self):
1365 return PenDigitizer(
1366 "uhid test nexio_1870_010d",
1367 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",
1368 input_info=(BusType.USB, 0x1870, 0x010D),
1372 class TestNexio_1870_0119(BaseTest.TestTablet):
1373 def create_device(self):
1374 return PenDigitizer(
1375 "uhid test nexio_1870_0119",
1376 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",
1377 input_info=(BusType.USB, 0x1870, 0x0119),
1381 ################################################################################
1383 # Windows 8 compatible devices
1385 ################################################################################
1387 # bogus: application is 'undefined'
1388 # class Testatmel_03eb_8409(BaseTest.TestTablet):
1389 # def create_device(self):
1390 # 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')
1393 class Testatmel_03eb_840b(BaseTest.TestTablet):
1394 def create_device(self):
1395 return PenDigitizer(
1396 "uhid test atmel_03eb_840b",
1397 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",
1401 class Testn_trig_1b96_0c01(BaseTest.TestTablet):
1402 def create_device(self):
1403 return PenDigitizer(
1404 "uhid test n_trig_1b96_0c01",
1405 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",
1409 class Testn_trig_1b96_0c03(BaseTest.TestTablet):
1410 def create_device(self):
1411 return PenDigitizer(
1412 "uhid test n_trig_1b96_0c03",
1413 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",
1417 class Testn_trig_1b96_0f00(BaseTest.TestTablet):
1418 def create_device(self):
1419 return PenDigitizer(
1420 "uhid test n_trig_1b96_0f00",
1421 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",
1425 class Testn_trig_1b96_0f04(BaseTest.TestTablet):
1426 def create_device(self):
1427 return PenDigitizer(
1428 "uhid test n_trig_1b96_0f04",
1429 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",
1433 class Testn_trig_1b96_1000(BaseTest.TestTablet):
1434 def create_device(self):
1435 return PenDigitizer(
1436 "uhid test n_trig_1b96_1000",
1437 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",
1441 class TestGXTP_27c6_0113(BaseTest.TestTablet):
1442 def create_device(self):
1444 "uhid test GXTP_27c6_0113",
1445 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",
1449 ################################################################################
1451 # Windows 8 compatible devices with USI Pen
1453 ################################################################################
1456 class TestElan_04f3_2A49(BaseTest.TestTablet):
1457 def create_device(self):
1459 "uhid test Elan_04f3_2A49",
1460 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",
1461 input_info=(BusType.I2C, 0x04F3, 0x2A49),
1465 class TestGoodix_27c6_0e00(BaseTest.TestTablet):
1466 def create_device(self):
1468 "uhid test Elan_04f3_2A49",
1469 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",
1470 input_info=(BusType.I2C, 0x27C6, 0x0E00),
1474 class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
1475 hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)]
1477 def create_device(self):
1478 dev = XPPen_ArtistPro16Gen2_28bd_095b(
1479 "uhid test XPPen Artist Pro 16 Gen2 28bd 095b",
1480 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",
1481 input_info=(BusType.USB, 0x28BD, 0x095B),
1486 class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
1487 hid_bpfs = [("XPPen__Artist24.bpf.o", True)]
1489 def create_device(self):
1490 return XPPen_Artist24_28bd_093a(
1491 "uhid test XPPen Artist 24 28bd 093a",
1492 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",
1493 input_info=(BusType.USB, 0x28BD, 0x093A),
1497 class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
1498 hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)]
1500 def create_device(self):
1501 return Huion_Kamvas_Pro_19_256c_006b(
1502 "uhid test HUION Huion Tablet_GT1902",
1503 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",
1504 input_info=(BusType.USB, 0x256C, 0x006B),