1#!/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# -*- coding: utf-8 -*- 4# 5# Copyright (c) 2021 Benjamin Tissoires <benjamin.tissoires@gmail.com> 6# Copyright (c) 2021 Red Hat, Inc. 7# 8 9from . import base 10import copy 11from enum import Enum 12from hidtools.util import BusType 13import libevdev 14import logging 15import pytest 16from typing import Dict, List, Optional, Tuple 17 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 = True 25 UP = False 26 27 28class ToolType(Enum): 29 PEN = libevdev.EV_KEY.BTN_TOOL_PEN 30 RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER 31 32 33class BtnPressed(Enum): 34 """Represents whether a button is pressed on the stylus""" 35 36 PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS 37 SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2 38 39 40class PenState(Enum): 41 """Pen states according to Microsoft reference: 42 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 43 44 We extend it with the various buttons when we need to check them. 45 """ 46 47 PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, None 48 PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, None 49 PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, BtnPressed.PRIMARY_PRESSED 50 PEN_IS_IN_RANGE_WITH_SECOND_BUTTON = ( 51 BtnTouch.UP, 52 ToolType.PEN, 53 BtnPressed.SECONDARY_PRESSED, 54 ) 55 PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, None 56 PEN_IS_IN_CONTACT_WITH_BUTTON = ( 57 BtnTouch.DOWN, 58 ToolType.PEN, 59 BtnPressed.PRIMARY_PRESSED, 60 ) 61 PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON = ( 62 BtnTouch.DOWN, 63 ToolType.PEN, 64 BtnPressed.SECONDARY_PRESSED, 65 ) 66 PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, None 67 PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = ( 68 BtnTouch.UP, 69 ToolType.RUBBER, 70 BtnPressed.PRIMARY_PRESSED, 71 ) 72 PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_SECOND_BUTTON = ( 73 BtnTouch.UP, 74 ToolType.RUBBER, 75 BtnPressed.SECONDARY_PRESSED, 76 ) 77 PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, None 78 PEN_IS_ERASING_WITH_BUTTON = ( 79 BtnTouch.DOWN, 80 ToolType.RUBBER, 81 BtnPressed.PRIMARY_PRESSED, 82 ) 83 PEN_IS_ERASING_WITH_SECOND_BUTTON = ( 84 BtnTouch.DOWN, 85 ToolType.RUBBER, 86 BtnPressed.SECONDARY_PRESSED, 87 ) 88 89 def __init__(self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[BtnPressed]): 90 self.touch = touch # type: ignore 91 self.tool = tool # type: ignore 92 self.button = button # type: ignore 93 94 @classmethod 95 def from_evdev(cls, evdev) -> "PenState": 96 touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) 97 tool = None 98 button = None 99 if ( 100 evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] 101 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] 102 ): 103 tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER) 104 elif ( 105 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] 106 and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] 107 ): 108 tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN) 109 elif ( 110 evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] 111 or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] 112 ): 113 raise ValueError("2 tools are not allowed") 114 115 # we take only the highest button in account 116 for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]: 117 if bool(evdev.value[b]): 118 button = BtnPressed(b) 119 120 # the kernel tends to insert an EV_SYN once removing the tool, so 121 # the button will be released after 122 if tool is None: 123 button = None 124 125 return cls((touch, tool, button)) # type: ignore 126 127 def apply(self, events: List[libevdev.InputEvent], strict: bool) -> "PenState": 128 if libevdev.EV_SYN.SYN_REPORT in events: 129 raise ValueError("EV_SYN is in the event sequence") 130 touch = self.touch 131 touch_found = False 132 tool = self.tool 133 tool_found = False 134 button = self.button 135 button_found = False 136 137 for ev in events: 138 if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH): 139 if touch_found: 140 raise ValueError(f"duplicated BTN_TOUCH in {events}") 141 touch_found = True 142 touch = BtnTouch(ev.value) 143 elif ev in ( 144 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN), 145 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER), 146 ): 147 if tool_found: 148 raise ValueError(f"duplicated BTN_TOOL_* in {events}") 149 tool_found = True 150 tool = ToolType(ev.code) if ev.value else None 151 elif ev in ( 152 libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS), 153 libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2), 154 ): 155 if button_found: 156 raise ValueError(f"duplicated BTN_STYLUS* in {events}") 157 button_found = True 158 button = BtnPressed(ev.code) if ev.value else None 159 160 # the kernel tends to insert an EV_SYN once removing the tool, so 161 # the button will be released after 162 if tool is None: 163 button = None 164 165 new_state = PenState((touch, tool, button)) # type: ignore 166 if strict: 167 assert ( 168 new_state in self.valid_transitions() 169 ), f"moving from {self} to {new_state} is forbidden" 170 else: 171 assert ( 172 new_state in self.historically_tolerated_transitions() 173 ), f"moving from {self} to {new_state} is forbidden" 174 175 return new_state 176 177 def valid_transitions(self) -> Tuple["PenState", ...]: 178 """Following the state machine in the URL above. 179 180 Note that those transitions are from the evdev point of view, not HID""" 181 if self == PenState.PEN_IS_OUT_OF_RANGE: 182 return ( 183 PenState.PEN_IS_OUT_OF_RANGE, 184 PenState.PEN_IS_IN_RANGE, 185 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 186 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 187 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 188 PenState.PEN_IS_IN_CONTACT, 189 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 190 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 191 PenState.PEN_IS_ERASING, 192 ) 193 194 if self == PenState.PEN_IS_IN_RANGE: 195 return ( 196 PenState.PEN_IS_IN_RANGE, 197 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 198 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 199 PenState.PEN_IS_OUT_OF_RANGE, 200 PenState.PEN_IS_IN_CONTACT, 201 ) 202 203 if self == PenState.PEN_IS_IN_CONTACT: 204 return ( 205 PenState.PEN_IS_IN_CONTACT, 206 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 207 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 208 PenState.PEN_IS_IN_RANGE, 209 ) 210 211 if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: 212 return ( 213 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 214 PenState.PEN_IS_OUT_OF_RANGE, 215 PenState.PEN_IS_ERASING, 216 ) 217 218 if self == PenState.PEN_IS_ERASING: 219 return ( 220 PenState.PEN_IS_ERASING, 221 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 222 ) 223 224 if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: 225 return ( 226 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 227 PenState.PEN_IS_IN_RANGE, 228 PenState.PEN_IS_OUT_OF_RANGE, 229 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 230 ) 231 232 if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: 233 return ( 234 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 235 PenState.PEN_IS_IN_CONTACT, 236 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 237 ) 238 239 if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: 240 return ( 241 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 242 PenState.PEN_IS_IN_RANGE, 243 PenState.PEN_IS_OUT_OF_RANGE, 244 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 245 ) 246 247 if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: 248 return ( 249 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 250 PenState.PEN_IS_IN_CONTACT, 251 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 252 ) 253 254 return tuple() 255 256 def historically_tolerated_transitions(self) -> Tuple["PenState", ...]: 257 """Following the state machine in the URL above, with a couple of addition 258 for skipping the in-range state, due to historical reasons. 259 260 Note that those transitions are from the evdev point of view, not HID""" 261 if self == PenState.PEN_IS_OUT_OF_RANGE: 262 return ( 263 PenState.PEN_IS_OUT_OF_RANGE, 264 PenState.PEN_IS_IN_RANGE, 265 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 266 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 267 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 268 PenState.PEN_IS_IN_CONTACT, 269 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 270 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 271 PenState.PEN_IS_ERASING, 272 ) 273 274 if self == PenState.PEN_IS_IN_RANGE: 275 return ( 276 PenState.PEN_IS_IN_RANGE, 277 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 278 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 279 PenState.PEN_IS_OUT_OF_RANGE, 280 PenState.PEN_IS_IN_CONTACT, 281 ) 282 283 if self == PenState.PEN_IS_IN_CONTACT: 284 return ( 285 PenState.PEN_IS_IN_CONTACT, 286 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 287 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 288 PenState.PEN_IS_IN_RANGE, 289 PenState.PEN_IS_OUT_OF_RANGE, 290 ) 291 292 if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: 293 return ( 294 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 295 PenState.PEN_IS_OUT_OF_RANGE, 296 PenState.PEN_IS_ERASING, 297 ) 298 299 if self == PenState.PEN_IS_ERASING: 300 return ( 301 PenState.PEN_IS_ERASING, 302 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 303 PenState.PEN_IS_OUT_OF_RANGE, 304 ) 305 306 if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: 307 return ( 308 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 309 PenState.PEN_IS_IN_RANGE, 310 PenState.PEN_IS_OUT_OF_RANGE, 311 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 312 ) 313 314 if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: 315 return ( 316 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 317 PenState.PEN_IS_IN_CONTACT, 318 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 319 PenState.PEN_IS_OUT_OF_RANGE, 320 ) 321 322 if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: 323 return ( 324 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 325 PenState.PEN_IS_IN_RANGE, 326 PenState.PEN_IS_OUT_OF_RANGE, 327 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 328 ) 329 330 if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: 331 return ( 332 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 333 PenState.PEN_IS_IN_CONTACT, 334 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 335 PenState.PEN_IS_OUT_OF_RANGE, 336 ) 337 338 return tuple() 339 340 @staticmethod 341 def legal_transitions() -> Dict[str, Tuple["PenState", ...]]: 342 """This is the first half of the Windows Pen Implementation state machine: 343 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. 344 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 345 """ 346 return { 347 "in-range": (PenState.PEN_IS_IN_RANGE,), 348 "in-range -> out-of-range": ( 349 PenState.PEN_IS_IN_RANGE, 350 PenState.PEN_IS_OUT_OF_RANGE, 351 ), 352 "in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT), 353 "in-range -> touch -> release": ( 354 PenState.PEN_IS_IN_RANGE, 355 PenState.PEN_IS_IN_CONTACT, 356 PenState.PEN_IS_IN_RANGE, 357 ), 358 "in-range -> touch -> release -> out-of-range": ( 359 PenState.PEN_IS_IN_RANGE, 360 PenState.PEN_IS_IN_CONTACT, 361 PenState.PEN_IS_IN_RANGE, 362 PenState.PEN_IS_OUT_OF_RANGE, 363 ), 364 } 365 366 @staticmethod 367 def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]: 368 """This is the second half of the Windows Pen Implementation state machine: 369 we now have Invert and Erase bits, so move in/out or proximity with the intend 370 to erase. 371 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 372 """ 373 return { 374 "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,), 375 "hover-erasing -> out-of-range": ( 376 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 377 PenState.PEN_IS_OUT_OF_RANGE, 378 ), 379 "hover-erasing -> erase": ( 380 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 381 PenState.PEN_IS_ERASING, 382 ), 383 "hover-erasing -> erase -> release": ( 384 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 385 PenState.PEN_IS_ERASING, 386 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 387 ), 388 "hover-erasing -> erase -> release -> out-of-range": ( 389 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 390 PenState.PEN_IS_ERASING, 391 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 392 PenState.PEN_IS_OUT_OF_RANGE, 393 ), 394 "hover-erasing -> in-range": ( 395 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 396 PenState.PEN_IS_IN_RANGE, 397 ), 398 "in-range -> hover-erasing": ( 399 PenState.PEN_IS_IN_RANGE, 400 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 401 ), 402 } 403 404 @staticmethod 405 def legal_transitions_with_primary_button() -> Dict[str, Tuple["PenState", ...]]: 406 """We revisit the Windows Pen Implementation state machine: 407 we now have a primary button. 408 """ 409 return { 410 "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,), 411 "hover-button -> out-of-range": ( 412 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 413 PenState.PEN_IS_OUT_OF_RANGE, 414 ), 415 "in-range -> button-press": ( 416 PenState.PEN_IS_IN_RANGE, 417 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 418 ), 419 "in-range -> button-press -> button-release": ( 420 PenState.PEN_IS_IN_RANGE, 421 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 422 PenState.PEN_IS_IN_RANGE, 423 ), 424 "in-range -> touch -> button-press -> button-release": ( 425 PenState.PEN_IS_IN_RANGE, 426 PenState.PEN_IS_IN_CONTACT, 427 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 428 PenState.PEN_IS_IN_CONTACT, 429 ), 430 "in-range -> touch -> button-press -> release -> button-release": ( 431 PenState.PEN_IS_IN_RANGE, 432 PenState.PEN_IS_IN_CONTACT, 433 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 434 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 435 PenState.PEN_IS_IN_RANGE, 436 ), 437 "in-range -> button-press -> touch -> release -> button-release": ( 438 PenState.PEN_IS_IN_RANGE, 439 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 440 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 441 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 442 PenState.PEN_IS_IN_RANGE, 443 ), 444 "in-range -> button-press -> touch -> button-release -> release": ( 445 PenState.PEN_IS_IN_RANGE, 446 PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 447 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, 448 PenState.PEN_IS_IN_CONTACT, 449 PenState.PEN_IS_IN_RANGE, 450 ), 451 } 452 453 @staticmethod 454 def legal_transitions_with_secondary_button() -> Dict[str, Tuple["PenState", ...]]: 455 """We revisit the Windows Pen Implementation state machine: 456 we now have a secondary button. 457 Note: we don't looks for 2 buttons interactions. 458 """ 459 return { 460 "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,), 461 "hover-button -> out-of-range": ( 462 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 463 PenState.PEN_IS_OUT_OF_RANGE, 464 ), 465 "in-range -> button-press": ( 466 PenState.PEN_IS_IN_RANGE, 467 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 468 ), 469 "in-range -> button-press -> button-release": ( 470 PenState.PEN_IS_IN_RANGE, 471 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 472 PenState.PEN_IS_IN_RANGE, 473 ), 474 "in-range -> touch -> button-press -> button-release": ( 475 PenState.PEN_IS_IN_RANGE, 476 PenState.PEN_IS_IN_CONTACT, 477 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 478 PenState.PEN_IS_IN_CONTACT, 479 ), 480 "in-range -> touch -> button-press -> release -> button-release": ( 481 PenState.PEN_IS_IN_RANGE, 482 PenState.PEN_IS_IN_CONTACT, 483 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 484 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 485 PenState.PEN_IS_IN_RANGE, 486 ), 487 "in-range -> button-press -> touch -> release -> button-release": ( 488 PenState.PEN_IS_IN_RANGE, 489 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 490 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 491 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 492 PenState.PEN_IS_IN_RANGE, 493 ), 494 "in-range -> button-press -> touch -> button-release -> release": ( 495 PenState.PEN_IS_IN_RANGE, 496 PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, 497 PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, 498 PenState.PEN_IS_IN_CONTACT, 499 PenState.PEN_IS_IN_RANGE, 500 ), 501 } 502 503 @staticmethod 504 def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]: 505 """This is not adhering to the Windows Pen Implementation state machine 506 but we should expect the kernel to behave properly, mostly for historical 507 reasons.""" 508 return { 509 "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,), 510 "direct-in-contact -> out-of-range": ( 511 PenState.PEN_IS_IN_CONTACT, 512 PenState.PEN_IS_OUT_OF_RANGE, 513 ), 514 } 515 516 @staticmethod 517 def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]: 518 """This is the second half of the Windows Pen Implementation state machine: 519 we now have Invert and Erase bits, so move in/out or proximity with the intend 520 to erase. 521 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 522 """ 523 return { 524 "direct-erase": (PenState.PEN_IS_ERASING,), 525 "direct-erase -> out-of-range": ( 526 PenState.PEN_IS_ERASING, 527 PenState.PEN_IS_OUT_OF_RANGE, 528 ), 529 } 530 531 @staticmethod 532 def broken_transitions() -> Dict[str, Tuple["PenState", ...]]: 533 """Those tests are definitely not part of the Windows specification. 534 However, a half broken device might export those transitions. 535 For example, a pen that has the eraser button might wobble between 536 touching and erasing if the tablet doesn't enforce the Windows 537 state machine.""" 538 return { 539 "in-range -> touch -> erase -> hover-erase": ( 540 PenState.PEN_IS_IN_RANGE, 541 PenState.PEN_IS_IN_CONTACT, 542 PenState.PEN_IS_ERASING, 543 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 544 ), 545 "in-range -> erase -> hover-erase": ( 546 PenState.PEN_IS_IN_RANGE, 547 PenState.PEN_IS_ERASING, 548 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 549 ), 550 "hover-erase -> erase -> touch -> in-range": ( 551 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 552 PenState.PEN_IS_ERASING, 553 PenState.PEN_IS_IN_CONTACT, 554 PenState.PEN_IS_IN_RANGE, 555 ), 556 "hover-erase -> touch -> in-range": ( 557 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, 558 PenState.PEN_IS_IN_CONTACT, 559 PenState.PEN_IS_IN_RANGE, 560 ), 561 "touch -> erase -> touch -> erase": ( 562 PenState.PEN_IS_IN_CONTACT, 563 PenState.PEN_IS_ERASING, 564 PenState.PEN_IS_IN_CONTACT, 565 PenState.PEN_IS_ERASING, 566 ), 567 } 568 569 570class Pen(object): 571 def __init__(self, x, y): 572 self.x = x 573 self.y = y 574 self.tipswitch = False 575 self.tippressure = 15 576 self.azimuth = 0 577 self.inrange = False 578 self.width = 10 579 self.height = 10 580 self.barrelswitch = False 581 self.secondarybarrelswitch = False 582 self.invert = False 583 self.eraser = False 584 self.xtilt = 1 585 self.ytilt = 1 586 self.twist = 1 587 self._old_values = None 588 self.current_state = None 589 590 def restore(self): 591 if self._old_values is not None: 592 for i in [ 593 "x", 594 "y", 595 "tippressure", 596 "azimuth", 597 "width", 598 "height", 599 "twist", 600 "xtilt", 601 "ytilt", 602 ]: 603 setattr(self, i, getattr(self._old_values, i)) 604 605 def backup(self): 606 self._old_values = copy.copy(self) 607 608 def __assert_axis(self, evdev, axis, value): 609 if ( 610 axis == libevdev.EV_KEY.BTN_TOOL_RUBBER 611 and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None 612 ): 613 return 614 615 assert ( 616 evdev.value[axis] == value 617 ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}" 618 619 def assert_expected_input_events(self, evdev): 620 assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x 621 assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y 622 assert self.current_state == PenState.from_evdev(evdev) 623 624 625class PenDigitizer(base.UHIDTestDevice): 626 def __init__( 627 self, 628 name, 629 rdesc_str=None, 630 rdesc=None, 631 application="Pen", 632 physical="Stylus", 633 input_info=(BusType.USB, 1, 2), 634 evdev_name_suffix=None, 635 ): 636 super().__init__(name, application, rdesc_str, rdesc, input_info) 637 self.physical = physical 638 self.cur_application = application 639 if evdev_name_suffix is not None: 640 self.name += evdev_name_suffix 641 642 self.fields = [] 643 for r in self.parsed_rdesc.input_reports.values(): 644 if r.application_name == self.application: 645 physicals = [f.physical_name for f in r] 646 if self.physical not in physicals and None not in physicals: 647 continue 648 self.fields = [f.usage_name for f in r] 649 650 def move_to(self, pen, state): 651 # fill in the previous values 652 if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE: 653 pen.restore() 654 655 print(f"\n *** pen is moving to {state} ***") 656 657 if state == PenState.PEN_IS_OUT_OF_RANGE: 658 pen.backup() 659 pen.x = 0 660 pen.y = 0 661 pen.tipswitch = False 662 pen.tippressure = 0 663 pen.azimuth = 0 664 pen.inrange = False 665 pen.width = 0 666 pen.height = 0 667 pen.invert = False 668 pen.eraser = False 669 pen.xtilt = 0 670 pen.ytilt = 0 671 pen.twist = 0 672 pen.barrelswitch = False 673 pen.secondarybarrelswitch = False 674 elif state == PenState.PEN_IS_IN_RANGE: 675 pen.tipswitch = False 676 pen.inrange = True 677 pen.invert = False 678 pen.eraser = False 679 pen.barrelswitch = False 680 pen.secondarybarrelswitch = False 681 elif state == PenState.PEN_IS_IN_CONTACT: 682 pen.tipswitch = True 683 pen.inrange = True 684 pen.invert = False 685 pen.eraser = False 686 pen.barrelswitch = False 687 pen.secondarybarrelswitch = False 688 elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: 689 pen.tipswitch = False 690 pen.inrange = True 691 pen.invert = False 692 pen.eraser = False 693 pen.barrelswitch = True 694 pen.secondarybarrelswitch = False 695 elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: 696 pen.tipswitch = True 697 pen.inrange = True 698 pen.invert = False 699 pen.eraser = False 700 pen.barrelswitch = True 701 pen.secondarybarrelswitch = False 702 elif state == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: 703 pen.tipswitch = False 704 pen.inrange = True 705 pen.invert = False 706 pen.eraser = False 707 pen.barrelswitch = False 708 pen.secondarybarrelswitch = True 709 elif state == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: 710 pen.tipswitch = True 711 pen.inrange = True 712 pen.invert = False 713 pen.eraser = False 714 pen.barrelswitch = False 715 pen.secondarybarrelswitch = True 716 elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: 717 pen.tipswitch = False 718 pen.inrange = True 719 pen.invert = True 720 pen.eraser = False 721 pen.barrelswitch = False 722 pen.secondarybarrelswitch = False 723 elif state == PenState.PEN_IS_ERASING: 724 pen.tipswitch = False 725 pen.inrange = True 726 pen.invert = False 727 pen.eraser = True 728 pen.barrelswitch = False 729 pen.secondarybarrelswitch = False 730 731 pen.current_state = state 732 733 def event(self, pen): 734 rs = [] 735 r = self.create_report(application=self.cur_application, data=pen) 736 self.call_input_event(r) 737 rs.append(r) 738 return rs 739 740 def get_report(self, req, rnum, rtype): 741 if rtype != self.UHID_FEATURE_REPORT: 742 return (1, []) 743 744 rdesc = None 745 for v in self.parsed_rdesc.feature_reports.values(): 746 if v.report_ID == rnum: 747 rdesc = v 748 749 if rdesc is None: 750 return (1, []) 751 752 return (1, []) 753 754 def set_report(self, req, rnum, rtype, data): 755 if rtype != self.UHID_FEATURE_REPORT: 756 return 1 757 758 rdesc = None 759 for v in self.parsed_rdesc.feature_reports.values(): 760 if v.report_ID == rnum: 761 rdesc = v 762 763 if rdesc is None: 764 return 1 765 766 return 1 767 768 769class BaseTest: 770 class TestTablet(base.BaseTestCase.TestUhid): 771 def create_device(self): 772 raise Exception("please reimplement me in subclasses") 773 774 def post(self, uhdev, pen): 775 r = uhdev.event(pen) 776 events = uhdev.next_sync_events() 777 self.debug_reports(r, uhdev, events) 778 return events 779 780 def validate_transitions( 781 self, from_state, pen, evdev, events, allow_intermediate_states 782 ): 783 # check that the final state is correct 784 pen.assert_expected_input_events(evdev) 785 786 state = from_state 787 788 # check that the transitions are valid 789 sync_events = [] 790 while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events: 791 # split the first EV_SYN from the list 792 idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT)) 793 sync_events = events[:idx] 794 events = events[idx + 1 :] 795 796 # now check for a valid transition 797 state = state.apply(sync_events, not allow_intermediate_states) 798 799 if events: 800 state = state.apply(sync_events, not allow_intermediate_states) 801 802 def _test_states(self, state_list, scribble, allow_intermediate_states): 803 """Internal method to test against a list of 804 transition between states. 805 state_list is a list of PenState objects 806 scribble is a boolean which tells if we need 807 to wobble a little the X,Y coordinates of the pen 808 between each state transition.""" 809 uhdev = self.uhdev 810 evdev = uhdev.get_evdev() 811 812 cur_state = PenState.PEN_IS_OUT_OF_RANGE 813 814 p = Pen(50, 60) 815 uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE) 816 events = self.post(uhdev, p) 817 self.validate_transitions( 818 cur_state, p, evdev, events, allow_intermediate_states 819 ) 820 821 cur_state = p.current_state 822 823 for state in state_list: 824 if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE: 825 p.x += 1 826 p.y -= 1 827 events = self.post(uhdev, p) 828 self.validate_transitions( 829 cur_state, p, evdev, events, allow_intermediate_states 830 ) 831 assert len(events) >= 3 # X, Y, SYN 832 uhdev.move_to(p, state) 833 if scribble and state != PenState.PEN_IS_OUT_OF_RANGE: 834 p.x += 1 835 p.y -= 1 836 events = self.post(uhdev, p) 837 self.validate_transitions( 838 cur_state, p, evdev, events, allow_intermediate_states 839 ) 840 cur_state = p.current_state 841 842 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 843 @pytest.mark.parametrize( 844 "state_list", 845 [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()], 846 ) 847 def test_valid_pen_states(self, state_list, scribble): 848 """This is the first half of the Windows Pen Implementation state machine: 849 we don't have Invert nor Erase bits, so just move in/out-of-range or proximity. 850 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 851 """ 852 self._test_states(state_list, scribble, allow_intermediate_states=False) 853 854 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 855 @pytest.mark.parametrize( 856 "state_list", 857 [ 858 pytest.param(v, id=k) 859 for k, v in PenState.tolerated_transitions().items() 860 ], 861 ) 862 def test_tolerated_pen_states(self, state_list, scribble): 863 """This is not adhering to the Windows Pen Implementation state machine 864 but we should expect the kernel to behave properly, mostly for historical 865 reasons.""" 866 self._test_states(state_list, scribble, allow_intermediate_states=True) 867 868 @pytest.mark.skip_if_uhdev( 869 lambda uhdev: "Barrel Switch" not in uhdev.fields, 870 "Device not compatible, missing Barrel Switch usage", 871 ) 872 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 873 @pytest.mark.parametrize( 874 "state_list", 875 [ 876 pytest.param(v, id=k) 877 for k, v in PenState.legal_transitions_with_primary_button().items() 878 ], 879 ) 880 def test_valid_primary_button_pen_states(self, state_list, scribble): 881 """Rework the transition state machine by adding the primary button.""" 882 self._test_states(state_list, scribble, allow_intermediate_states=False) 883 884 @pytest.mark.skip_if_uhdev( 885 lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields, 886 "Device not compatible, missing Secondary Barrel Switch usage", 887 ) 888 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 889 @pytest.mark.parametrize( 890 "state_list", 891 [ 892 pytest.param(v, id=k) 893 for k, v in PenState.legal_transitions_with_secondary_button().items() 894 ], 895 ) 896 def test_valid_secondary_button_pen_states(self, state_list, scribble): 897 """Rework the transition state machine by adding the secondary button.""" 898 self._test_states(state_list, scribble, allow_intermediate_states=False) 899 900 @pytest.mark.skip_if_uhdev( 901 lambda uhdev: "Invert" not in uhdev.fields, 902 "Device not compatible, missing Invert usage", 903 ) 904 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 905 @pytest.mark.parametrize( 906 "state_list", 907 [ 908 pytest.param(v, id=k) 909 for k, v in PenState.legal_transitions_with_invert().items() 910 ], 911 ) 912 def test_valid_invert_pen_states(self, state_list, scribble): 913 """This is the second half of the Windows Pen Implementation state machine: 914 we now have Invert and Erase bits, so move in/out or proximity with the intend 915 to erase. 916 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 917 """ 918 self._test_states(state_list, scribble, allow_intermediate_states=False) 919 920 @pytest.mark.skip_if_uhdev( 921 lambda uhdev: "Invert" not in uhdev.fields, 922 "Device not compatible, missing Invert usage", 923 ) 924 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 925 @pytest.mark.parametrize( 926 "state_list", 927 [ 928 pytest.param(v, id=k) 929 for k, v in PenState.tolerated_transitions_with_invert().items() 930 ], 931 ) 932 def test_tolerated_invert_pen_states(self, state_list, scribble): 933 """This is the second half of the Windows Pen Implementation state machine: 934 we now have Invert and Erase bits, so move in/out or proximity with the intend 935 to erase. 936 https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states 937 """ 938 self._test_states(state_list, scribble, allow_intermediate_states=True) 939 940 @pytest.mark.skip_if_uhdev( 941 lambda uhdev: "Invert" not in uhdev.fields, 942 "Device not compatible, missing Invert usage", 943 ) 944 @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 945 @pytest.mark.parametrize( 946 "state_list", 947 [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()], 948 ) 949 def test_tolerated_broken_pen_states(self, state_list, scribble): 950 """Those tests are definitely not part of the Windows specification. 951 However, a half broken device might export those transitions. 952 For example, a pen that has the eraser button might wobble between 953 touching and erasing if the tablet doesn't enforce the Windows 954 state machine.""" 955 self._test_states(state_list, scribble, allow_intermediate_states=True) 956 957 958class GXTP_pen(PenDigitizer): 959 def event(self, pen): 960 if not hasattr(self, "prev_tip_state"): 961 self.prev_tip_state = False 962 963 internal_pen = copy.copy(pen) 964 965 # bug in the controller: when the pen touches the 966 # surface, in-range stays to 1, but when 967 # the pen moves in-range gets reverted to 0 968 if pen.tipswitch and self.prev_tip_state: 969 internal_pen.inrange = False 970 971 self.prev_tip_state = pen.tipswitch 972 973 # another bug in the controller: when the pen is 974 # inverted, invert is set to 1, but as soon as 975 # the pen touches the surface, eraser is correctly 976 # set to 1 but invert is released 977 if pen.eraser: 978 internal_pen.invert = False 979 980 return super().event(internal_pen) 981 982 983class USIPen(PenDigitizer): 984 pass 985 986 987################################################################################ 988# 989# Windows 7 compatible devices 990# 991################################################################################ 992# class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet): 993# def create_device(self): 994# return PenDigitizer('uhid test egalax-capacitive_0eef_7224', 995# 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', 996# input_info=(BusType.USB, 0x0eef, 0x7224), 997# evdev_name_suffix=' Touchscreen') 998# 999# 1000# class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet): 1001# def create_device(self): 1002# return PenDigitizer('uhid test egalax-capacitive_0eef_72fa', 1003# 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', 1004# input_info=(BusType.USB, 0x0eef, 0x72fa), 1005# evdev_name_suffix=' Touchscreen') 1006# 1007# 1008# class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet): 1009# def create_device(self): 1010# return PenDigitizer('uhid test egalax-capacitive_0eef_7336', 1011# 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', 1012# input_info=(BusType.USB, 0x0eef, 0x7336), 1013# evdev_name_suffix=' Touchscreen') 1014# 1015# 1016# class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet): 1017# def create_device(self): 1018# return PenDigitizer('uhid test egalax-capacitive_0eef_7337', 1019# 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', 1020# input_info=(BusType.USB, 0x0eef, 0x7337), 1021# evdev_name_suffix=' Touchscreen') 1022# 1023# 1024# class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet): 1025# def create_device(self): 1026# return PenDigitizer('uhid test egalax-capacitive_0eef_7349', 1027# 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', 1028# input_info=(BusType.USB, 0x0eef, 0x7349), 1029# evdev_name_suffix=' Touchscreen') 1030# 1031# 1032# class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet): 1033# def create_device(self): 1034# return PenDigitizer('uhid test egalax-capacitive_0eef_73f4', 1035# 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', 1036# input_info=(BusType.USB, 0x0eef, 0x73f4), 1037# evdev_name_suffix=' Touchscreen') 1038# 1039# bogus: BTN_TOOL_PEN is not emitted 1040# class TestIrtouch_6615_0070(BaseTest.TestTablet): 1041# def create_device(self): 1042# return PenDigitizer('uhid test irtouch_6615_0070', 1043# 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', 1044# input_info=(BusType.USB, 0x6615, 0x0070)) 1045 1046 1047class TestNexio_1870_0100(BaseTest.TestTablet): 1048 def create_device(self): 1049 return PenDigitizer( 1050 "uhid test nexio_1870_0100", 1051 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", 1052 input_info=(BusType.USB, 0x1870, 0x0100), 1053 ) 1054 1055 1056class TestNexio_1870_010d(BaseTest.TestTablet): 1057 def create_device(self): 1058 return PenDigitizer( 1059 "uhid test nexio_1870_010d", 1060 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", 1061 input_info=(BusType.USB, 0x1870, 0x010D), 1062 ) 1063 1064 1065class TestNexio_1870_0119(BaseTest.TestTablet): 1066 def create_device(self): 1067 return PenDigitizer( 1068 "uhid test nexio_1870_0119", 1069 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", 1070 input_info=(BusType.USB, 0x1870, 0x0119), 1071 ) 1072 1073 1074################################################################################ 1075# 1076# Windows 8 compatible devices 1077# 1078################################################################################ 1079 1080# bogus: application is 'undefined' 1081# class Testatmel_03eb_8409(BaseTest.TestTablet): 1082# def create_device(self): 1083# 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') 1084 1085 1086class Testatmel_03eb_840b(BaseTest.TestTablet): 1087 def create_device(self): 1088 return PenDigitizer( 1089 "uhid test atmel_03eb_840b", 1090 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", 1091 ) 1092 1093 1094class Testn_trig_1b96_0c01(BaseTest.TestTablet): 1095 def create_device(self): 1096 return PenDigitizer( 1097 "uhid test n_trig_1b96_0c01", 1098 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", 1099 ) 1100 1101 1102class Testn_trig_1b96_0c03(BaseTest.TestTablet): 1103 def create_device(self): 1104 return PenDigitizer( 1105 "uhid test n_trig_1b96_0c03", 1106 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", 1107 ) 1108 1109 1110class Testn_trig_1b96_0f00(BaseTest.TestTablet): 1111 def create_device(self): 1112 return PenDigitizer( 1113 "uhid test n_trig_1b96_0f00", 1114 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", 1115 ) 1116 1117 1118class Testn_trig_1b96_0f04(BaseTest.TestTablet): 1119 def create_device(self): 1120 return PenDigitizer( 1121 "uhid test n_trig_1b96_0f04", 1122 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", 1123 ) 1124 1125 1126class Testn_trig_1b96_1000(BaseTest.TestTablet): 1127 def create_device(self): 1128 return PenDigitizer( 1129 "uhid test n_trig_1b96_1000", 1130 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", 1131 ) 1132 1133 1134class TestGXTP_27c6_0113(BaseTest.TestTablet): 1135 def create_device(self): 1136 return GXTP_pen( 1137 "uhid test GXTP_27c6_0113", 1138 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", 1139 ) 1140 1141 1142################################################################################ 1143# 1144# Windows 8 compatible devices with USI Pen 1145# 1146################################################################################ 1147 1148 1149class TestElan_04f3_2A49(BaseTest.TestTablet): 1150 def create_device(self): 1151 return USIPen( 1152 "uhid test Elan_04f3_2A49", 1153 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", 1154 input_info=(BusType.I2C, 0x04F3, 0x2A49), 1155 ) 1156 1157 1158class TestGoodix_27c6_0e00(BaseTest.TestTablet): 1159 def create_device(self): 1160 return USIPen( 1161 "uhid test Elan_04f3_2A49", 1162 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", 1163 input_info=(BusType.I2C, 0x27C6, 0x0E00), 1164 ) 1165