~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/hid/tests/test_tablet.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/testing/selftests/hid/tests/test_tablet.py (Architecture i386) and /tools/testing/selftests/hid/tests/test_tablet.py (Architecture sparc)


  1 #!/bin/env python3                                  1 #!/bin/env python3
  2 # SPDX-License-Identifier: GPL-2.0                  2 # SPDX-License-Identifier: GPL-2.0
  3 # -*- coding: utf-8 -*-                             3 # -*- coding: utf-8 -*-
  4 #                                                   4 #
  5 # Copyright (c) 2021 Benjamin Tissoires <benjam      5 # Copyright (c) 2021 Benjamin Tissoires <benjamin.tissoires@gmail.com>
  6 # Copyright (c) 2021 Red Hat, Inc.                  6 # Copyright (c) 2021 Red Hat, Inc.
  7 #                                                   7 #
  8                                                     8 
  9 from . import base                                  9 from . import base
 10 import copy                                        10 import copy
 11 from enum import Enum                              11 from enum import Enum
 12 from hidtools.util import BusType                  12 from hidtools.util import BusType
 13 import libevdev                                    13 import libevdev
 14 import logging                                     14 import logging
 15 import pytest                                      15 import pytest
 16 from typing import Dict, List, Optional, Tuple     16 from typing import Dict, List, Optional, Tuple
 17                                                    17 
 18 logger = logging.getLogger("hidtools.test.tabl     18 logger = logging.getLogger("hidtools.test.tablet")
 19                                                    19 
 20                                                    20 
 21 class BtnTouch(Enum):                              21 class BtnTouch(Enum):
 22     """Represents whether the BTN_TOUCH event      22     """Represents whether the BTN_TOUCH event is set to True or False"""
 23                                                    23 
 24     DOWN = True                                    24     DOWN = True
 25     UP = False                                     25     UP = False
 26                                                    26 
 27                                                    27 
 28 class ToolType(Enum):                              28 class ToolType(Enum):
 29     PEN = libevdev.EV_KEY.BTN_TOOL_PEN             29     PEN = libevdev.EV_KEY.BTN_TOOL_PEN
 30     RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER       30     RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER
 31                                                    31 
 32                                                    32 
 33 class BtnPressed(Enum):                            33 class BtnPressed(Enum):
 34     """Represents whether a button is pressed      34     """Represents whether a button is pressed on the stylus"""
 35                                                    35 
 36     PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYL     36     PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS
 37     SECONDARY_PRESSED = libevdev.EV_KEY.BTN_ST     37     SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2
 38     THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS     38     THIRD_PRESSED = libevdev.EV_KEY.BTN_STYLUS3
 39                                                    39 
 40                                                    40 
 41 class PenState(Enum):                              41 class PenState(Enum):
 42     """Pen states according to Microsoft refer     42     """Pen states according to Microsoft reference:
 43     https://docs.microsoft.com/en-us/windows-h     43     https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
 44                                                    44 
 45     We extend it with the various buttons when     45     We extend it with the various buttons when we need to check them.
 46     """                                            46     """
 47                                                    47 
 48     PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, F     48     PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False
 49     PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PE     49     PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False
 50     PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP,     50     PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True
 51     PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolTyp     51     PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False
 52     PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.D     52     PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True
 53     PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnT     53     PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False
 54     PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_B     54     PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True
 55     PEN_IS_ERASING = BtnTouch.DOWN, ToolType.R     55     PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False
 56     PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN     56     PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True
 57                                                    57 
 58     def __init__(                                  58     def __init__(
 59         self, touch: BtnTouch, tool: Optional[     59         self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]
 60     ):                                             60     ):
 61         self.touch = touch  # type: ignore         61         self.touch = touch  # type: ignore
 62         self.tool = tool  # type: ignore           62         self.tool = tool  # type: ignore
 63         self.button = button  # type: ignore       63         self.button = button  # type: ignore
 64                                                    64 
 65     @classmethod                                   65     @classmethod
 66     def from_evdev(cls, evdev, test_button) ->     66     def from_evdev(cls, evdev, test_button) -> "PenState":
 67         touch = BtnTouch(evdev.value[libevdev.     67         touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
 68         tool = None                                68         tool = None
 69         button = False                             69         button = False
 70         if (                                       70         if (
 71             evdev.value[libevdev.EV_KEY.BTN_TO     71             evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
 72             and not evdev.value[libevdev.EV_KE     72             and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
 73         ):                                         73         ):
 74             tool = ToolType(libevdev.EV_KEY.BT     74             tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)
 75         elif (                                     75         elif (
 76             evdev.value[libevdev.EV_KEY.BTN_TO     76             evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
 77             and not evdev.value[libevdev.EV_KE     77             and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
 78         ):                                         78         ):
 79             tool = ToolType(libevdev.EV_KEY.BT     79             tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)
 80         elif (                                     80         elif (
 81             evdev.value[libevdev.EV_KEY.BTN_TO     81             evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
 82             or evdev.value[libevdev.EV_KEY.BTN     82             or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
 83         ):                                         83         ):
 84             raise ValueError("2 tools are not      84             raise ValueError("2 tools are not allowed")
 85                                                    85 
 86         # we take only the provided button int     86         # we take only the provided button into account
 87         if test_button is not None:                87         if test_button is not None:
 88             button = bool(evdev.value[test_but     88             button = bool(evdev.value[test_button.value])
 89                                                    89 
 90         # the kernel tends to insert an EV_SYN     90         # the kernel tends to insert an EV_SYN once removing the tool, so
 91         # the button will be released after        91         # the button will be released after
 92         if tool is None:                           92         if tool is None:
 93             button = False                         93             button = False
 94                                                    94 
 95         return cls((touch, tool, button))  # t     95         return cls((touch, tool, button))  # type: ignore
 96                                                    96 
 97     def apply(                                     97     def apply(
 98         self, events: List[libevdev.InputEvent     98         self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed
 99     ) -> "PenState":                               99     ) -> "PenState":
100         if libevdev.EV_SYN.SYN_REPORT in event    100         if libevdev.EV_SYN.SYN_REPORT in events:
101             raise ValueError("EV_SYN is in the    101             raise ValueError("EV_SYN is in the event sequence")
102         touch = self.touch                        102         touch = self.touch
103         touch_found = False                       103         touch_found = False
104         tool = self.tool                          104         tool = self.tool
105         tool_found = False                        105         tool_found = False
106         button = self.button                      106         button = self.button
107         button_found = False                      107         button_found = False
108                                                   108 
109         for ev in events:                         109         for ev in events:
110             if ev == libevdev.InputEvent(libev    110             if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):
111                 if touch_found:                   111                 if touch_found:
112                     raise ValueError(f"duplica    112                     raise ValueError(f"duplicated BTN_TOUCH in {events}")
113                 touch_found = True                113                 touch_found = True
114                 touch = BtnTouch(ev.value)        114                 touch = BtnTouch(ev.value)
115             elif ev in (                          115             elif ev in (
116                 libevdev.InputEvent(libevdev.E    116                 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),
117                 libevdev.InputEvent(libevdev.E    117                 libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),
118             ):                                    118             ):
119                 if tool_found:                    119                 if tool_found:
120                     raise ValueError(f"duplica    120                     raise ValueError(f"duplicated BTN_TOOL_* in {events}")
121                 tool_found = True                 121                 tool_found = True
122                 tool = ToolType(ev.code) if ev    122                 tool = ToolType(ev.code) if ev.value else None
123             elif test_button is not None and e    123             elif test_button is not None and ev in (test_button.value,):
124                 if button_found:                  124                 if button_found:
125                     raise ValueError(f"duplica    125                     raise ValueError(f"duplicated BTN_STYLUS* in {events}")
126                 button_found = True               126                 button_found = True
127                 button = bool(ev.value)           127                 button = bool(ev.value)
128                                                   128 
129         # the kernel tends to insert an EV_SYN    129         # the kernel tends to insert an EV_SYN once removing the tool, so
130         # the button will be released after       130         # the button will be released after
131         if tool is None:                          131         if tool is None:
132             button = False                        132             button = False
133                                                   133 
134         new_state = PenState((touch, tool, but    134         new_state = PenState((touch, tool, button))  # type: ignore
135         if strict:                                135         if strict:
136             assert (                              136             assert (
137                 new_state in self.valid_transi    137                 new_state in self.valid_transitions()
138             ), f"moving from {self} to {new_st    138             ), f"moving from {self} to {new_state} is forbidden"
139         else:                                     139         else:
140             assert (                              140             assert (
141                 new_state in self.historically    141                 new_state in self.historically_tolerated_transitions()
142             ), f"moving from {self} to {new_st    142             ), f"moving from {self} to {new_state} is forbidden"
143                                                   143 
144         return new_state                          144         return new_state
145                                                   145 
146     def valid_transitions(self) -> Tuple["PenS    146     def valid_transitions(self) -> Tuple["PenState", ...]:
147         """Following the state machine in the     147         """Following the state machine in the URL above.
148                                                   148 
149         Note that those transitions are from t    149         Note that those transitions are from the evdev point of view, not HID"""
150         if self == PenState.PEN_IS_OUT_OF_RANG    150         if self == PenState.PEN_IS_OUT_OF_RANGE:
151             return (                              151             return (
152                 PenState.PEN_IS_OUT_OF_RANGE,     152                 PenState.PEN_IS_OUT_OF_RANGE,
153                 PenState.PEN_IS_IN_RANGE,         153                 PenState.PEN_IS_IN_RANGE,
154                 PenState.PEN_IS_IN_RANGE_WITH_    154                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
155                 PenState.PEN_IS_IN_RANGE_WITH_    155                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
156                 PenState.PEN_IS_IN_CONTACT,       156                 PenState.PEN_IS_IN_CONTACT,
157                 PenState.PEN_IS_IN_CONTACT_WIT    157                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
158                 PenState.PEN_IS_ERASING,          158                 PenState.PEN_IS_ERASING,
159             )                                     159             )
160                                                   160 
161         if self == PenState.PEN_IS_IN_RANGE:      161         if self == PenState.PEN_IS_IN_RANGE:
162             return (                              162             return (
163                 PenState.PEN_IS_IN_RANGE,         163                 PenState.PEN_IS_IN_RANGE,
164                 PenState.PEN_IS_IN_RANGE_WITH_    164                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
165                 PenState.PEN_IS_OUT_OF_RANGE,     165                 PenState.PEN_IS_OUT_OF_RANGE,
166                 PenState.PEN_IS_IN_CONTACT,       166                 PenState.PEN_IS_IN_CONTACT,
167             )                                     167             )
168                                                   168 
169         if self == PenState.PEN_IS_IN_CONTACT:    169         if self == PenState.PEN_IS_IN_CONTACT:
170             return (                              170             return (
171                 PenState.PEN_IS_IN_CONTACT,       171                 PenState.PEN_IS_IN_CONTACT,
172                 PenState.PEN_IS_IN_CONTACT_WIT    172                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
173                 PenState.PEN_IS_IN_RANGE,         173                 PenState.PEN_IS_IN_RANGE,
174             )                                     174             )
175                                                   175 
176         if self == PenState.PEN_IS_IN_RANGE_WI    176         if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
177             return (                              177             return (
178                 PenState.PEN_IS_IN_RANGE_WITH_    178                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
179                 PenState.PEN_IS_OUT_OF_RANGE,     179                 PenState.PEN_IS_OUT_OF_RANGE,
180                 PenState.PEN_IS_ERASING,          180                 PenState.PEN_IS_ERASING,
181             )                                     181             )
182                                                   182 
183         if self == PenState.PEN_IS_ERASING:       183         if self == PenState.PEN_IS_ERASING:
184             return (                              184             return (
185                 PenState.PEN_IS_ERASING,          185                 PenState.PEN_IS_ERASING,
186                 PenState.PEN_IS_IN_RANGE_WITH_    186                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
187             )                                     187             )
188                                                   188 
189         if self == PenState.PEN_IS_IN_RANGE_WI    189         if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
190             return (                              190             return (
191                 PenState.PEN_IS_IN_RANGE_WITH_    191                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
192                 PenState.PEN_IS_IN_RANGE,         192                 PenState.PEN_IS_IN_RANGE,
193                 PenState.PEN_IS_OUT_OF_RANGE,     193                 PenState.PEN_IS_OUT_OF_RANGE,
194                 PenState.PEN_IS_IN_CONTACT_WIT    194                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
195             )                                     195             )
196                                                   196 
197         if self == PenState.PEN_IS_IN_CONTACT_    197         if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
198             return (                              198             return (
199                 PenState.PEN_IS_IN_CONTACT_WIT    199                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
200                 PenState.PEN_IS_IN_CONTACT,       200                 PenState.PEN_IS_IN_CONTACT,
201                 PenState.PEN_IS_IN_RANGE_WITH_    201                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
202             )                                     202             )
203                                                   203 
204         return tuple()                            204         return tuple()
205                                                   205 
206     def historically_tolerated_transitions(sel    206     def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:
207         """Following the state machine in the     207         """Following the state machine in the URL above, with a couple of addition
208         for skipping the in-range state, due t    208         for skipping the in-range state, due to historical reasons.
209                                                   209 
210         Note that those transitions are from t    210         Note that those transitions are from the evdev point of view, not HID"""
211         if self == PenState.PEN_IS_OUT_OF_RANG    211         if self == PenState.PEN_IS_OUT_OF_RANGE:
212             return (                              212             return (
213                 PenState.PEN_IS_OUT_OF_RANGE,     213                 PenState.PEN_IS_OUT_OF_RANGE,
214                 PenState.PEN_IS_IN_RANGE,         214                 PenState.PEN_IS_IN_RANGE,
215                 PenState.PEN_IS_IN_RANGE_WITH_    215                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
216                 PenState.PEN_IS_IN_RANGE_WITH_    216                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
217                 PenState.PEN_IS_IN_CONTACT,       217                 PenState.PEN_IS_IN_CONTACT,
218                 PenState.PEN_IS_IN_CONTACT_WIT    218                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
219                 PenState.PEN_IS_ERASING,          219                 PenState.PEN_IS_ERASING,
220             )                                     220             )
221                                                   221 
222         if self == PenState.PEN_IS_IN_RANGE:      222         if self == PenState.PEN_IS_IN_RANGE:
223             return (                              223             return (
224                 PenState.PEN_IS_IN_RANGE,         224                 PenState.PEN_IS_IN_RANGE,
225                 PenState.PEN_IS_IN_RANGE_WITH_    225                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
226                 PenState.PEN_IS_OUT_OF_RANGE,     226                 PenState.PEN_IS_OUT_OF_RANGE,
227                 PenState.PEN_IS_IN_CONTACT,       227                 PenState.PEN_IS_IN_CONTACT,
228             )                                     228             )
229                                                   229 
230         if self == PenState.PEN_IS_IN_CONTACT:    230         if self == PenState.PEN_IS_IN_CONTACT:
231             return (                              231             return (
232                 PenState.PEN_IS_IN_CONTACT,       232                 PenState.PEN_IS_IN_CONTACT,
233                 PenState.PEN_IS_IN_CONTACT_WIT    233                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
234                 PenState.PEN_IS_IN_RANGE,         234                 PenState.PEN_IS_IN_RANGE,
235                 PenState.PEN_IS_OUT_OF_RANGE,     235                 PenState.PEN_IS_OUT_OF_RANGE,
236             )                                     236             )
237                                                   237 
238         if self == PenState.PEN_IS_IN_RANGE_WI    238         if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
239             return (                              239             return (
240                 PenState.PEN_IS_IN_RANGE_WITH_    240                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
241                 PenState.PEN_IS_OUT_OF_RANGE,     241                 PenState.PEN_IS_OUT_OF_RANGE,
242                 PenState.PEN_IS_ERASING,          242                 PenState.PEN_IS_ERASING,
243             )                                     243             )
244                                                   244 
245         if self == PenState.PEN_IS_ERASING:       245         if self == PenState.PEN_IS_ERASING:
246             return (                              246             return (
247                 PenState.PEN_IS_ERASING,          247                 PenState.PEN_IS_ERASING,
248                 PenState.PEN_IS_IN_RANGE_WITH_    248                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
249                 PenState.PEN_IS_OUT_OF_RANGE,     249                 PenState.PEN_IS_OUT_OF_RANGE,
250             )                                     250             )
251                                                   251 
252         if self == PenState.PEN_IS_IN_RANGE_WI    252         if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
253             return (                              253             return (
254                 PenState.PEN_IS_IN_RANGE_WITH_    254                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
255                 PenState.PEN_IS_IN_RANGE,         255                 PenState.PEN_IS_IN_RANGE,
256                 PenState.PEN_IS_OUT_OF_RANGE,     256                 PenState.PEN_IS_OUT_OF_RANGE,
257                 PenState.PEN_IS_IN_CONTACT_WIT    257                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
258             )                                     258             )
259                                                   259 
260         if self == PenState.PEN_IS_IN_CONTACT_    260         if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
261             return (                              261             return (
262                 PenState.PEN_IS_IN_CONTACT_WIT    262                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
263                 PenState.PEN_IS_IN_CONTACT,       263                 PenState.PEN_IS_IN_CONTACT,
264                 PenState.PEN_IS_IN_RANGE_WITH_    264                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
265                 PenState.PEN_IS_OUT_OF_RANGE,     265                 PenState.PEN_IS_OUT_OF_RANGE,
266             )                                     266             )
267                                                   267 
268         return tuple()                            268         return tuple()
269                                                   269 
270     @staticmethod                                 270     @staticmethod
271     def legal_transitions() -> Dict[str, Tuple    271     def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:
272         """This is the first half of the Windo    272         """This is the first half of the Windows Pen Implementation state machine:
273         we don't have Invert nor Erase bits, s    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/windo    274         https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
275         """                                       275         """
276         return {                                  276         return {
277             "in-range": (PenState.PEN_IS_IN_RA    277             "in-range": (PenState.PEN_IS_IN_RANGE,),
278             "in-range -> out-of-range": (         278             "in-range -> out-of-range": (
279                 PenState.PEN_IS_IN_RANGE,         279                 PenState.PEN_IS_IN_RANGE,
280                 PenState.PEN_IS_OUT_OF_RANGE,     280                 PenState.PEN_IS_OUT_OF_RANGE,
281             ),                                    281             ),
282             "in-range -> touch": (PenState.PEN    282             "in-range -> touch": (PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_CONTACT),
283             "in-range -> touch -> release": (     283             "in-range -> touch -> release": (
284                 PenState.PEN_IS_IN_RANGE,         284                 PenState.PEN_IS_IN_RANGE,
285                 PenState.PEN_IS_IN_CONTACT,       285                 PenState.PEN_IS_IN_CONTACT,
286                 PenState.PEN_IS_IN_RANGE,         286                 PenState.PEN_IS_IN_RANGE,
287             ),                                    287             ),
288             "in-range -> touch -> release -> o    288             "in-range -> touch -> release -> out-of-range": (
289                 PenState.PEN_IS_IN_RANGE,         289                 PenState.PEN_IS_IN_RANGE,
290                 PenState.PEN_IS_IN_CONTACT,       290                 PenState.PEN_IS_IN_CONTACT,
291                 PenState.PEN_IS_IN_RANGE,         291                 PenState.PEN_IS_IN_RANGE,
292                 PenState.PEN_IS_OUT_OF_RANGE,     292                 PenState.PEN_IS_OUT_OF_RANGE,
293             ),                                    293             ),
294         }                                         294         }
295                                                   295 
296     @staticmethod                                 296     @staticmethod
297     def legal_transitions_with_invert() -> Dic    297     def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
298         """This is the second half of the Wind    298         """This is the second half of the Windows Pen Implementation state machine:
299         we now have Invert and Erase bits, so     299         we now have Invert and Erase bits, so move in/out or proximity with the intend
300         to erase.                                 300         to erase.
301         https://docs.microsoft.com/en-us/windo    301         https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
302         """                                       302         """
303         return {                                  303         return {
304             "hover-erasing": (PenState.PEN_IS_    304             "hover-erasing": (PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,),
305             "hover-erasing -> out-of-range": (    305             "hover-erasing -> out-of-range": (
306                 PenState.PEN_IS_IN_RANGE_WITH_    306                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
307                 PenState.PEN_IS_OUT_OF_RANGE,     307                 PenState.PEN_IS_OUT_OF_RANGE,
308             ),                                    308             ),
309             "hover-erasing -> erase": (           309             "hover-erasing -> erase": (
310                 PenState.PEN_IS_IN_RANGE_WITH_    310                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
311                 PenState.PEN_IS_ERASING,          311                 PenState.PEN_IS_ERASING,
312             ),                                    312             ),
313             "hover-erasing -> erase -> release    313             "hover-erasing -> erase -> release": (
314                 PenState.PEN_IS_IN_RANGE_WITH_    314                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
315                 PenState.PEN_IS_ERASING,          315                 PenState.PEN_IS_ERASING,
316                 PenState.PEN_IS_IN_RANGE_WITH_    316                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
317             ),                                    317             ),
318             "hover-erasing -> erase -> release    318             "hover-erasing -> erase -> release -> out-of-range": (
319                 PenState.PEN_IS_IN_RANGE_WITH_    319                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
320                 PenState.PEN_IS_ERASING,          320                 PenState.PEN_IS_ERASING,
321                 PenState.PEN_IS_IN_RANGE_WITH_    321                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
322                 PenState.PEN_IS_OUT_OF_RANGE,     322                 PenState.PEN_IS_OUT_OF_RANGE,
323             ),                                    323             ),
324             "hover-erasing -> in-range": (        324             "hover-erasing -> in-range": (
325                 PenState.PEN_IS_IN_RANGE_WITH_    325                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
326                 PenState.PEN_IS_IN_RANGE,         326                 PenState.PEN_IS_IN_RANGE,
327             ),                                    327             ),
328             "in-range -> hover-erasing": (        328             "in-range -> hover-erasing": (
329                 PenState.PEN_IS_IN_RANGE,         329                 PenState.PEN_IS_IN_RANGE,
330                 PenState.PEN_IS_IN_RANGE_WITH_    330                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
331             ),                                    331             ),
332         }                                         332         }
333                                                   333 
334     @staticmethod                                 334     @staticmethod
335     def legal_transitions_with_button() -> Dic    335     def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:
336         """We revisit the Windows Pen Implemen    336         """We revisit the Windows Pen Implementation state machine:
337         we now have a button.                     337         we now have a button.
338         """                                       338         """
339         return {                                  339         return {
340             "hover-button": (PenState.PEN_IS_I    340             "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),
341             "hover-button -> out-of-range": (     341             "hover-button -> out-of-range": (
342                 PenState.PEN_IS_IN_RANGE_WITH_    342                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
343                 PenState.PEN_IS_OUT_OF_RANGE,     343                 PenState.PEN_IS_OUT_OF_RANGE,
344             ),                                    344             ),
345             "in-range -> button-press": (         345             "in-range -> button-press": (
346                 PenState.PEN_IS_IN_RANGE,         346                 PenState.PEN_IS_IN_RANGE,
347                 PenState.PEN_IS_IN_RANGE_WITH_    347                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
348             ),                                    348             ),
349             "in-range -> button-press -> butto    349             "in-range -> button-press -> button-release": (
350                 PenState.PEN_IS_IN_RANGE,         350                 PenState.PEN_IS_IN_RANGE,
351                 PenState.PEN_IS_IN_RANGE_WITH_    351                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
352                 PenState.PEN_IS_IN_RANGE,         352                 PenState.PEN_IS_IN_RANGE,
353             ),                                    353             ),
354             "in-range -> touch -> button-press    354             "in-range -> touch -> button-press -> button-release": (
355                 PenState.PEN_IS_IN_RANGE,         355                 PenState.PEN_IS_IN_RANGE,
356                 PenState.PEN_IS_IN_CONTACT,       356                 PenState.PEN_IS_IN_CONTACT,
357                 PenState.PEN_IS_IN_CONTACT_WIT    357                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
358                 PenState.PEN_IS_IN_CONTACT,       358                 PenState.PEN_IS_IN_CONTACT,
359             ),                                    359             ),
360             "in-range -> touch -> button-press    360             "in-range -> touch -> button-press -> release -> button-release": (
361                 PenState.PEN_IS_IN_RANGE,         361                 PenState.PEN_IS_IN_RANGE,
362                 PenState.PEN_IS_IN_CONTACT,       362                 PenState.PEN_IS_IN_CONTACT,
363                 PenState.PEN_IS_IN_CONTACT_WIT    363                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
364                 PenState.PEN_IS_IN_RANGE_WITH_    364                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
365                 PenState.PEN_IS_IN_RANGE,         365                 PenState.PEN_IS_IN_RANGE,
366             ),                                    366             ),
367             "in-range -> button-press -> touch    367             "in-range -> button-press -> touch -> release -> button-release": (
368                 PenState.PEN_IS_IN_RANGE,         368                 PenState.PEN_IS_IN_RANGE,
369                 PenState.PEN_IS_IN_RANGE_WITH_    369                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
370                 PenState.PEN_IS_IN_CONTACT_WIT    370                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
371                 PenState.PEN_IS_IN_RANGE_WITH_    371                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
372                 PenState.PEN_IS_IN_RANGE,         372                 PenState.PEN_IS_IN_RANGE,
373             ),                                    373             ),
374             "in-range -> button-press -> touch    374             "in-range -> button-press -> touch -> button-release -> release": (
375                 PenState.PEN_IS_IN_RANGE,         375                 PenState.PEN_IS_IN_RANGE,
376                 PenState.PEN_IS_IN_RANGE_WITH_    376                 PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
377                 PenState.PEN_IS_IN_CONTACT_WIT    377                 PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
378                 PenState.PEN_IS_IN_CONTACT,       378                 PenState.PEN_IS_IN_CONTACT,
379                 PenState.PEN_IS_IN_RANGE,         379                 PenState.PEN_IS_IN_RANGE,
380             ),                                    380             ),
381         }                                         381         }
382                                                   382 
383     @staticmethod                                 383     @staticmethod
384     def tolerated_transitions() -> Dict[str, T    384     def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:
385         """This is not adhering to the Windows    385         """This is not adhering to the Windows Pen Implementation state machine
386         but we should expect the kernel to beh    386         but we should expect the kernel to behave properly, mostly for historical
387         reasons."""                               387         reasons."""
388         return {                                  388         return {
389             "direct-in-contact": (PenState.PEN    389             "direct-in-contact": (PenState.PEN_IS_IN_CONTACT,),
390             "direct-in-contact -> out-of-range    390             "direct-in-contact -> out-of-range": (
391                 PenState.PEN_IS_IN_CONTACT,       391                 PenState.PEN_IS_IN_CONTACT,
392                 PenState.PEN_IS_OUT_OF_RANGE,     392                 PenState.PEN_IS_OUT_OF_RANGE,
393             ),                                    393             ),
394         }                                         394         }
395                                                   395 
396     @staticmethod                                 396     @staticmethod
397     def tolerated_transitions_with_invert() ->    397     def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
398         """This is the second half of the Wind    398         """This is the second half of the Windows Pen Implementation state machine:
399         we now have Invert and Erase bits, so     399         we now have Invert and Erase bits, so move in/out or proximity with the intend
400         to erase.                                 400         to erase.
401         https://docs.microsoft.com/en-us/windo    401         https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
402         """                                       402         """
403         return {                                  403         return {
404             "direct-erase": (PenState.PEN_IS_E    404             "direct-erase": (PenState.PEN_IS_ERASING,),
405             "direct-erase -> out-of-range": (     405             "direct-erase -> out-of-range": (
406                 PenState.PEN_IS_ERASING,          406                 PenState.PEN_IS_ERASING,
407                 PenState.PEN_IS_OUT_OF_RANGE,     407                 PenState.PEN_IS_OUT_OF_RANGE,
408             ),                                    408             ),
409         }                                         409         }
410                                                   410 
411     @staticmethod                                 411     @staticmethod
412     def broken_transitions() -> Dict[str, Tupl    412     def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:
413         """Those tests are definitely not part    413         """Those tests are definitely not part of the Windows specification.
414         However, a half broken device might ex    414         However, a half broken device might export those transitions.
415         For example, a pen that has the eraser    415         For example, a pen that has the eraser button might wobble between
416         touching and erasing if the tablet doe    416         touching and erasing if the tablet doesn't enforce the Windows
417         state machine."""                         417         state machine."""
418         return {                                  418         return {
419             "in-range -> touch -> erase -> hov    419             "in-range -> touch -> erase -> hover-erase": (
420                 PenState.PEN_IS_IN_RANGE,         420                 PenState.PEN_IS_IN_RANGE,
421                 PenState.PEN_IS_IN_CONTACT,       421                 PenState.PEN_IS_IN_CONTACT,
422                 PenState.PEN_IS_ERASING,          422                 PenState.PEN_IS_ERASING,
423                 PenState.PEN_IS_IN_RANGE_WITH_    423                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
424             ),                                    424             ),
425             "in-range -> erase -> hover-erase"    425             "in-range -> erase -> hover-erase": (
426                 PenState.PEN_IS_IN_RANGE,         426                 PenState.PEN_IS_IN_RANGE,
427                 PenState.PEN_IS_ERASING,          427                 PenState.PEN_IS_ERASING,
428                 PenState.PEN_IS_IN_RANGE_WITH_    428                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
429             ),                                    429             ),
430             "hover-erase -> erase -> touch ->     430             "hover-erase -> erase -> touch -> in-range": (
431                 PenState.PEN_IS_IN_RANGE_WITH_    431                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
432                 PenState.PEN_IS_ERASING,          432                 PenState.PEN_IS_ERASING,
433                 PenState.PEN_IS_IN_CONTACT,       433                 PenState.PEN_IS_IN_CONTACT,
434                 PenState.PEN_IS_IN_RANGE,         434                 PenState.PEN_IS_IN_RANGE,
435             ),                                    435             ),
436             "hover-erase -> touch -> in-range"    436             "hover-erase -> touch -> in-range": (
437                 PenState.PEN_IS_IN_RANGE_WITH_    437                 PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
438                 PenState.PEN_IS_IN_CONTACT,       438                 PenState.PEN_IS_IN_CONTACT,
439                 PenState.PEN_IS_IN_RANGE,         439                 PenState.PEN_IS_IN_RANGE,
440             ),                                    440             ),
441             "touch -> erase -> touch -> erase"    441             "touch -> erase -> touch -> erase": (
442                 PenState.PEN_IS_IN_CONTACT,       442                 PenState.PEN_IS_IN_CONTACT,
443                 PenState.PEN_IS_ERASING,          443                 PenState.PEN_IS_ERASING,
444                 PenState.PEN_IS_IN_CONTACT,       444                 PenState.PEN_IS_IN_CONTACT,
445                 PenState.PEN_IS_ERASING,          445                 PenState.PEN_IS_ERASING,
446             ),                                    446             ),
447         }                                         447         }
448                                                   448 
449                                                   449 
450 class Pen(object):                                450 class Pen(object):
451     def __init__(self, x, y):                     451     def __init__(self, x, y):
452         self.x = x                                452         self.x = x
453         self.y = y                                453         self.y = y
454         self.tipswitch = False                    454         self.tipswitch = False
455         self.tippressure = 15                     455         self.tippressure = 15
456         self.azimuth = 0                          456         self.azimuth = 0
457         self.inrange = False                      457         self.inrange = False
458         self.width = 10                           458         self.width = 10
459         self.height = 10                          459         self.height = 10
460         self.barrelswitch = False                 460         self.barrelswitch = False
461         self.secondarybarrelswitch = False        461         self.secondarybarrelswitch = False
462         self.invert = False                       462         self.invert = False
463         self.eraser = False                       463         self.eraser = False
464         self.xtilt = 1                            464         self.xtilt = 1
465         self.ytilt = 1                            465         self.ytilt = 1
466         self.twist = 1                            466         self.twist = 1
467         self._old_values = None                   467         self._old_values = None
468         self.current_state = None                 468         self.current_state = None
469                                                   469 
470     def restore(self):                            470     def restore(self):
471         if self._old_values is not None:          471         if self._old_values is not None:
472             for i in [                            472             for i in [
473                 "x",                              473                 "x",
474                 "y",                              474                 "y",
475                 "tippressure",                    475                 "tippressure",
476                 "azimuth",                        476                 "azimuth",
477                 "width",                          477                 "width",
478                 "height",                         478                 "height",
479                 "twist",                          479                 "twist",
480                 "xtilt",                          480                 "xtilt",
481                 "ytilt",                          481                 "ytilt",
482             ]:                                    482             ]:
483                 setattr(self, i, getattr(self.    483                 setattr(self, i, getattr(self._old_values, i))
484                                                   484 
485     def backup(self):                             485     def backup(self):
486         self._old_values = copy.copy(self)        486         self._old_values = copy.copy(self)
487                                                   487 
488     def __assert_axis(self, evdev, axis, value    488     def __assert_axis(self, evdev, axis, value):
489         if (                                      489         if (
490             axis == libevdev.EV_KEY.BTN_TOOL_R    490             axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
491             and evdev.value[libevdev.EV_KEY.BT    491             and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
492         ):                                        492         ):
493             return                                493             return
494                                                   494 
495         assert (                                  495         assert (
496             evdev.value[axis] == value            496             evdev.value[axis] == value
497         ), f"assert evdev.value[{axis}] ({evde    497         ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
498                                                   498 
499     def assert_expected_input_events(self, evd    499     def assert_expected_input_events(self, evdev, button):
500         assert evdev.value[libevdev.EV_ABS.ABS    500         assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
501         assert evdev.value[libevdev.EV_ABS.ABS    501         assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
502                                                   502 
503         # assert no other buttons than the tes    503         # assert no other buttons than the tested ones are set
504         buttons = [                               504         buttons = [
505             BtnPressed.PRIMARY_PRESSED,           505             BtnPressed.PRIMARY_PRESSED,
506             BtnPressed.SECONDARY_PRESSED,         506             BtnPressed.SECONDARY_PRESSED,
507             BtnPressed.THIRD_PRESSED,             507             BtnPressed.THIRD_PRESSED,
508         ]                                         508         ]
509         if button is not None:                    509         if button is not None:
510             buttons.remove(button)                510             buttons.remove(button)
511         for b in buttons:                         511         for b in buttons:
512             assert evdev.value[b.value] is Non    512             assert evdev.value[b.value] is None or evdev.value[b.value] == False
513                                                   513 
514         assert self.current_state == PenState.    514         assert self.current_state == PenState.from_evdev(evdev, button)
515                                                   515 
516                                                   516 
517 class PenDigitizer(base.UHIDTestDevice):          517 class PenDigitizer(base.UHIDTestDevice):
518     def __init__(                                 518     def __init__(
519         self,                                     519         self,
520         name,                                     520         name,
521         rdesc_str=None,                           521         rdesc_str=None,
522         rdesc=None,                               522         rdesc=None,
523         application="Pen",                        523         application="Pen",
524         physical="Stylus",                        524         physical="Stylus",
525         input_info=(BusType.USB, 1, 2),           525         input_info=(BusType.USB, 1, 2),
526         evdev_name_suffix=None,                   526         evdev_name_suffix=None,
527     ):                                            527     ):
528         super().__init__(name, application, rd    528         super().__init__(name, application, rdesc_str, rdesc, input_info)
529         self.physical = physical                  529         self.physical = physical
530         self.cur_application = application        530         self.cur_application = application
531         if evdev_name_suffix is not None:         531         if evdev_name_suffix is not None:
532             self.name += evdev_name_suffix        532             self.name += evdev_name_suffix
533                                                   533 
534         self.fields = []                          534         self.fields = []
535         for r in self.parsed_rdesc.input_repor    535         for r in self.parsed_rdesc.input_reports.values():
536             if r.application_name == self.appl    536             if r.application_name == self.application:
537                 physicals = [f.physical_name f    537                 physicals = [f.physical_name for f in r]
538                 if self.physical not in physic    538                 if self.physical not in physicals and None not in physicals:
539                     continue                      539                     continue
540                 self.fields = [f.usage_name fo    540                 self.fields = [f.usage_name for f in r]
541                                                   541 
542     def move_to(self, pen, state, button):        542     def move_to(self, pen, state, button):
543         # fill in the previous values             543         # fill in the previous values
544         if pen.current_state == PenState.PEN_I    544         if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
545             pen.restore()                         545             pen.restore()
546                                                   546 
547         print(f"\n  *** pen is moving to {stat    547         print(f"\n  *** pen is moving to {state} ***")
548                                                   548 
549         if state == PenState.PEN_IS_OUT_OF_RAN    549         if state == PenState.PEN_IS_OUT_OF_RANGE:
550             pen.backup()                          550             pen.backup()
551             pen.x = 0                             551             pen.x = 0
552             pen.y = 0                             552             pen.y = 0
553             pen.tipswitch = False                 553             pen.tipswitch = False
554             pen.tippressure = 0                   554             pen.tippressure = 0
555             pen.azimuth = 0                       555             pen.azimuth = 0
556             pen.inrange = False                   556             pen.inrange = False
557             pen.width = 0                         557             pen.width = 0
558             pen.height = 0                        558             pen.height = 0
559             pen.invert = False                    559             pen.invert = False
560             pen.eraser = False                    560             pen.eraser = False
561             pen.xtilt = 0                         561             pen.xtilt = 0
562             pen.ytilt = 0                         562             pen.ytilt = 0
563             pen.twist = 0                         563             pen.twist = 0
564             pen.barrelswitch = False              564             pen.barrelswitch = False
565             pen.secondarybarrelswitch = False     565             pen.secondarybarrelswitch = False
566         elif state == PenState.PEN_IS_IN_RANGE    566         elif state == PenState.PEN_IS_IN_RANGE:
567             pen.tipswitch = False                 567             pen.tipswitch = False
568             pen.inrange = True                    568             pen.inrange = True
569             pen.invert = False                    569             pen.invert = False
570             pen.eraser = False                    570             pen.eraser = False
571             pen.barrelswitch = False              571             pen.barrelswitch = False
572             pen.secondarybarrelswitch = False     572             pen.secondarybarrelswitch = False
573         elif state == PenState.PEN_IS_IN_CONTA    573         elif state == PenState.PEN_IS_IN_CONTACT:
574             pen.tipswitch = True                  574             pen.tipswitch = True
575             pen.inrange = True                    575             pen.inrange = True
576             pen.invert = False                    576             pen.invert = False
577             pen.eraser = False                    577             pen.eraser = False
578             pen.barrelswitch = False              578             pen.barrelswitch = False
579             pen.secondarybarrelswitch = False     579             pen.secondarybarrelswitch = False
580         elif state == PenState.PEN_IS_IN_RANGE    580         elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
581             pen.tipswitch = False                 581             pen.tipswitch = False
582             pen.inrange = True                    582             pen.inrange = True
583             pen.invert = False                    583             pen.invert = False
584             pen.eraser = False                    584             pen.eraser = False
585             assert button is not None             585             assert button is not None
586             pen.barrelswitch = button == BtnPr    586             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
587             pen.secondarybarrelswitch = button    587             pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
588         elif state == PenState.PEN_IS_IN_CONTA    588         elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
589             pen.tipswitch = True                  589             pen.tipswitch = True
590             pen.inrange = True                    590             pen.inrange = True
591             pen.invert = False                    591             pen.invert = False
592             pen.eraser = False                    592             pen.eraser = False
593             assert button is not None             593             assert button is not None
594             pen.barrelswitch = button == BtnPr    594             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
595             pen.secondarybarrelswitch = button    595             pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
596         elif state == PenState.PEN_IS_IN_RANGE    596         elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
597             pen.tipswitch = False                 597             pen.tipswitch = False
598             pen.inrange = True                    598             pen.inrange = True
599             pen.invert = True                     599             pen.invert = True
600             pen.eraser = False                    600             pen.eraser = False
601             pen.barrelswitch = False              601             pen.barrelswitch = False
602             pen.secondarybarrelswitch = False     602             pen.secondarybarrelswitch = False
603         elif state == PenState.PEN_IS_ERASING:    603         elif state == PenState.PEN_IS_ERASING:
604             pen.tipswitch = False                 604             pen.tipswitch = False
605             pen.inrange = True                    605             pen.inrange = True
606             pen.invert = False                    606             pen.invert = False
607             pen.eraser = True                     607             pen.eraser = True
608             pen.barrelswitch = False              608             pen.barrelswitch = False
609             pen.secondarybarrelswitch = False     609             pen.secondarybarrelswitch = False
610                                                   610 
611         pen.current_state = state                 611         pen.current_state = state
612                                                   612 
613     def event(self, pen, button):                 613     def event(self, pen, button):
614         rs = []                                   614         rs = []
615         r = self.create_report(application=sel    615         r = self.create_report(application=self.cur_application, data=pen)
616         self.call_input_event(r)                  616         self.call_input_event(r)
617         rs.append(r)                              617         rs.append(r)
618         return rs                                 618         return rs
619                                                   619 
620     def get_report(self, req, rnum, rtype):       620     def get_report(self, req, rnum, rtype):
621         if rtype != self.UHID_FEATURE_REPORT:     621         if rtype != self.UHID_FEATURE_REPORT:
622             return (1, [])                        622             return (1, [])
623                                                   623 
624         rdesc = None                              624         rdesc = None
625         for v in self.parsed_rdesc.feature_rep    625         for v in self.parsed_rdesc.feature_reports.values():
626             if v.report_ID == rnum:               626             if v.report_ID == rnum:
627                 rdesc = v                         627                 rdesc = v
628                                                   628 
629         if rdesc is None:                         629         if rdesc is None:
630             return (1, [])                        630             return (1, [])
631                                                   631 
632         return (1, [])                            632         return (1, [])
633                                                   633 
634     def set_report(self, req, rnum, rtype, dat    634     def set_report(self, req, rnum, rtype, data):
635         if rtype != self.UHID_FEATURE_REPORT:     635         if rtype != self.UHID_FEATURE_REPORT:
636             return 1                              636             return 1
637                                                   637 
638         rdesc = None                              638         rdesc = None
639         for v in self.parsed_rdesc.feature_rep    639         for v in self.parsed_rdesc.feature_reports.values():
640             if v.report_ID == rnum:               640             if v.report_ID == rnum:
641                 rdesc = v                         641                 rdesc = v
642                                                   642 
643         if rdesc is None:                         643         if rdesc is None:
644             return 1                              644             return 1
645                                                   645 
646         return 1                                  646         return 1
647                                                   647 
648                                                   648 
649 class BaseTest:                                   649 class BaseTest:
650     class TestTablet(base.BaseTestCase.TestUhi    650     class TestTablet(base.BaseTestCase.TestUhid):
651         def create_device(self):                  651         def create_device(self):
652             raise Exception("please reimplemen    652             raise Exception("please reimplement me in subclasses")
653                                                   653 
654         def post(self, uhdev, pen, test_button    654         def post(self, uhdev, pen, test_button):
655             r = uhdev.event(pen, test_button)     655             r = uhdev.event(pen, test_button)
656             events = uhdev.next_sync_events()     656             events = uhdev.next_sync_events()
657             self.debug_reports(r, uhdev, event    657             self.debug_reports(r, uhdev, events)
658             return events                         658             return events
659                                                   659 
660         def validate_transitions(                 660         def validate_transitions(
661             self, from_state, pen, evdev, even    661             self, from_state, pen, evdev, events, allow_intermediate_states, button
662         ):                                        662         ):
663             # check that the final state is co    663             # check that the final state is correct
664             pen.assert_expected_input_events(e    664             pen.assert_expected_input_events(evdev, button)
665                                                   665 
666             state = from_state                    666             state = from_state
667                                                   667 
668             # check that the transitions are v    668             # check that the transitions are valid
669             sync_events = []                      669             sync_events = []
670             while libevdev.InputEvent(libevdev    670             while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:
671                 # split the first EV_SYN from     671                 # split the first EV_SYN from the list
672                 idx = events.index(libevdev.In    672                 idx = events.index(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT))
673                 sync_events = events[:idx]        673                 sync_events = events[:idx]
674                 events = events[idx + 1 :]        674                 events = events[idx + 1 :]
675                                                   675 
676                 # now check for a valid transi    676                 # now check for a valid transition
677                 state = state.apply(sync_event    677                 state = state.apply(sync_events, not allow_intermediate_states, button)
678                                                   678 
679             if events:                            679             if events:
680                 state = state.apply(sync_event    680                 state = state.apply(sync_events, not allow_intermediate_states, button)
681                                                   681 
682         def _test_states(                         682         def _test_states(
683             self, state_list, scribble, allow_    683             self, state_list, scribble, allow_intermediate_states, button=None
684         ):                                        684         ):
685             """Internal method to test against    685             """Internal method to test against a list of
686             transition between states.            686             transition between states.
687             state_list is a list of PenState o    687             state_list is a list of PenState objects
688             scribble is a boolean which tells     688             scribble is a boolean which tells if we need
689             to wobble a little the X,Y coordin    689             to wobble a little the X,Y coordinates of the pen
690             between each state transition."""     690             between each state transition."""
691             uhdev = self.uhdev                    691             uhdev = self.uhdev
692             evdev = uhdev.get_evdev()             692             evdev = uhdev.get_evdev()
693                                                   693 
694             cur_state = PenState.PEN_IS_OUT_OF    694             cur_state = PenState.PEN_IS_OUT_OF_RANGE
695                                                   695 
696             p = Pen(50, 60)                       696             p = Pen(50, 60)
697             uhdev.move_to(p, PenState.PEN_IS_O    697             uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)
698             events = self.post(uhdev, p, butto    698             events = self.post(uhdev, p, button)
699             self.validate_transitions(            699             self.validate_transitions(
700                 cur_state, p, evdev, events, a    700                 cur_state, p, evdev, events, allow_intermediate_states, button
701             )                                     701             )
702                                                   702 
703             cur_state = p.current_state           703             cur_state = p.current_state
704                                                   704 
705             for state in state_list:              705             for state in state_list:
706                 if scribble and cur_state != P    706                 if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:
707                     p.x += 1                      707                     p.x += 1
708                     p.y -= 1                      708                     p.y -= 1
709                     events = self.post(uhdev,     709                     events = self.post(uhdev, p, button)
710                     self.validate_transitions(    710                     self.validate_transitions(
711                         cur_state, p, evdev, e    711                         cur_state, p, evdev, events, allow_intermediate_states, button
712                     )                             712                     )
713                     assert len(events) >= 3  #    713                     assert len(events) >= 3  # X, Y, SYN
714                 uhdev.move_to(p, state, button    714                 uhdev.move_to(p, state, button)
715                 if scribble and state != PenSt    715                 if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
716                     p.x += 1                      716                     p.x += 1
717                     p.y -= 1                      717                     p.y -= 1
718                 events = self.post(uhdev, p, b    718                 events = self.post(uhdev, p, button)
719                 self.validate_transitions(        719                 self.validate_transitions(
720                     cur_state, p, evdev, event    720                     cur_state, p, evdev, events, allow_intermediate_states, button
721                 )                                 721                 )
722                 cur_state = p.current_state       722                 cur_state = p.current_state
723                                                   723 
724         @pytest.mark.parametrize("scribble", [    724         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
725         @pytest.mark.parametrize(                 725         @pytest.mark.parametrize(
726             "state_list",                         726             "state_list",
727             [pytest.param(v, id=k) for k, v in    727             [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
728         )                                         728         )
729         def test_valid_pen_states(self, state_    729         def test_valid_pen_states(self, state_list, scribble):
730             """This is the first half of the W    730             """This is the first half of the Windows Pen Implementation state machine:
731             we don't have Invert nor Erase bit    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/w    732             https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
733             """                                   733             """
734             self._test_states(state_list, scri    734             self._test_states(state_list, scribble, allow_intermediate_states=False)
735                                                   735 
736         @pytest.mark.parametrize("scribble", [    736         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
737         @pytest.mark.parametrize(                 737         @pytest.mark.parametrize(
738             "state_list",                         738             "state_list",
739             [                                     739             [
740                 pytest.param(v, id=k)             740                 pytest.param(v, id=k)
741                 for k, v in PenState.tolerated    741                 for k, v in PenState.tolerated_transitions().items()
742             ],                                    742             ],
743         )                                         743         )
744         def test_tolerated_pen_states(self, st    744         def test_tolerated_pen_states(self, state_list, scribble):
745             """This is not adhering to the Win    745             """This is not adhering to the Windows Pen Implementation state machine
746             but we should expect the kernel to    746             but we should expect the kernel to behave properly, mostly for historical
747             reasons."""                           747             reasons."""
748             self._test_states(state_list, scri    748             self._test_states(state_list, scribble, allow_intermediate_states=True)
749                                                   749 
750         @pytest.mark.skip_if_uhdev(               750         @pytest.mark.skip_if_uhdev(
751             lambda uhdev: "Barrel Switch" not     751             lambda uhdev: "Barrel Switch" not in uhdev.fields,
752             "Device not compatible, missing Ba    752             "Device not compatible, missing Barrel Switch usage",
753         )                                         753         )
754         @pytest.mark.parametrize("scribble", [    754         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
755         @pytest.mark.parametrize(                 755         @pytest.mark.parametrize(
756             "state_list",                         756             "state_list",
757             [                                     757             [
758                 pytest.param(v, id=k)             758                 pytest.param(v, id=k)
759                 for k, v in PenState.legal_tra    759                 for k, v in PenState.legal_transitions_with_button().items()
760             ],                                    760             ],
761         )                                         761         )
762         def test_valid_primary_button_pen_stat    762         def test_valid_primary_button_pen_states(self, state_list, scribble):
763             """Rework the transition state mac    763             """Rework the transition state machine by adding the primary button."""
764             self._test_states(                    764             self._test_states(
765                 state_list,                       765                 state_list,
766                 scribble,                         766                 scribble,
767                 allow_intermediate_states=Fals    767                 allow_intermediate_states=False,
768                 button=BtnPressed.PRIMARY_PRES    768                 button=BtnPressed.PRIMARY_PRESSED,
769             )                                     769             )
770                                                   770 
771         @pytest.mark.skip_if_uhdev(               771         @pytest.mark.skip_if_uhdev(
772             lambda uhdev: "Secondary Barrel Sw    772             lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,
773             "Device not compatible, missing Se    773             "Device not compatible, missing Secondary Barrel Switch usage",
774         )                                         774         )
775         @pytest.mark.parametrize("scribble", [    775         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
776         @pytest.mark.parametrize(                 776         @pytest.mark.parametrize(
777             "state_list",                         777             "state_list",
778             [                                     778             [
779                 pytest.param(v, id=k)             779                 pytest.param(v, id=k)
780                 for k, v in PenState.legal_tra    780                 for k, v in PenState.legal_transitions_with_button().items()
781             ],                                    781             ],
782         )                                         782         )
783         def test_valid_secondary_button_pen_st    783         def test_valid_secondary_button_pen_states(self, state_list, scribble):
784             """Rework the transition state mac    784             """Rework the transition state machine by adding the secondary button."""
785             self._test_states(                    785             self._test_states(
786                 state_list,                       786                 state_list,
787                 scribble,                         787                 scribble,
788                 allow_intermediate_states=Fals    788                 allow_intermediate_states=False,
789                 button=BtnPressed.SECONDARY_PR    789                 button=BtnPressed.SECONDARY_PRESSED,
790             )                                     790             )
791                                                   791 
792         @pytest.mark.skip_if_uhdev(               792         @pytest.mark.skip_if_uhdev(
793             lambda uhdev: "Third Barrel Switch    793             lambda uhdev: "Third Barrel Switch" not in uhdev.fields,
794             "Device not compatible, missing Th    794             "Device not compatible, missing Third Barrel Switch usage",
795         )                                         795         )
796         @pytest.mark.parametrize("scribble", [    796         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
797         @pytest.mark.parametrize(                 797         @pytest.mark.parametrize(
798             "state_list",                         798             "state_list",
799             [                                     799             [
800                 pytest.param(v, id=k)             800                 pytest.param(v, id=k)
801                 for k, v in PenState.legal_tra    801                 for k, v in PenState.legal_transitions_with_button().items()
802             ],                                    802             ],
803         )                                         803         )
804         def test_valid_third_button_pen_states    804         def test_valid_third_button_pen_states(self, state_list, scribble):
805             """Rework the transition state mac    805             """Rework the transition state machine by adding the secondary button."""
806             self._test_states(                    806             self._test_states(
807                 state_list,                       807                 state_list,
808                 scribble,                         808                 scribble,
809                 allow_intermediate_states=Fals    809                 allow_intermediate_states=False,
810                 button=BtnPressed.THIRD_PRESSE    810                 button=BtnPressed.THIRD_PRESSED,
811             )                                     811             )
812                                                   812 
813         @pytest.mark.skip_if_uhdev(               813         @pytest.mark.skip_if_uhdev(
814             lambda uhdev: "Invert" not in uhde    814             lambda uhdev: "Invert" not in uhdev.fields,
815             "Device not compatible, missing In    815             "Device not compatible, missing Invert usage",
816         )                                         816         )
817         @pytest.mark.parametrize("scribble", [    817         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
818         @pytest.mark.parametrize(                 818         @pytest.mark.parametrize(
819             "state_list",                         819             "state_list",
820             [                                     820             [
821                 pytest.param(v, id=k)             821                 pytest.param(v, id=k)
822                 for k, v in PenState.legal_tra    822                 for k, v in PenState.legal_transitions_with_invert().items()
823             ],                                    823             ],
824         )                                         824         )
825         def test_valid_invert_pen_states(self,    825         def test_valid_invert_pen_states(self, state_list, scribble):
826             """This is the second half of the     826             """This is the second half of the Windows Pen Implementation state machine:
827             we now have Invert and Erase bits,    827             we now have Invert and Erase bits, so move in/out or proximity with the intend
828             to erase.                             828             to erase.
829             https://docs.microsoft.com/en-us/w    829             https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
830             """                                   830             """
831             self._test_states(state_list, scri    831             self._test_states(state_list, scribble, allow_intermediate_states=False)
832                                                   832 
833         @pytest.mark.skip_if_uhdev(               833         @pytest.mark.skip_if_uhdev(
834             lambda uhdev: "Invert" not in uhde    834             lambda uhdev: "Invert" not in uhdev.fields,
835             "Device not compatible, missing In    835             "Device not compatible, missing Invert usage",
836         )                                         836         )
837         @pytest.mark.parametrize("scribble", [    837         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
838         @pytest.mark.parametrize(                 838         @pytest.mark.parametrize(
839             "state_list",                         839             "state_list",
840             [                                     840             [
841                 pytest.param(v, id=k)             841                 pytest.param(v, id=k)
842                 for k, v in PenState.tolerated    842                 for k, v in PenState.tolerated_transitions_with_invert().items()
843             ],                                    843             ],
844         )                                         844         )
845         def test_tolerated_invert_pen_states(s    845         def test_tolerated_invert_pen_states(self, state_list, scribble):
846             """This is the second half of the     846             """This is the second half of the Windows Pen Implementation state machine:
847             we now have Invert and Erase bits,    847             we now have Invert and Erase bits, so move in/out or proximity with the intend
848             to erase.                             848             to erase.
849             https://docs.microsoft.com/en-us/w    849             https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
850             """                                   850             """
851             self._test_states(state_list, scri    851             self._test_states(state_list, scribble, allow_intermediate_states=True)
852                                                   852 
853         @pytest.mark.skip_if_uhdev(               853         @pytest.mark.skip_if_uhdev(
854             lambda uhdev: "Invert" not in uhde    854             lambda uhdev: "Invert" not in uhdev.fields,
855             "Device not compatible, missing In    855             "Device not compatible, missing Invert usage",
856         )                                         856         )
857         @pytest.mark.parametrize("scribble", [    857         @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
858         @pytest.mark.parametrize(                 858         @pytest.mark.parametrize(
859             "state_list",                         859             "state_list",
860             [pytest.param(v, id=k) for k, v in    860             [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],
861         )                                         861         )
862         def test_tolerated_broken_pen_states(s    862         def test_tolerated_broken_pen_states(self, state_list, scribble):
863             """Those tests are definitely not     863             """Those tests are definitely not part of the Windows specification.
864             However, a half broken device migh    864             However, a half broken device might export those transitions.
865             For example, a pen that has the er    865             For example, a pen that has the eraser button might wobble between
866             touching and erasing if the tablet    866             touching and erasing if the tablet doesn't enforce the Windows
867             state machine."""                     867             state machine."""
868             self._test_states(state_list, scri    868             self._test_states(state_list, scribble, allow_intermediate_states=True)
869                                                   869 
870                                                   870 
871 class GXTP_pen(PenDigitizer):                     871 class GXTP_pen(PenDigitizer):
872     def event(self, pen, test_button):            872     def event(self, pen, test_button):
873         if not hasattr(self, "prev_tip_state")    873         if not hasattr(self, "prev_tip_state"):
874             self.prev_tip_state = False           874             self.prev_tip_state = False
875                                                   875 
876         internal_pen = copy.copy(pen)             876         internal_pen = copy.copy(pen)
877                                                   877 
878         # bug in the controller: when the pen     878         # bug in the controller: when the pen touches the
879         # surface, in-range stays to 1, but wh    879         # surface, in-range stays to 1, but when
880         # the pen moves in-range gets reverted    880         # the pen moves in-range gets reverted to 0
881         if pen.tipswitch and self.prev_tip_sta    881         if pen.tipswitch and self.prev_tip_state:
882             internal_pen.inrange = False          882             internal_pen.inrange = False
883                                                   883 
884         self.prev_tip_state = pen.tipswitch       884         self.prev_tip_state = pen.tipswitch
885                                                   885 
886         # another bug in the controller: when     886         # another bug in the controller: when the pen is
887         # inverted, invert is set to 1, but as    887         # inverted, invert is set to 1, but as soon as
888         # the pen touches the surface, eraser     888         # the pen touches the surface, eraser is correctly
889         # set to 1 but invert is released         889         # set to 1 but invert is released
890         if pen.eraser:                            890         if pen.eraser:
891             internal_pen.invert = False           891             internal_pen.invert = False
892                                                   892 
893         return super().event(internal_pen, tes    893         return super().event(internal_pen, test_button)
894                                                   894 
895                                                   895 
896 class USIPen(PenDigitizer):                       896 class USIPen(PenDigitizer):
897     pass                                          897     pass
898                                                   898 
899                                                   899 
900 class XPPen_ArtistPro16Gen2_28bd_095b(PenDigit    900 class XPPen_ArtistPro16Gen2_28bd_095b(PenDigitizer):
901     """                                           901     """
902     Pen with two buttons and a rubber end, but    902     Pen with two buttons and a rubber end, but which reports
903     the second button as an eraser                903     the second button as an eraser
904     """                                           904     """
905                                                   905 
906     def __init__(                                 906     def __init__(
907         self,                                     907         self,
908         name,                                     908         name,
909         rdesc_str=None,                           909         rdesc_str=None,
910         rdesc=None,                               910         rdesc=None,
911         application="Pen",                        911         application="Pen",
912         physical="Stylus",                        912         physical="Stylus",
913         input_info=(BusType.USB, 0x28BD, 0x095    913         input_info=(BusType.USB, 0x28BD, 0x095B),
914         evdev_name_suffix=None,                   914         evdev_name_suffix=None,
915     ):                                            915     ):
916         super().__init__(                         916         super().__init__(
917             name, rdesc_str, rdesc, applicatio    917             name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
918         )                                         918         )
919         self.fields.append("Secondary Barrel S    919         self.fields.append("Secondary Barrel Switch")
920                                                   920 
921     def move_to(self, pen, state, button):        921     def move_to(self, pen, state, button):
922         # fill in the previous values             922         # fill in the previous values
923         if pen.current_state == PenState.PEN_I    923         if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
924             pen.restore()                         924             pen.restore()
925                                                   925 
926         print(f"\n  *** pen is moving to {stat    926         print(f"\n  *** pen is moving to {state} ***")
927                                                   927 
928         if state == PenState.PEN_IS_OUT_OF_RAN    928         if state == PenState.PEN_IS_OUT_OF_RANGE:
929             pen.backup()                          929             pen.backup()
930             pen.x = 0                             930             pen.x = 0
931             pen.y = 0                             931             pen.y = 0
932             pen.tipswitch = False                 932             pen.tipswitch = False
933             pen.tippressure = 0                   933             pen.tippressure = 0
934             pen.azimuth = 0                       934             pen.azimuth = 0
935             pen.inrange = False                   935             pen.inrange = False
936             pen.width = 0                         936             pen.width = 0
937             pen.height = 0                        937             pen.height = 0
938             pen.invert = False                    938             pen.invert = False
939             pen.eraser = False                    939             pen.eraser = False
940             pen.xtilt = 0                         940             pen.xtilt = 0
941             pen.ytilt = 0                         941             pen.ytilt = 0
942             pen.twist = 0                         942             pen.twist = 0
943             pen.barrelswitch = False              943             pen.barrelswitch = False
944         elif state == PenState.PEN_IS_IN_RANGE    944         elif state == PenState.PEN_IS_IN_RANGE:
945             pen.tipswitch = False                 945             pen.tipswitch = False
946             pen.inrange = True                    946             pen.inrange = True
947             pen.invert = False                    947             pen.invert = False
948             pen.eraser = False                    948             pen.eraser = False
949             pen.barrelswitch = False              949             pen.barrelswitch = False
950         elif state == PenState.PEN_IS_IN_CONTA    950         elif state == PenState.PEN_IS_IN_CONTACT:
951             pen.tipswitch = True                  951             pen.tipswitch = True
952             pen.inrange = True                    952             pen.inrange = True
953             pen.invert = False                    953             pen.invert = False
954             pen.eraser = False                    954             pen.eraser = False
955             pen.barrelswitch = False              955             pen.barrelswitch = False
956         elif state == PenState.PEN_IS_IN_RANGE    956         elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
957             pen.tipswitch = False                 957             pen.tipswitch = False
958             pen.inrange = True                    958             pen.inrange = True
959             pen.invert = False                    959             pen.invert = False
960             assert button is not None             960             assert button is not None
961             pen.barrelswitch = button == BtnPr    961             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
962             pen.eraser = button == BtnPressed.    962             pen.eraser = button == BtnPressed.SECONDARY_PRESSED
963         elif state == PenState.PEN_IS_IN_CONTA    963         elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
964             pen.tipswitch = True                  964             pen.tipswitch = True
965             pen.inrange = True                    965             pen.inrange = True
966             pen.invert = False                    966             pen.invert = False
967             assert button is not None             967             assert button is not None
968             pen.barrelswitch = button == BtnPr    968             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
969             pen.eraser = button == BtnPressed.    969             pen.eraser = button == BtnPressed.SECONDARY_PRESSED
970         elif state == PenState.PEN_IS_IN_RANGE    970         elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
971             pen.tipswitch = False                 971             pen.tipswitch = False
972             pen.inrange = True                    972             pen.inrange = True
973             pen.invert = True                     973             pen.invert = True
974             pen.eraser = False                    974             pen.eraser = False
975             pen.barrelswitch = False              975             pen.barrelswitch = False
976         elif state == PenState.PEN_IS_ERASING:    976         elif state == PenState.PEN_IS_ERASING:
977             pen.tipswitch = True                  977             pen.tipswitch = True
978             pen.inrange = True                    978             pen.inrange = True
979             pen.invert = True                     979             pen.invert = True
980             pen.eraser = False                    980             pen.eraser = False
981             pen.barrelswitch = False              981             pen.barrelswitch = False
982                                                   982 
983         pen.current_state = state                 983         pen.current_state = state
984                                                   984 
985     def event(self, pen, test_button):            985     def event(self, pen, test_button):
986         import math                               986         import math
987                                                   987 
988         pen_copy = copy.copy(pen)                 988         pen_copy = copy.copy(pen)
989         width = 13.567                            989         width = 13.567
990         height = 8.480                            990         height = 8.480
991         tip_height = 0.055677699                  991         tip_height = 0.055677699
992         hx = tip_height * (32767 / width)         992         hx = tip_height * (32767 / width)
993         hy = tip_height * (32767 / height)        993         hy = tip_height * (32767 / height)
994         if pen_copy.xtilt != 0:                   994         if pen_copy.xtilt != 0:
995             pen_copy.x += round(hx * math.sin(    995             pen_copy.x += round(hx * math.sin(math.radians(pen_copy.xtilt)))
996         if pen_copy.ytilt != 0:                   996         if pen_copy.ytilt != 0:
997             pen_copy.y += round(hy * math.sin(    997             pen_copy.y += round(hy * math.sin(math.radians(pen_copy.ytilt)))
998                                                   998 
999         return super().event(pen_copy, test_bu    999         return super().event(pen_copy, test_button)
1000                                                  1000 
1001                                                  1001 
1002 class XPPen_Artist24_28bd_093a(PenDigitizer):    1002 class XPPen_Artist24_28bd_093a(PenDigitizer):
1003     """                                          1003     """
1004     Pen that reports secondary barrel switch     1004     Pen that reports secondary barrel switch through eraser
1005     """                                          1005     """
1006                                                  1006 
1007     def __init__(                                1007     def __init__(
1008         self,                                    1008         self,
1009         name,                                    1009         name,
1010         rdesc_str=None,                          1010         rdesc_str=None,
1011         rdesc=None,                              1011         rdesc=None,
1012         application="Pen",                       1012         application="Pen",
1013         physical="Stylus",                       1013         physical="Stylus",
1014         input_info=(BusType.USB, 0x28BD, 0x09    1014         input_info=(BusType.USB, 0x28BD, 0x093A),
1015         evdev_name_suffix=None,                  1015         evdev_name_suffix=None,
1016     ):                                           1016     ):
1017         super().__init__(                        1017         super().__init__(
1018             name, rdesc_str, rdesc, applicati    1018             name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1019         )                                        1019         )
1020         self.fields.append("Secondary Barrel     1020         self.fields.append("Secondary Barrel Switch")
1021         self.previous_state = PenState.PEN_IS    1021         self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1022                                                  1022 
1023     def move_to(self, pen, state, button, deb    1023     def move_to(self, pen, state, button, debug=True):
1024         # fill in the previous values            1024         # fill in the previous values
1025         if pen.current_state == PenState.PEN_    1025         if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1026             pen.restore()                        1026             pen.restore()
1027                                                  1027 
1028         if debug:                                1028         if debug:
1029             print(f"\n  *** pen is moving to     1029             print(f"\n  *** pen is moving to {state} ***")
1030                                                  1030 
1031         if state == PenState.PEN_IS_OUT_OF_RA    1031         if state == PenState.PEN_IS_OUT_OF_RANGE:
1032             pen.backup()                         1032             pen.backup()
1033             pen.tipswitch = False                1033             pen.tipswitch = False
1034             pen.tippressure = 0                  1034             pen.tippressure = 0
1035             pen.azimuth = 0                      1035             pen.azimuth = 0
1036             pen.inrange = False                  1036             pen.inrange = False
1037             pen.width = 0                        1037             pen.width = 0
1038             pen.height = 0                       1038             pen.height = 0
1039             pen.invert = False                   1039             pen.invert = False
1040             pen.eraser = False                   1040             pen.eraser = False
1041             pen.xtilt = 0                        1041             pen.xtilt = 0
1042             pen.ytilt = 0                        1042             pen.ytilt = 0
1043             pen.twist = 0                        1043             pen.twist = 0
1044             pen.barrelswitch = False             1044             pen.barrelswitch = False
1045         elif state == PenState.PEN_IS_IN_RANG    1045         elif state == PenState.PEN_IS_IN_RANGE:
1046             pen.tipswitch = False                1046             pen.tipswitch = False
1047             pen.inrange = True                   1047             pen.inrange = True
1048             pen.invert = False                   1048             pen.invert = False
1049             pen.eraser = False                   1049             pen.eraser = False
1050             pen.barrelswitch = False             1050             pen.barrelswitch = False
1051         elif state == PenState.PEN_IS_IN_CONT    1051         elif state == PenState.PEN_IS_IN_CONTACT:
1052             pen.tipswitch = True                 1052             pen.tipswitch = True
1053             pen.inrange = True                   1053             pen.inrange = True
1054             pen.invert = False                   1054             pen.invert = False
1055             pen.eraser = False                   1055             pen.eraser = False
1056             pen.barrelswitch = False             1056             pen.barrelswitch = False
1057         elif state == PenState.PEN_IS_IN_RANG    1057         elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1058             pen.tipswitch = False                1058             pen.tipswitch = False
1059             pen.inrange = True                   1059             pen.inrange = True
1060             pen.invert = False                   1060             pen.invert = False
1061             assert button is not None            1061             assert button is not None
1062             pen.barrelswitch = button == BtnP    1062             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1063             pen.eraser = button == BtnPressed    1063             pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1064         elif state == PenState.PEN_IS_IN_CONT    1064         elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1065             pen.tipswitch = True                 1065             pen.tipswitch = True
1066             pen.inrange = True                   1066             pen.inrange = True
1067             pen.invert = False                   1067             pen.invert = False
1068             assert button is not None            1068             assert button is not None
1069             pen.barrelswitch = button == BtnP    1069             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1070             pen.eraser = button == BtnPressed    1070             pen.eraser = button == BtnPressed.SECONDARY_PRESSED
1071                                                  1071 
1072         pen.current_state = state                1072         pen.current_state = state
1073                                                  1073 
1074     def send_intermediate_state(self, pen, st    1074     def send_intermediate_state(self, pen, state, button):
1075         intermediate_pen = copy.copy(pen)        1075         intermediate_pen = copy.copy(pen)
1076         self.move_to(intermediate_pen, state,    1076         self.move_to(intermediate_pen, state, button, debug=False)
1077         return super().event(intermediate_pen    1077         return super().event(intermediate_pen, button)
1078                                                  1078 
1079     def event(self, pen, button):                1079     def event(self, pen, button):
1080         rs = []                                  1080         rs = []
1081                                                  1081 
1082         # the pen reliably sends in-range eve    1082         # the pen reliably sends in-range events in a normal case (non emulation of eraser mode)
1083         if self.previous_state == PenState.PE    1083         if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1084             if pen.current_state == PenState.    1084             if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1085                 rs.extend(                       1085                 rs.extend(
1086                     self.send_intermediate_st    1086                     self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1087                 )                                1087                 )
1088                                                  1088 
1089         if button == BtnPressed.SECONDARY_PRE    1089         if button == BtnPressed.SECONDARY_PRESSED:
1090             if self.previous_state == PenStat    1090             if self.previous_state == PenState.PEN_IS_IN_RANGE:
1091                 if pen.current_state == PenSt    1091                 if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1092                     rs.extend(                   1092                     rs.extend(
1093                         self.send_intermediat    1093                         self.send_intermediate_state(
1094                             pen, PenState.PEN    1094                             pen, PenState.PEN_IS_OUT_OF_RANGE, button
1095                         )                        1095                         )
1096                     )                            1096                     )
1097                                                  1097 
1098             if self.previous_state == PenStat    1098             if self.previous_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1099                 if pen.current_state == PenSt    1099                 if pen.current_state == PenState.PEN_IS_IN_RANGE:
1100                     rs.extend(                   1100                     rs.extend(
1101                         self.send_intermediat    1101                         self.send_intermediate_state(
1102                             pen, PenState.PEN    1102                             pen, PenState.PEN_IS_OUT_OF_RANGE, button
1103                         )                        1103                         )
1104                     )                            1104                     )
1105                                                  1105 
1106             if self.previous_state == PenStat    1106             if self.previous_state == PenState.PEN_IS_IN_CONTACT:
1107                 if pen.current_state == PenSt    1107                 if pen.current_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1108                     rs.extend(                   1108                     rs.extend(
1109                         self.send_intermediat    1109                         self.send_intermediate_state(
1110                             pen, PenState.PEN    1110                             pen, PenState.PEN_IS_OUT_OF_RANGE, button
1111                         )                        1111                         )
1112                     )                            1112                     )
1113                     rs.extend(                   1113                     rs.extend(
1114                         self.send_intermediat    1114                         self.send_intermediate_state(
1115                             pen, PenState.PEN    1115                             pen, PenState.PEN_IS_IN_RANGE_WITH_BUTTON, button
1116                         )                        1116                         )
1117                     )                            1117                     )
1118                                                  1118 
1119             if self.previous_state == PenStat    1119             if self.previous_state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1120                 if pen.current_state == PenSt    1120                 if pen.current_state == PenState.PEN_IS_IN_CONTACT:
1121                     rs.extend(                   1121                     rs.extend(
1122                         self.send_intermediat    1122                         self.send_intermediate_state(
1123                             pen, PenState.PEN    1123                             pen, PenState.PEN_IS_OUT_OF_RANGE, button
1124                         )                        1124                         )
1125                     )                            1125                     )
1126                     rs.extend(                   1126                     rs.extend(
1127                         self.send_intermediat    1127                         self.send_intermediate_state(
1128                             pen, PenState.PEN    1128                             pen, PenState.PEN_IS_IN_RANGE, button
1129                         )                        1129                         )
1130                     )                            1130                     )
1131                                                  1131 
1132         rs.extend(super().event(pen, button))    1132         rs.extend(super().event(pen, button))
1133         self.previous_state = pen.current_sta    1133         self.previous_state = pen.current_state
1134         return rs                                1134         return rs
1135                                                  1135 
1136                                                  1136 
1137 class Huion_Kamvas_Pro_19_256c_006b(PenDigiti    1137 class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):
1138     """                                          1138     """
1139     Pen that reports secondary barrel switch     1139     Pen that reports secondary barrel switch through secondary TipSwtich
1140     and 3rd button through Invert                1140     and 3rd button through Invert
1141     """                                          1141     """
1142                                                  1142 
1143     def __init__(                                1143     def __init__(
1144         self,                                    1144         self,
1145         name,                                    1145         name,
1146         rdesc_str=None,                          1146         rdesc_str=None,
1147         rdesc=None,                              1147         rdesc=None,
1148         application="Stylus",                    1148         application="Stylus",
1149         physical=None,                           1149         physical=None,
1150         input_info=(BusType.USB, 0x256C, 0x00    1150         input_info=(BusType.USB, 0x256C, 0x006B),
1151         evdev_name_suffix=None,                  1151         evdev_name_suffix=None,
1152     ):                                           1152     ):
1153         super().__init__(                        1153         super().__init__(
1154             name, rdesc_str, rdesc, applicati    1154             name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix
1155         )                                        1155         )
1156         self.fields.append("Secondary Barrel     1156         self.fields.append("Secondary Barrel Switch")
1157         self.fields.append("Third Barrel Swit    1157         self.fields.append("Third Barrel Switch")
1158         self.previous_state = PenState.PEN_IS    1158         self.previous_state = PenState.PEN_IS_OUT_OF_RANGE
1159                                                  1159 
1160     def move_to(self, pen, state, button, deb    1160     def move_to(self, pen, state, button, debug=True):
1161         # fill in the previous values            1161         # fill in the previous values
1162         if pen.current_state == PenState.PEN_    1162         if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
1163             pen.restore()                        1163             pen.restore()
1164                                                  1164 
1165         if debug:                                1165         if debug:
1166             print(f"\n  *** pen is moving to     1166             print(f"\n  *** pen is moving to {state} ***")
1167                                                  1167 
1168         if state == PenState.PEN_IS_OUT_OF_RA    1168         if state == PenState.PEN_IS_OUT_OF_RANGE:
1169             pen.backup()                         1169             pen.backup()
1170             pen.tipswitch = False                1170             pen.tipswitch = False
1171             pen.tippressure = 0                  1171             pen.tippressure = 0
1172             pen.azimuth = 0                      1172             pen.azimuth = 0
1173             pen.inrange = False                  1173             pen.inrange = False
1174             pen.width = 0                        1174             pen.width = 0
1175             pen.height = 0                       1175             pen.height = 0
1176             pen.invert = False                   1176             pen.invert = False
1177             pen.eraser = False                   1177             pen.eraser = False
1178             pen.xtilt = 0                        1178             pen.xtilt = 0
1179             pen.ytilt = 0                        1179             pen.ytilt = 0
1180             pen.twist = 0                        1180             pen.twist = 0
1181             pen.barrelswitch = False             1181             pen.barrelswitch = False
1182             pen.secondarytipswitch = False       1182             pen.secondarytipswitch = False
1183         elif state == PenState.PEN_IS_IN_RANG    1183         elif state == PenState.PEN_IS_IN_RANGE:
1184             pen.tipswitch = False                1184             pen.tipswitch = False
1185             pen.inrange = True                   1185             pen.inrange = True
1186             pen.invert = False                   1186             pen.invert = False
1187             pen.eraser = False                   1187             pen.eraser = False
1188             pen.barrelswitch = False             1188             pen.barrelswitch = False
1189             pen.secondarytipswitch = False       1189             pen.secondarytipswitch = False
1190         elif state == PenState.PEN_IS_IN_CONT    1190         elif state == PenState.PEN_IS_IN_CONTACT:
1191             pen.tipswitch = True                 1191             pen.tipswitch = True
1192             pen.inrange = True                   1192             pen.inrange = True
1193             pen.invert = False                   1193             pen.invert = False
1194             pen.eraser = False                   1194             pen.eraser = False
1195             pen.barrelswitch = False             1195             pen.barrelswitch = False
1196             pen.secondarytipswitch = False       1196             pen.secondarytipswitch = False
1197         elif state == PenState.PEN_IS_IN_RANG    1197         elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1198             pen.tipswitch = False                1198             pen.tipswitch = False
1199             pen.inrange = True                   1199             pen.inrange = True
1200             pen.eraser = False                   1200             pen.eraser = False
1201             assert button is not None            1201             assert button is not None
1202             pen.barrelswitch = button == BtnP    1202             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1203             pen.secondarytipswitch = button =    1203             pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1204             pen.invert = button == BtnPressed    1204             pen.invert = button == BtnPressed.THIRD_PRESSED
1205         elif state == PenState.PEN_IS_IN_CONT    1205         elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
1206             pen.tipswitch = True                 1206             pen.tipswitch = True
1207             pen.inrange = True                   1207             pen.inrange = True
1208             pen.eraser = False                   1208             pen.eraser = False
1209             assert button is not None            1209             assert button is not None
1210             pen.barrelswitch = button == BtnP    1210             pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
1211             pen.secondarytipswitch = button =    1211             pen.secondarytipswitch = button == BtnPressed.SECONDARY_PRESSED
1212             pen.invert = button == BtnPressed    1212             pen.invert = button == BtnPressed.THIRD_PRESSED
1213         elif state == PenState.PEN_IS_IN_RANG    1213         elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
1214             pen.tipswitch = False                1214             pen.tipswitch = False
1215             pen.inrange = True                   1215             pen.inrange = True
1216             pen.invert = True                    1216             pen.invert = True
1217             pen.eraser = False                   1217             pen.eraser = False
1218             pen.barrelswitch = False             1218             pen.barrelswitch = False
1219             pen.secondarytipswitch = False       1219             pen.secondarytipswitch = False
1220         elif state == PenState.PEN_IS_ERASING    1220         elif state == PenState.PEN_IS_ERASING:
1221             pen.tipswitch = False                1221             pen.tipswitch = False
1222             pen.inrange = True                   1222             pen.inrange = True
1223             pen.invert = False                   1223             pen.invert = False
1224             pen.eraser = True                    1224             pen.eraser = True
1225             pen.barrelswitch = False             1225             pen.barrelswitch = False
1226             pen.secondarytipswitch = False       1226             pen.secondarytipswitch = False
1227                                                  1227 
1228         pen.current_state = state                1228         pen.current_state = state
1229                                                  1229 
1230     def call_input_event(self, report):          1230     def call_input_event(self, report):
1231         if report[0] == 0x0a:                    1231         if report[0] == 0x0a:
1232             # ensures the original second Era    1232             # ensures the original second Eraser usage is null
1233             report[1] &= 0xdf                    1233             report[1] &= 0xdf
1234                                                  1234 
1235             # ensures the original last bit i    1235             # ensures the original last bit is equal to bit 6 (In Range)
1236             if report[1] & 0x40:                 1236             if report[1] & 0x40:
1237                 report[1] |= 0x80                1237                 report[1] |= 0x80
1238                                                  1238 
1239         super().call_input_event(report)         1239         super().call_input_event(report)
1240                                                  1240 
1241     def send_intermediate_state(self, pen, st    1241     def send_intermediate_state(self, pen, state, test_button):
1242         intermediate_pen = copy.copy(pen)        1242         intermediate_pen = copy.copy(pen)
1243         self.move_to(intermediate_pen, state,    1243         self.move_to(intermediate_pen, state, test_button, debug=False)
1244         return super().event(intermediate_pen    1244         return super().event(intermediate_pen, test_button)
1245                                                  1245 
1246     def event(self, pen, button):                1246     def event(self, pen, button):
1247         rs = []                                  1247         rs = []
1248                                                  1248 
1249         # it's not possible to go between era    1249         # it's not possible to go between eraser mode or not without
1250         # going out-of-prox: the eraser mode     1250         # going out-of-prox: the eraser mode is activated by presenting
1251         # the tail of the pen                    1251         # the tail of the pen
1252         if self.previous_state in (              1252         if self.previous_state in (
1253             PenState.PEN_IS_IN_RANGE,            1253             PenState.PEN_IS_IN_RANGE,
1254             PenState.PEN_IS_IN_RANGE_WITH_BUT    1254             PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1255             PenState.PEN_IS_IN_CONTACT,          1255             PenState.PEN_IS_IN_CONTACT,
1256             PenState.PEN_IS_IN_CONTACT_WITH_B    1256             PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1257         ) and pen.current_state in (             1257         ) and pen.current_state in (
1258             PenState.PEN_IS_IN_RANGE_WITH_ERA    1258             PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1259             PenState.PEN_IS_IN_RANGE_WITH_ERA    1259             PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1260             PenState.PEN_IS_ERASING,             1260             PenState.PEN_IS_ERASING,
1261             PenState.PEN_IS_ERASING_WITH_BUTT    1261             PenState.PEN_IS_ERASING_WITH_BUTTON,
1262         ):                                       1262         ):
1263             rs.extend(                           1263             rs.extend(
1264                 self.send_intermediate_state(    1264                 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1265             )                                    1265             )
1266                                                  1266 
1267         # same than above except from eraser     1267         # same than above except from eraser to normal
1268         if self.previous_state in (              1268         if self.previous_state in (
1269             PenState.PEN_IS_IN_RANGE_WITH_ERA    1269             PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
1270             PenState.PEN_IS_IN_RANGE_WITH_ERA    1270             PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON,
1271             PenState.PEN_IS_ERASING,             1271             PenState.PEN_IS_ERASING,
1272             PenState.PEN_IS_ERASING_WITH_BUTT    1272             PenState.PEN_IS_ERASING_WITH_BUTTON,
1273         ) and pen.current_state in (             1273         ) and pen.current_state in (
1274             PenState.PEN_IS_IN_RANGE,            1274             PenState.PEN_IS_IN_RANGE,
1275             PenState.PEN_IS_IN_RANGE_WITH_BUT    1275             PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
1276             PenState.PEN_IS_IN_CONTACT,          1276             PenState.PEN_IS_IN_CONTACT,
1277             PenState.PEN_IS_IN_CONTACT_WITH_B    1277             PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
1278         ):                                       1278         ):
1279             rs.extend(                           1279             rs.extend(
1280                 self.send_intermediate_state(    1280                 self.send_intermediate_state(pen, PenState.PEN_IS_OUT_OF_RANGE, button)
1281             )                                    1281             )
1282                                                  1282 
1283         if self.previous_state == PenState.PE    1283         if self.previous_state == PenState.PEN_IS_OUT_OF_RANGE:
1284             if pen.current_state == PenState.    1284             if pen.current_state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
1285                 rs.extend(                       1285                 rs.extend(
1286                     self.send_intermediate_st    1286                     self.send_intermediate_state(pen, PenState.PEN_IS_IN_RANGE, button)
1287                 )                                1287                 )
1288                                                  1288 
1289         rs.extend(super().event(pen, button))    1289         rs.extend(super().event(pen, button))
1290         self.previous_state = pen.current_sta    1290         self.previous_state = pen.current_state
1291         return rs                                1291         return rs
1292                                                  1292 
1293                                                  1293 
1294 #############################################    1294 ################################################################################
1295 #                                                1295 #
1296 # Windows 7 compatible devices                   1296 # Windows 7 compatible devices
1297 #                                                1297 #
1298 #############################################    1298 ################################################################################
1299 # class TestEgalax_capacitive_0eef_7224(BaseT    1299 # class TestEgalax_capacitive_0eef_7224(BaseTest.TestTablet):
1300 #     def create_device(self):                   1300 #     def create_device(self):
1301 #         return PenDigitizer('uhid test egal    1301 #         return PenDigitizer('uhid test egalax-capacitive_0eef_7224',
1302 #                             rdesc='05 0d 09    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=(Bus    1303 #                             input_info=(BusType.USB, 0x0eef, 0x7224),
1304 #                             evdev_name_suff    1304 #                             evdev_name_suffix=' Touchscreen')
1305 #                                                1305 #
1306 #                                                1306 #
1307 # class TestEgalax_capacitive_0eef_72fa(BaseT    1307 # class TestEgalax_capacitive_0eef_72fa(BaseTest.TestTablet):
1308 #     def create_device(self):                   1308 #     def create_device(self):
1309 #         return PenDigitizer('uhid test egal    1309 #         return PenDigitizer('uhid test egalax-capacitive_0eef_72fa',
1310 #                             rdesc='05 0d 09    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=(Bus    1311 #                             input_info=(BusType.USB, 0x0eef, 0x72fa),
1312 #                             evdev_name_suff    1312 #                             evdev_name_suffix=' Touchscreen')
1313 #                                                1313 #
1314 #                                                1314 #
1315 # class TestEgalax_capacitive_0eef_7336(BaseT    1315 # class TestEgalax_capacitive_0eef_7336(BaseTest.TestTablet):
1316 #     def create_device(self):                   1316 #     def create_device(self):
1317 #         return PenDigitizer('uhid test egal    1317 #         return PenDigitizer('uhid test egalax-capacitive_0eef_7336',
1318 #                             rdesc='05 0d 09    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=(Bus    1319 #                             input_info=(BusType.USB, 0x0eef, 0x7336),
1320 #                             evdev_name_suff    1320 #                             evdev_name_suffix=' Touchscreen')
1321 #                                                1321 #
1322 #                                                1322 #
1323 # class TestEgalax_capacitive_0eef_7337(BaseT    1323 # class TestEgalax_capacitive_0eef_7337(BaseTest.TestTablet):
1324 #     def create_device(self):                   1324 #     def create_device(self):
1325 #         return PenDigitizer('uhid test egal    1325 #         return PenDigitizer('uhid test egalax-capacitive_0eef_7337',
1326 #                             rdesc='05 0d 09    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=(Bus    1327 #                             input_info=(BusType.USB, 0x0eef, 0x7337),
1328 #                             evdev_name_suff    1328 #                             evdev_name_suffix=' Touchscreen')
1329 #                                                1329 #
1330 #                                                1330 #
1331 # class TestEgalax_capacitive_0eef_7349(BaseT    1331 # class TestEgalax_capacitive_0eef_7349(BaseTest.TestTablet):
1332 #     def create_device(self):                   1332 #     def create_device(self):
1333 #         return PenDigitizer('uhid test egal    1333 #         return PenDigitizer('uhid test egalax-capacitive_0eef_7349',
1334 #                             rdesc='05 0d 09    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=(Bus    1335 #                             input_info=(BusType.USB, 0x0eef, 0x7349),
1336 #                             evdev_name_suff    1336 #                             evdev_name_suffix=' Touchscreen')
1337 #                                                1337 #
1338 #                                                1338 #
1339 # class TestEgalax_capacitive_0eef_73f4(BaseT    1339 # class TestEgalax_capacitive_0eef_73f4(BaseTest.TestTablet):
1340 #     def create_device(self):                   1340 #     def create_device(self):
1341 #         return PenDigitizer('uhid test egal    1341 #         return PenDigitizer('uhid test egalax-capacitive_0eef_73f4',
1342 #                             rdesc='05 0d 09    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=(Bus    1343 #                             input_info=(BusType.USB, 0x0eef, 0x73f4),
1344 #                             evdev_name_suff    1344 #                             evdev_name_suffix=' Touchscreen')
1345 #                                                1345 #
1346 #  bogus: BTN_TOOL_PEN is not emitted            1346 #  bogus: BTN_TOOL_PEN is not emitted
1347 # class TestIrtouch_6615_0070(BaseTest.TestTa    1347 # class TestIrtouch_6615_0070(BaseTest.TestTablet):
1348 #     def create_device(self):                   1348 #     def create_device(self):
1349 #         return PenDigitizer('uhid test irto    1349 #         return PenDigitizer('uhid test irtouch_6615_0070',
1350 #                             rdesc='05 01 09    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=(Bus    1351 #                             input_info=(BusType.USB, 0x6615, 0x0070))
1352                                                  1352 
1353                                                  1353 
1354 class TestNexio_1870_0100(BaseTest.TestTablet    1354 class TestNexio_1870_0100(BaseTest.TestTablet):
1355     def create_device(self):                     1355     def create_device(self):
1356         return PenDigitizer(                     1356         return PenDigitizer(
1357             "uhid test nexio_1870_0100",         1357             "uhid test nexio_1870_0100",
1358             rdesc="05 0d 09 04 a1 01 85 01 09    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,     1359             input_info=(BusType.USB, 0x1870, 0x0100),
1360         )                                        1360         )
1361                                                  1361 
1362                                                  1362 
1363 class TestNexio_1870_010d(BaseTest.TestTablet    1363 class TestNexio_1870_010d(BaseTest.TestTablet):
1364     def create_device(self):                     1364     def create_device(self):
1365         return PenDigitizer(                     1365         return PenDigitizer(
1366             "uhid test nexio_1870_010d",         1366             "uhid test nexio_1870_010d",
1367             rdesc="05 0d 09 04 a1 01 85 01 09    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,     1368             input_info=(BusType.USB, 0x1870, 0x010D),
1369         )                                        1369         )
1370                                                  1370 
1371                                                  1371 
1372 class TestNexio_1870_0119(BaseTest.TestTablet    1372 class TestNexio_1870_0119(BaseTest.TestTablet):
1373     def create_device(self):                     1373     def create_device(self):
1374         return PenDigitizer(                     1374         return PenDigitizer(
1375             "uhid test nexio_1870_0119",         1375             "uhid test nexio_1870_0119",
1376             rdesc="05 0d 09 04 a1 01 85 01 09    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,     1377             input_info=(BusType.USB, 0x1870, 0x0119),
1378         )                                        1378         )
1379                                                  1379 
1380                                                  1380 
1381 #############################################    1381 ################################################################################
1382 #                                                1382 #
1383 # Windows 8 compatible devices                   1383 # Windows 8 compatible devices
1384 #                                                1384 #
1385 #############################################    1385 ################################################################################
1386                                                  1386 
1387 # bogus: application is 'undefined'              1387 # bogus: application is 'undefined'
1388 # class Testatmel_03eb_8409(BaseTest.TestTabl    1388 # class Testatmel_03eb_8409(BaseTest.TestTablet):
1389 #     def create_device(self):                   1389 #     def create_device(self):
1390 #         return PenDigitizer('uhid test atme    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                                                  1391 
1392                                                  1392 
1393 class Testatmel_03eb_840b(BaseTest.TestTablet    1393 class Testatmel_03eb_840b(BaseTest.TestTablet):
1394     def create_device(self):                     1394     def create_device(self):
1395         return PenDigitizer(                     1395         return PenDigitizer(
1396             "uhid test atmel_03eb_840b",         1396             "uhid test atmel_03eb_840b",
1397             rdesc="05 0d 09 04 a1 01 85 01 09    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         )                                        1398         )
1399                                                  1399 
1400                                                  1400 
1401 class Testn_trig_1b96_0c01(BaseTest.TestTable    1401 class Testn_trig_1b96_0c01(BaseTest.TestTablet):
1402     def create_device(self):                     1402     def create_device(self):
1403         return PenDigitizer(                     1403         return PenDigitizer(
1404             "uhid test n_trig_1b96_0c01",        1404             "uhid test n_trig_1b96_0c01",
1405             rdesc="75 08 15 00 26 ff 00 06 0b    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         )                                        1406         )
1407                                                  1407 
1408                                                  1408 
1409 class Testn_trig_1b96_0c03(BaseTest.TestTable    1409 class Testn_trig_1b96_0c03(BaseTest.TestTablet):
1410     def create_device(self):                     1410     def create_device(self):
1411         return PenDigitizer(                     1411         return PenDigitizer(
1412             "uhid test n_trig_1b96_0c03",        1412             "uhid test n_trig_1b96_0c03",
1413             rdesc="75 08 15 00 26 ff 00 06 0b    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         )                                        1414         )
1415                                                  1415 
1416                                                  1416 
1417 class Testn_trig_1b96_0f00(BaseTest.TestTable    1417 class Testn_trig_1b96_0f00(BaseTest.TestTablet):
1418     def create_device(self):                     1418     def create_device(self):
1419         return PenDigitizer(                     1419         return PenDigitizer(
1420             "uhid test n_trig_1b96_0f00",        1420             "uhid test n_trig_1b96_0f00",
1421             rdesc="75 08 15 00 26 ff 00 06 0b    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         )                                        1422         )
1423                                                  1423 
1424                                                  1424 
1425 class Testn_trig_1b96_0f04(BaseTest.TestTable    1425 class Testn_trig_1b96_0f04(BaseTest.TestTablet):
1426     def create_device(self):                     1426     def create_device(self):
1427         return PenDigitizer(                     1427         return PenDigitizer(
1428             "uhid test n_trig_1b96_0f04",        1428             "uhid test n_trig_1b96_0f04",
1429             rdesc="75 08 15 00 26 ff 00 06 0b    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         )                                        1430         )
1431                                                  1431 
1432                                                  1432 
1433 class Testn_trig_1b96_1000(BaseTest.TestTable    1433 class Testn_trig_1b96_1000(BaseTest.TestTablet):
1434     def create_device(self):                     1434     def create_device(self):
1435         return PenDigitizer(                     1435         return PenDigitizer(
1436             "uhid test n_trig_1b96_1000",        1436             "uhid test n_trig_1b96_1000",
1437             rdesc="75 08 15 00 26 ff 00 06 0b    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         )                                        1438         )
1439                                                  1439 
1440                                                  1440 
1441 class TestGXTP_27c6_0113(BaseTest.TestTablet)    1441 class TestGXTP_27c6_0113(BaseTest.TestTablet):
1442     def create_device(self):                     1442     def create_device(self):
1443         return GXTP_pen(                         1443         return GXTP_pen(
1444             "uhid test GXTP_27c6_0113",          1444             "uhid test GXTP_27c6_0113",
1445             rdesc="05 0d 09 04 a1 01 85 01 09    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         )                                        1446         )
1447                                                  1447 
1448                                                  1448 
1449 #############################################    1449 ################################################################################
1450 #                                                1450 #
1451 # Windows 8 compatible devices with USI Pen      1451 # Windows 8 compatible devices with USI Pen
1452 #                                                1452 #
1453 #############################################    1453 ################################################################################
1454                                                  1454 
1455                                                  1455 
1456 class TestElan_04f3_2A49(BaseTest.TestTablet)    1456 class TestElan_04f3_2A49(BaseTest.TestTablet):
1457     def create_device(self):                     1457     def create_device(self):
1458         return USIPen(                           1458         return USIPen(
1459             "uhid test Elan_04f3_2A49",          1459             "uhid test Elan_04f3_2A49",
1460             rdesc="05 0d 09 04 a1 01 85 01 09    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,     1461             input_info=(BusType.I2C, 0x04F3, 0x2A49),
1462         )                                        1462         )
1463                                                  1463 
1464                                                  1464 
1465 class TestGoodix_27c6_0e00(BaseTest.TestTable    1465 class TestGoodix_27c6_0e00(BaseTest.TestTablet):
1466     def create_device(self):                     1466     def create_device(self):
1467         return USIPen(                           1467         return USIPen(
1468             "uhid test Elan_04f3_2A49",          1468             "uhid test Elan_04f3_2A49",
1469             rdesc="05 0d 09 04 a1 01 85 01 09    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,     1470             input_info=(BusType.I2C, 0x27C6, 0x0E00),
1471         )                                        1471         )
1472                                                  1472 
1473                                                  1473 
1474 class TestXPPen_ArtistPro16Gen2_28bd_095b(Bas    1474 class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
1475     hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.    1475     hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)]
1476                                                  1476 
1477     def create_device(self):                     1477     def create_device(self):
1478         dev = XPPen_ArtistPro16Gen2_28bd_095b    1478         dev = XPPen_ArtistPro16Gen2_28bd_095b(
1479             "uhid test XPPen Artist Pro 16 Ge    1479             "uhid test XPPen Artist Pro 16 Gen2 28bd 095b",
1480             rdesc="05 0d 09 02 a1 01 85 07 09    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,     1481             input_info=(BusType.USB, 0x28BD, 0x095B),
1482         )                                        1482         )
1483         return dev                               1483         return dev
1484                                                  1484 
1485                                                  1485 
1486 class TestXPPen_Artist24_28bd_093a(BaseTest.T    1486 class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
1487     hid_bpfs = [("XPPen__Artist24.bpf.o", Tru    1487     hid_bpfs = [("XPPen__Artist24.bpf.o", True)]
1488                                                  1488 
1489     def create_device(self):                     1489     def create_device(self):
1490         return XPPen_Artist24_28bd_093a(         1490         return XPPen_Artist24_28bd_093a(
1491             "uhid test XPPen Artist 24 28bd 0    1491             "uhid test XPPen Artist 24 28bd 093a",
1492             rdesc="05 0d 09 02 a1 01 85 07 09    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,     1493             input_info=(BusType.USB, 0x28BD, 0x093A),
1494         )                                        1494         )
1495                                                  1495 
1496                                                  1496 
1497 class TestHuion_Kamvas_Pro_19_256c_006b(BaseT    1497 class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
1498     hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o"    1498     hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)]
1499                                                  1499 
1500     def create_device(self):                     1500     def create_device(self):
1501         return Huion_Kamvas_Pro_19_256c_006b(    1501         return Huion_Kamvas_Pro_19_256c_006b(
1502             "uhid test HUION Huion Tablet_GT1    1502             "uhid test HUION Huion Tablet_GT1902",
1503             rdesc="05 0d 09 02 a1 01 85 0a 09    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,     1504             input_info=(BusType.USB, 0x256C, 0x006B),
1505         )                                        1505         )
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php