1506 lines · python
1#!/bin/env python32# SPDX-License-Identifier: GPL-2.03# -*- 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 base10import copy11from enum import Enum12from hidtools.util import BusType13import libevdev14import logging15import pytest16from typing import Dict, List, Optional, Tuple17 18logger = logging.getLogger("hidtools.test.tablet")19 20 21class BtnTouch(Enum):22 """Represents whether the BTN_TOUCH event is set to True or False"""23 24 DOWN = True25 UP = False26 27 28class ToolType(Enum):29 PEN = libevdev.EV_KEY.BTN_TOOL_PEN30 RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER31 32 33class BtnPressed(Enum):34 """Represents whether a button is pressed on the stylus"""35 36 PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS37 SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS238 THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS339 40 41class PenState(Enum):42 """Pen states according to Microsoft reference:43 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states44 45 We extend it with the various buttons when we need to check them.46 """47 48 PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False49 PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False50 PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True51 PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False52 PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True53 PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False54 PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True55 PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False56 PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True57 58 def __init__(59 self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]60 ):61 self.touch = touch # type: ignore62 self.tool = tool # type: ignore63 self.button = button # type: ignore64 65 @classmethod66 def from_evdev(cls, evdev, test_button) -> "PenState":67 touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])68 tool = None69 button = False70 if (71 evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]72 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]73 ):74 tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)75 elif (76 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]77 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]78 ):79 tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)80 elif (81 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]82 or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]83 ):84 raise ValueError("2 tools are not allowed")85 86 # we take only the provided button into account87 if test_button is not None:88 button = bool(evdev.value[test_button.value])89 90 # the kernel tends to insert an EV_SYN once removing the tool, so91 # the button will be released after92 if tool is None:93 button = False94 95 return cls((touch, tool, button)) # type: ignore96 97 def apply(98 self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed99 ) -> "PenState":100 if libevdev.EV_SYN.SYN_REPORT in events:101 raise ValueError("EV_SYN is in the event sequence")102 touch = self.touch103 touch_found = False104 tool = self.tool105 tool_found = False106 button = self.button107 button_found = False108 109 for ev in events:110 if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):111 if touch_found:112 raise ValueError(f"duplicated BTN_TOUCH in {events}")113 touch_found = True114 touch = BtnTouch(ev.value)115 elif ev in (116 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),117 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),118 ):119 if tool_found:120 raise ValueError(f"duplicated BTN_TOOL_* in {events}")121 tool_found = True122 tool = ToolType(ev.code) if ev.value else None123 elif test_button is not None and ev in (test_button.value,):124 if button_found:125 raise ValueError(f"duplicated BTN_STYLUS* in {events}")126 button_found = True127 button = bool(ev.value)128 129 # the kernel tends to insert an EV_SYN once removing the tool, so130 # the button will be released after131 if tool is None:132 button = False133 134 new_state = PenState((touch, tool, button)) # type: ignore135 if strict:136 assert (137 new_state in self.valid_transitions()138 ), f"moving from {self} to {new_state} is forbidden"139 else:140 assert (141 new_state in self.historically_tolerated_transitions()142 ), f"moving from {self} to {new_state} is forbidden"143 144 return new_state145 146 def valid_transitions(self) -> Tuple["PenState", ...]:147 """Following the state machine in the URL above.148 149 Note that those transitions are from the evdev point of view, not HID"""150 if self == PenState.PEN_IS_OUT_OF_RANGE:151 return (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,159 )160 161 if self == PenState.PEN_IS_IN_RANGE:162 return (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,167 )168 169 if self == PenState.PEN_IS_IN_CONTACT:170 return (171 PenState.PEN_IS_IN_CONTACT,172 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,173 PenState.PEN_IS_IN_RANGE,174 )175 176 if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:177 return (178 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,179 PenState.PEN_IS_OUT_OF_RANGE,180 PenState.PEN_IS_ERASING,181 )182 183 if self == PenState.PEN_IS_ERASING:184 return (185 PenState.PEN_IS_ERASING,186 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,187 )188 189 if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:190 return (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,195 )196 197 if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:198 return (199 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,200 PenState.PEN_IS_IN_CONTACT,201 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,202 )203 204 return tuple()205 206 def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:207 """Following the state machine in the URL above, with a couple of addition208 for skipping the in-range state, due to historical reasons.209 210 Note that those transitions are from the evdev point of view, not HID"""211 if self == PenState.PEN_IS_OUT_OF_RANGE:212 return (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,220 )221 222 if self == PenState.PEN_IS_IN_RANGE:223 return (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,228 )229 230 if self == PenState.PEN_IS_IN_CONTACT:231 return (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,236 )237 238 if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:239 return (240 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,241 PenState.PEN_IS_OUT_OF_RANGE,242 PenState.PEN_IS_ERASING,243 )244 245 if self == PenState.PEN_IS_ERASING:246 return (247 PenState.PEN_IS_ERASING,248 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,249 PenState.PEN_IS_OUT_OF_RANGE,250 )251 252 if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:253 return (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,258 )259 260 if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:261 return (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,266 )267 268 return tuple()269 270 @staticmethod271 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-states275 """276 return {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,281 ),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,287 ),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,293 ),294 }295 296 @staticmethod297 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 intend300 to erase.301 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states302 """303 return {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,308 ),309 "hover-erasing -> erase": (310 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,311 PenState.PEN_IS_ERASING,312 ),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,317 ),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,323 ),324 "hover-erasing -> in-range": (325 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,326 PenState.PEN_IS_IN_RANGE,327 ),328 "in-range -> hover-erasing": (329 PenState.PEN_IS_IN_RANGE,330 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,331 ),332 }333 334 @staticmethod335 def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:336 """We revisit the Windows Pen Implementation state machine:337 we now have a button.338 """339 return {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,344 ),345 "in-range -> button-press": (346 PenState.PEN_IS_IN_RANGE,347 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,348 ),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,353 ),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,359 ),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,366 ),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,373 ),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,380 ),381 }382 383 @staticmethod384 def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:385 """This is not adhering to the Windows Pen Implementation state machine386 but we should expect the kernel to behave properly, mostly for historical387 reasons."""388 return {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,393 ),394 }395 396 @staticmethod397 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 intend400 to erase.401 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states402 """403 return {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,408 ),409 }410 411 @staticmethod412 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 between416 touching and erasing if the tablet doesn't enforce the Windows417 state machine."""418 return {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,424 ),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,429 ),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,435 ),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,440 ),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,446 ),447 }448 449 450class Pen(object):451 def __init__(self, x, y):452 self.x = x453 self.y = y454 self.tipswitch = False455 self.tippressure = 15456 self.azimuth = 0457 self.inrange = False458 self.width = 10459 self.height = 10460 self.barrelswitch = False461 self.secondarybarrelswitch = False462 self.invert = False463 self.eraser = False464 self.xtilt = 1465 self.ytilt = 1466 self.twist = 1467 self._old_values = None468 self.current_state = None469 470 def restore(self):471 if self._old_values is not None:472 for i in [473 "x",474 "y",475 "tippressure",476 "azimuth",477 "width",478 "height",479 "twist",480 "xtilt",481 "ytilt",482 ]:483 setattr(self, i, getattr(self._old_values, i))484 485 def backup(self):486 self._old_values = copy.copy(self)487 488 def __assert_axis(self, evdev, axis, value):489 if (490 axis == libevdev.EV_KEY.BTN_TOOL_RUBBER491 and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None492 ):493 return494 495 assert (496 evdev.value[axis] == value497 ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"498 499 def assert_expected_input_events(self, evdev, button):500 assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x501 assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y502 503 # assert no other buttons than the tested ones are set504 buttons = [505 BtnPressed.PRIMARY_PRESSED,506 BtnPressed.SECONDARY_PRESSED,507 BtnPressed.THIRD_PRESSED,508 ]509 if button is not None:510 buttons.remove(button)511 for b in buttons:512 assert evdev.value[b.value] is None or evdev.value[b.value] == False513 514 assert self.current_state == PenState.from_evdev(evdev, button)515 516 517class PenDigitizer(base.UHIDTestDevice):518 def __init__(519 self,520 name,521 rdesc_str=None,522 rdesc=None,523 application="Pen",524 physical="Stylus",525 input_info=(BusType.USB, 1, 2),526 evdev_name_suffix=None,527 ):528 super().__init__(name, application, rdesc_str, rdesc, input_info)529 self.physical = physical530 self.cur_application = application531 if evdev_name_suffix is not None:532 self.name += evdev_name_suffix533 534 self.fields = []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:539 continue540 self.fields = [f.usage_name for f in r]541 542 def move_to(self, pen, state, button):543 # fill in the previous values544 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:545 pen.restore()546 547 print(f"\n *** pen is moving to {state} ***")548 549 if state == PenState.PEN_IS_OUT_OF_RANGE:550 pen.backup()551 pen.x = 0552 pen.y = 0553 pen.tipswitch = False554 pen.tippressure = 0555 pen.azimuth = 0556 pen.inrange = False557 pen.width = 0558 pen.height = 0559 pen.invert = False560 pen.eraser = False561 pen.xtilt = 0562 pen.ytilt = 0563 pen.twist = 0564 pen.barrelswitch = False565 pen.secondarybarrelswitch = False566 elif state == PenState.PEN_IS_IN_RANGE:567 pen.tipswitch = False568 pen.inrange = True569 pen.invert = False570 pen.eraser = False571 pen.barrelswitch = False572 pen.secondarybarrelswitch = False573 elif state == PenState.PEN_IS_IN_CONTACT:574 pen.tipswitch = True575 pen.inrange = True576 pen.invert = False577 pen.eraser = False578 pen.barrelswitch = False579 pen.secondarybarrelswitch = False580 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:581 pen.tipswitch = False582 pen.inrange = True583 pen.invert = False584 pen.eraser = False585 assert button is not None586 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED587 pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED588 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:589 pen.tipswitch = True590 pen.inrange = True591 pen.invert = False592 pen.eraser = False593 assert button is not None594 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED595 pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED596 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:597 pen.tipswitch = False598 pen.inrange = True599 pen.invert = True600 pen.eraser = False601 pen.barrelswitch = False602 pen.secondarybarrelswitch = False603 elif state == PenState.PEN_IS_ERASING:604 pen.tipswitch = False605 pen.inrange = True606 pen.invert = False607 pen.eraser = True608 pen.barrelswitch = False609 pen.secondarybarrelswitch = False610 611 pen.current_state = state612 613 def event(self, pen, button):614 rs = []615 r = self.create_report(application=self.cur_application, data=pen)616 self.call_input_event(r)617 rs.append(r)618 return rs619 620 def get_report(self, req, rnum, rtype):621 if rtype != self.UHID_FEATURE_REPORT:622 return (1, [])623 624 rdesc = None625 for v in self.parsed_rdesc.feature_reports.values():626 if v.report_ID == rnum:627 rdesc = v628 629 if rdesc is None:630 return (1, [])631 632 return (1, [])633 634 def set_report(self, req, rnum, rtype, data):635 if rtype != self.UHID_FEATURE_REPORT:636 return 1637 638 rdesc = None639 for v in self.parsed_rdesc.feature_reports.values():640 if v.report_ID == rnum:641 rdesc = v642 643 if rdesc is None:644 return 1645 646 return 1647 648 649class BaseTest:650 class TestTablet(base.BaseTestCase.TestUhid):651 def create_device(self):652 raise Exception("please reimplement me in subclasses")653 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)658 return events659 660 def validate_transitions(661 self, from_state, pen, evdev, events, allow_intermediate_states, button662 ):663 # check that the final state is correct664 pen.assert_expected_input_events(evdev, button)665 666 state = from_state667 668 # check that the transitions are valid669 sync_events = []670 while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:671 # split the first EV_SYN from the list672 idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))673 sync_events = events[:idx]674 events = events[idx + 1 :]675 676 # now check for a valid transition677 state = state.apply(sync_events, not allow_intermediate_states, button)678 679 if events:680 state = state.apply(sync_events, not allow_intermediate_states, button)681 682 def _test_states(683 self, state_list, scribble, allow_intermediate_states, button=None684 ):685 """Internal method to test against a list of686 transition between states.687 state_list is a list of PenState objects688 scribble is a boolean which tells if we need689 to wobble a little the X,Y coordinates of the pen690 between each state transition."""691 uhdev = self.uhdev692 evdev = uhdev.get_evdev()693 694 cur_state = PenState.PEN_IS_OUT_OF_RANGE695 696 p = Pen(50, 60)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, button701 )702 703 cur_state = p.current_state704 705 for state in state_list:706 if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:707 p.x += 1708 p.y -= 1709 events = self.post(uhdev, p, button)710 self.validate_transitions(711 cur_state, p, evdev, events, allow_intermediate_states, button712 )713 assert len(events) >= 3 # X, Y, SYN714 uhdev.move_to(p, state, button)715 if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:716 p.x += 1717 p.y -= 1718 events = self.post(uhdev, p, button)719 self.validate_transitions(720 cur_state, p, evdev, events, allow_intermediate_states, button721 )722 cur_state = p.current_state723 724 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])725 @pytest.mark.parametrize(726 "state_list",727 [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],728 )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-states733 """734 self._test_states(state_list, scribble, allow_intermediate_states=False)735 736 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])737 @pytest.mark.parametrize(738 "state_list",739 [740 pytest.param(v, id=k)741 for k, v in PenState.tolerated_transitions().items()742 ],743 )744 def test_tolerated_pen_states(self, state_list, scribble):745 """This is not adhering to the Windows Pen Implementation state machine746 but we should expect the kernel to behave properly, mostly for historical747 reasons."""748 self._test_states(state_list, scribble, allow_intermediate_states=True)749 750 @pytest.mark.skip_if_uhdev(751 lambda uhdev: "Barrel Switch" not in uhdev.fields,752 "Device not compatible, missing Barrel Switch usage",753 )754 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])755 @pytest.mark.parametrize(756 "state_list",757 [758 pytest.param(v, id=k)759 for k, v in PenState.legal_transitions_with_button().items()760 ],761 )762 def test_valid_primary_button_pen_states(self, state_list, scribble):763 """Rework the transition state machine by adding the primary button."""764 self._test_states(765 state_list,766 scribble,767 allow_intermediate_states=False,768 button=BtnPressed.PRIMARY_PRESSED,769 )770 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",774 )775 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])776 @pytest.mark.parametrize(777 "state_list",778 [779 pytest.param(v, id=k)780 for k, v in PenState.legal_transitions_with_button().items()781 ],782 )783 def test_valid_secondary_button_pen_states(self, state_list, scribble):784 """Rework the transition state machine by adding the secondary button."""785 self._test_states(786 state_list,787 scribble,788 allow_intermediate_states=False,789 button=BtnPressed.SECONDARY_PRESSED,790 )791 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",795 )796 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])797 @pytest.mark.parametrize(798 "state_list",799 [800 pytest.param(v, id=k)801 for k, v in PenState.legal_transitions_with_button().items()802 ],803 )804 def test_valid_third_button_pen_states(self, state_list, scribble):805 """Rework the transition state machine by adding the secondary button."""806 self._test_states(807 state_list,808 scribble,809 allow_intermediate_states=False,810 button=BtnPressed.THIRD_PRESSED,811 )812 813 @pytest.mark.skip_if_uhdev(814 lambda uhdev: "Invert" not in uhdev.fields,815 "Device not compatible, missing Invert usage",816 )817 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])818 @pytest.mark.parametrize(819 "state_list",820 [821 pytest.param(v, id=k)822 for k, v in PenState.legal_transitions_with_invert().items()823 ],824 )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 intend828 to erase.829 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states830 """831 self._test_states(state_list, scribble, allow_intermediate_states=False)832 833 @pytest.mark.skip_if_uhdev(834 lambda uhdev: "Invert" not in uhdev.fields,835 "Device not compatible, missing Invert usage",836 )837 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])838 @pytest.mark.parametrize(839 "state_list",840 [841 pytest.param(v, id=k)842 for k, v in PenState.tolerated_transitions_with_invert().items()843 ],844 )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 intend848 to erase.849 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states850 """851 self._test_states(state_list, scribble, allow_intermediate_states=True)852 853 @pytest.mark.skip_if_uhdev(854 lambda uhdev: "Invert" not in uhdev.fields,855 "Device not compatible, missing Invert usage",856 )857 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])858 @pytest.mark.parametrize(859 "state_list",860 [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],861 )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 between866 touching and erasing if the tablet doesn't enforce the Windows867 state machine."""868 self._test_states(state_list, scribble, allow_intermediate_states=True)869 870 871class GXTP_pen(PenDigitizer):872 def event(self, pen, test_button):873 if not hasattr(self, "prev_tip_state"):874 self.prev_tip_state = False875 876 internal_pen = copy.copy(pen)877 878 # bug in the controller: when the pen touches the879 # surface, in-range stays to 1, but when880 # the pen moves in-range gets reverted to 0881 if pen.tipswitch and self.prev_tip_state:882 internal_pen.inrange = False883 884 self.prev_tip_state = pen.tipswitch885 886 # another bug in the controller: when the pen is887 # inverted, invert is set to 1, but as soon as888 # the pen touches the surface, eraser is correctly889 # set to 1 but invert is released890 if pen.eraser:891 internal_pen.invert = False892 893 return super().event(internal_pen, test_button)894 895 896class USIPen(PenDigitizer):897 pass898 899 900class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):901 """902 Pen with two buttons and a rubber end, but which reports903 the second button as an eraser904 """905 906 def __init__(907 self,908 name,909 rdesc_str=None,910 rdesc=None,911 application="Pen",912 physical="Stylus",913 input_info=(BusType.USB, 0x28BD, 0x095B),914 evdev_name_suffix=None,915 ):916 super().__init__(917 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix918 )919 self.fields.append("Secondary Barrel Switch")920 921 def move_to(self, pen, state, button):922 # fill in the previous values923 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:924 pen.restore()925 926 print(f"\n *** pen is moving to {state} ***")927 928 if state == PenState.PEN_IS_OUT_OF_RANGE:929 pen.backup()930 pen.x = 0931 pen.y = 0932 pen.tipswitch = False933 pen.tippressure = 0934 pen.azimuth = 0935 pen.inrange = False936 pen.width = 0937 pen.height = 0938 pen.invert = False939 pen.eraser = False940 pen.xtilt = 0941 pen.ytilt = 0942 pen.twist = 0943 pen.barrelswitch = False944 elif state == PenState.PEN_IS_IN_RANGE:945 pen.tipswitch = False946 pen.inrange = True947 pen.invert = False948 pen.eraser = False949 pen.barrelswitch = False950 elif state == PenState.PEN_IS_IN_CONTACT:951 pen.tipswitch = True952 pen.inrange = True953 pen.invert = False954 pen.eraser = False955 pen.barrelswitch = False956 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:957 pen.tipswitch = False958 pen.inrange = True959 pen.invert = False960 assert button is not None961 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED962 pen.eraser = button == BtnPressed.SECONDARY_PRESSED963 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:964 pen.tipswitch = True965 pen.inrange = True966 pen.invert = False967 assert button is not None968 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED969 pen.eraser = button == BtnPressed.SECONDARY_PRESSED970 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:971 pen.tipswitch = False972 pen.inrange = True973 pen.invert = True974 pen.eraser = False975 pen.barrelswitch = False976 elif state == PenState.PEN_IS_ERASING:977 pen.tipswitch = True978 pen.inrange = True979 pen.invert = True980 pen.eraser = False981 pen.barrelswitch = False982 983 pen.current_state = state984 985 def event(self, pen, test_button):986 import math987 988 pen_copy = copy.copy(pen)989 width = 13.567990 height = 8.480991 tip_height = 0.055677699992 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)))998 999 return super().event(pen_copy, test_button)1000 1001 1002class XPPen_Artist24_28bd_093a(PenDigitizer):1003 """1004 Pen that reports secondary barrel switch through eraser1005 """1006 1007 def __init__(1008 self,1009 name,1010 rdesc_str=None,1011 rdesc=None,1012 application="Pen",1013 physical="Stylus",1014 input_info=(BusType.USB, 0x28BD, 0x093A),1015 evdev_name_suffix=None,1016 ):1017 super().__init__(1018 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1019 )1020 self.fields.append("Secondary Barrel Switch")1021 self.previous_state = PenState.PEN_IS_OUT_OF_RANGE1022 1023 def move_to(self, pen, state, button, debug=True):1024 # fill in the previous values1025 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1026 pen.restore()1027 1028 if debug:1029 print(f"\n *** pen is moving to {state} ***")1030 1031 if state == PenState.PEN_IS_OUT_OF_RANGE:1032 pen.backup()1033 pen.tipswitch = False1034 pen.tippressure = 01035 pen.azimuth = 01036 pen.inrange = False1037 pen.width = 01038 pen.height = 01039 pen.invert = False1040 pen.eraser = False1041 pen.xtilt = 01042 pen.ytilt = 01043 pen.twist = 01044 pen.barrelswitch = False1045 elif state == PenState.PEN_IS_IN_RANGE:1046 pen.tipswitch = False1047 pen.inrange = True1048 pen.invert = False1049 pen.eraser = False1050 pen.barrelswitch = False1051 elif state == PenState.PEN_IS_IN_CONTACT:1052 pen.tipswitch = True1053 pen.inrange = True1054 pen.invert = False1055 pen.eraser = False1056 pen.barrelswitch = False1057 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1058 pen.tipswitch = False1059 pen.inrange = True1060 pen.invert = False1061 assert button is not None1062 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1063 pen.eraser = button == BtnPressed.SECONDARY_PRESSED1064 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1065 pen.tipswitch = True1066 pen.inrange = True1067 pen.invert = False1068 assert button is not None1069 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1070 pen.eraser = button == BtnPressed.SECONDARY_PRESSED1071 1072 pen.current_state = state1073 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)1078 1079 def event(self, pen, button):1080 rs = []1081 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:1085 rs.extend(1086 self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1087 )1088 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:1092 rs.extend(1093 self.send_intermediate_state(1094 pen, PenState.PEN_IS_OUT_OF_RANGE, button1095 )1096 )1097 1098 if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1099 if pen.current_state == PenState.PEN_IS_IN_RANGE:1100 rs.extend(1101 self.send_intermediate_state(1102 pen, PenState.PEN_IS_OUT_OF_RANGE, button1103 )1104 )1105 1106 if self.previous_state == PenState.PEN_IS_IN_CONTACT:1107 if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1108 rs.extend(1109 self.send_intermediate_state(1110 pen, PenState.PEN_IS_OUT_OF_RANGE, button1111 )1112 )1113 rs.extend(1114 self.send_intermediate_state(1115 pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button1116 )1117 )1118 1119 if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1120 if pen.current_state == PenState.PEN_IS_IN_CONTACT:1121 rs.extend(1122 self.send_intermediate_state(1123 pen, PenState.PEN_IS_OUT_OF_RANGE, button1124 )1125 )1126 rs.extend(1127 self.send_intermediate_state(1128 pen, PenState.PEN_IS_IN_RANGE, button1129 )1130 )1131 1132 rs.extend(super().event(pen, button))1133 self.previous_state = pen.current_state1134 return rs1135 1136 1137class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):1138 """1139 Pen that reports secondary barrel switch through secondary TipSwtich1140 and 3rd button through Invert1141 """1142 1143 def __init__(1144 self,1145 name,1146 rdesc_str=None,1147 rdesc=None,1148 application="Stylus",1149 physical=None,1150 input_info=(BusType.USB, 0x256C, 0x006B),1151 evdev_name_suffix=None,1152 ):1153 super().__init__(1154 name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix1155 )1156 self.fields.append("Secondary Barrel Switch")1157 self.fields.append("Third Barrel Switch")1158 self.previous_state = PenState.PEN_IS_OUT_OF_RANGE1159 1160 def move_to(self, pen, state, button, debug=True):1161 # fill in the previous values1162 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:1163 pen.restore()1164 1165 if debug:1166 print(f"\n *** pen is moving to {state} ***")1167 1168 if state == PenState.PEN_IS_OUT_OF_RANGE:1169 pen.backup()1170 pen.tipswitch = False1171 pen.tippressure = 01172 pen.azimuth = 01173 pen.inrange = False1174 pen.width = 01175 pen.height = 01176 pen.invert = False1177 pen.eraser = False1178 pen.xtilt = 01179 pen.ytilt = 01180 pen.twist = 01181 pen.barrelswitch = False1182 pen.secondarytipswitch = False1183 elif state == PenState.PEN_IS_IN_RANGE:1184 pen.tipswitch = False1185 pen.inrange = True1186 pen.invert = False1187 pen.eraser = False1188 pen.barrelswitch = False1189 pen.secondarytipswitch = False1190 elif state == PenState.PEN_IS_IN_CONTACT:1191 pen.tipswitch = True1192 pen.inrange = True1193 pen.invert = False1194 pen.eraser = False1195 pen.barrelswitch = False1196 pen.secondarytipswitch = False1197 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1198 pen.tipswitch = False1199 pen.inrange = True1200 pen.eraser = False1201 assert button is not None1202 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1203 pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1204 pen.invert = button == BtnPressed.THIRD_PRESSED1205 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:1206 pen.tipswitch = True1207 pen.inrange = True1208 pen.eraser = False1209 assert button is not None1210 pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED1211 pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED1212 pen.invert = button == BtnPressed.THIRD_PRESSED1213 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:1214 pen.tipswitch = False1215 pen.inrange = True1216 pen.invert = True1217 pen.eraser = False1218 pen.barrelswitch = False1219 pen.secondarytipswitch = False1220 elif state == PenState.PEN_IS_ERASING:1221 pen.tipswitch = False1222 pen.inrange = True1223 pen.invert = False1224 pen.eraser = True1225 pen.barrelswitch = False1226 pen.secondarytipswitch = False1227 1228 pen.current_state = state1229 1230 def call_input_event(self, report):1231 if report[0] == 0x0a:1232 # ensures the original second Eraser usage is null1233 report[1] &= 0xdf1234 1235 # ensures the original last bit is equal to bit 6 (In Range)1236 if report[1] & 0x40:1237 report[1] |= 0x801238 1239 super().call_input_event(report)1240 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)1245 1246 def event(self, pen, button):1247 rs = []1248 1249 # it's not possible to go between eraser mode or not without1250 # going out-of-prox: the eraser mode is activated by presenting1251 # the tail of the pen1252 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,1262 ):1263 rs.extend(1264 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1265 )1266 1267 # same than above except from eraser to normal1268 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,1278 ):1279 rs.extend(1280 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)1281 )1282 1283 if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:1284 if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:1285 rs.extend(1286 self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)1287 )1288 1289 rs.extend(super().event(pen, button))1290 self.previous_state = pen.current_state1291 return rs1292 1293 1294################################################################################1295#1296# Windows 7 compatible devices1297#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')1305#1306#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')1313#1314#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')1321#1322#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')1329#1330#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')1337#1338#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')1345#1346# bogus: BTN_TOOL_PEN is not emitted1347# 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))1352 1353 1354class 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),1360 )1361 1362 1363class 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),1369 )1370 1371 1372class 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),1378 )1379 1380 1381################################################################################1382#1383# Windows 8 compatible devices1384#1385################################################################################1386 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')1391 1392 1393class 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",1398 )1399 1400 1401class 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",1406 )1407 1408 1409class 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",1414 )1415 1416 1417class 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",1422 )1423 1424 1425class 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",1430 )1431 1432 1433class 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",1438 )1439 1440 1441class TestGXTP_27c6_0113(BaseTest.TestTablet):1442 def create_device(self):1443 return GXTP_pen(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",1446 )1447 1448 1449################################################################################1450#1451# Windows 8 compatible devices with USI Pen1452#1453################################################################################1454 1455 1456class TestElan_04f3_2A49(BaseTest.TestTablet):1457 def create_device(self):1458 return USIPen(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),1462 )1463 1464 1465class TestGoodix_27c6_0e00(BaseTest.TestTablet):1466 def create_device(self):1467 return USIPen(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),1471 )1472 1473 1474class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):1475 hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)]1476 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),1482 )1483 return dev1484 1485 1486class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):1487 hid_bpfs = [("XPPen__Artist24.bpf.o", True)]1488 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),1494 )1495 1496 1497class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):1498 hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)]1499 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),1505 )1506