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 )
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.