Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / hid / tests / test_mouse.py
blob66daf7e5975ca50f0b065080669d7f6123fb177f
1 #!/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0
3 # -*- coding: utf-8 -*-
5 # Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6 # Copyright (c) 2017 Red Hat, Inc.
9 from . import base
10 import hidtools.hid
11 from hidtools.util import BusType
12 import libevdev
13 import logging
14 import pytest
16 logger = logging.getLogger("hidtools.test.mouse")
18 # workaround https://gitlab.freedesktop.org/libevdev/python-libevdev/issues/6
19 try:
20 libevdev.EV_REL.REL_WHEEL_HI_RES
21 except AttributeError:
22 libevdev.EV_REL.REL_WHEEL_HI_RES = libevdev.EV_REL.REL_0B
23 libevdev.EV_REL.REL_HWHEEL_HI_RES = libevdev.EV_REL.REL_0C
26 class InvalidHIDCommunication(Exception):
27 pass
30 class MouseData(object):
31 pass
34 class BaseMouse(base.UHIDTestDevice):
35 def __init__(self, rdesc, name=None, input_info=None):
36 assert rdesc is not None
37 super().__init__(name, "Mouse", input_info=input_info, rdesc=rdesc)
38 self.left = False
39 self.right = False
40 self.middle = False
42 def create_report(self, x, y, buttons=None, wheels=None, reportID=None):
43 """
44 Return an input report for this device.
46 :param x: relative x
47 :param y: relative y
48 :param buttons: a (l, r, m) tuple of bools for the button states,
49 where ``None`` is "leave unchanged"
50 :param wheels: a single value for the vertical wheel or a (vertical, horizontal) tuple for
51 the two wheels
52 :param reportID: the numeric report ID for this report, if needed
53 """
54 if buttons is not None:
55 left, right, middle = buttons
56 if left is not None:
57 self.left = left
58 if right is not None:
59 self.right = right
60 if middle is not None:
61 self.middle = middle
62 left = self.left
63 right = self.right
64 middle = self.middle
65 # Note: the BaseMouse doesn't actually have a wheel but the
66 # create_report magic only fills in those fields exist, so let's
67 # make this generic here.
68 wheel, acpan = 0, 0
69 if wheels is not None:
70 if isinstance(wheels, tuple):
71 wheel = wheels[0]
72 acpan = wheels[1]
73 else:
74 wheel = wheels
76 reportID = reportID or self.default_reportID
78 mouse = MouseData()
79 mouse.b1 = int(left)
80 mouse.b2 = int(right)
81 mouse.b3 = int(middle)
82 mouse.x = x
83 mouse.y = y
84 mouse.wheel = wheel
85 mouse.acpan = acpan
86 return super().create_report(mouse, reportID=reportID)
88 def event(self, x, y, buttons=None, wheels=None):
89 """
90 Send an input event on the default report ID.
92 :param x: relative x
93 :param y: relative y
94 :param buttons: a (l, r, m) tuple of bools for the button states,
95 where ``None`` is "leave unchanged"
96 :param wheels: a single value for the vertical wheel or a (vertical, horizontal) tuple for
97 the two wheels
98 """
99 r = self.create_report(x, y, buttons, wheels)
100 self.call_input_event(r)
101 return [r]
104 class ButtonMouse(BaseMouse):
105 # fmt: off
106 report_descriptor = [
107 0x05, 0x01, # .Usage Page (Generic Desktop) 0
108 0x09, 0x02, # .Usage (Mouse) 2
109 0xa1, 0x01, # .Collection (Application) 4
110 0x09, 0x02, # ..Usage (Mouse) 6
111 0xa1, 0x02, # ..Collection (Logical) 8
112 0x09, 0x01, # ...Usage (Pointer) 10
113 0xa1, 0x00, # ...Collection (Physical) 12
114 0x05, 0x09, # ....Usage Page (Button) 14
115 0x19, 0x01, # ....Usage Minimum (1) 16
116 0x29, 0x03, # ....Usage Maximum (3) 18
117 0x15, 0x00, # ....Logical Minimum (0) 20
118 0x25, 0x01, # ....Logical Maximum (1) 22
119 0x75, 0x01, # ....Report Size (1) 24
120 0x95, 0x03, # ....Report Count (3) 26
121 0x81, 0x02, # ....Input (Data,Var,Abs) 28
122 0x75, 0x05, # ....Report Size (5) 30
123 0x95, 0x01, # ....Report Count (1) 32
124 0x81, 0x03, # ....Input (Cnst,Var,Abs) 34
125 0x05, 0x01, # ....Usage Page (Generic Desktop) 36
126 0x09, 0x30, # ....Usage (X) 38
127 0x09, 0x31, # ....Usage (Y) 40
128 0x15, 0x81, # ....Logical Minimum (-127) 42
129 0x25, 0x7f, # ....Logical Maximum (127) 44
130 0x75, 0x08, # ....Report Size (8) 46
131 0x95, 0x02, # ....Report Count (2) 48
132 0x81, 0x06, # ....Input (Data,Var,Rel) 50
133 0xc0, # ...End Collection 52
134 0xc0, # ..End Collection 53
135 0xc0, # .End Collection 54
137 # fmt: on
139 def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
140 super().__init__(rdesc, name, input_info)
142 def fake_report(self, x, y, buttons):
143 if buttons is not None:
144 left, right, middle = buttons
145 if left is None:
146 left = self.left
147 if right is None:
148 right = self.right
149 if middle is None:
150 middle = self.middle
151 else:
152 left = self.left
153 right = self.right
154 middle = self.middle
156 button_mask = sum(1 << i for i, b in enumerate([left, right, middle]) if b)
157 x = max(-127, min(127, x))
158 y = max(-127, min(127, y))
159 x = hidtools.util.to_twos_comp(x, 8)
160 y = hidtools.util.to_twos_comp(y, 8)
161 return [button_mask, x, y]
164 class WheelMouse(ButtonMouse):
165 # fmt: off
166 report_descriptor = [
167 0x05, 0x01, # Usage Page (Generic Desktop) 0
168 0x09, 0x02, # Usage (Mouse) 2
169 0xa1, 0x01, # Collection (Application) 4
170 0x05, 0x09, # .Usage Page (Button) 6
171 0x19, 0x01, # .Usage Minimum (1) 8
172 0x29, 0x03, # .Usage Maximum (3) 10
173 0x15, 0x00, # .Logical Minimum (0) 12
174 0x25, 0x01, # .Logical Maximum (1) 14
175 0x95, 0x03, # .Report Count (3) 16
176 0x75, 0x01, # .Report Size (1) 18
177 0x81, 0x02, # .Input (Data,Var,Abs) 20
178 0x95, 0x01, # .Report Count (1) 22
179 0x75, 0x05, # .Report Size (5) 24
180 0x81, 0x03, # .Input (Cnst,Var,Abs) 26
181 0x05, 0x01, # .Usage Page (Generic Desktop) 28
182 0x09, 0x01, # .Usage (Pointer) 30
183 0xa1, 0x00, # .Collection (Physical) 32
184 0x09, 0x30, # ..Usage (X) 34
185 0x09, 0x31, # ..Usage (Y) 36
186 0x15, 0x81, # ..Logical Minimum (-127) 38
187 0x25, 0x7f, # ..Logical Maximum (127) 40
188 0x75, 0x08, # ..Report Size (8) 42
189 0x95, 0x02, # ..Report Count (2) 44
190 0x81, 0x06, # ..Input (Data,Var,Rel) 46
191 0xc0, # .End Collection 48
192 0x09, 0x38, # .Usage (Wheel) 49
193 0x15, 0x81, # .Logical Minimum (-127) 51
194 0x25, 0x7f, # .Logical Maximum (127) 53
195 0x75, 0x08, # .Report Size (8) 55
196 0x95, 0x01, # .Report Count (1) 57
197 0x81, 0x06, # .Input (Data,Var,Rel) 59
198 0xc0, # End Collection 61
200 # fmt: on
202 def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
203 super().__init__(rdesc, name, input_info)
204 self.wheel_multiplier = 1
207 class TwoWheelMouse(WheelMouse):
208 # fmt: off
209 report_descriptor = [
210 0x05, 0x01, # Usage Page (Generic Desktop) 0
211 0x09, 0x02, # Usage (Mouse) 2
212 0xa1, 0x01, # Collection (Application) 4
213 0x09, 0x01, # .Usage (Pointer) 6
214 0xa1, 0x00, # .Collection (Physical) 8
215 0x05, 0x09, # ..Usage Page (Button) 10
216 0x19, 0x01, # ..Usage Minimum (1) 12
217 0x29, 0x10, # ..Usage Maximum (16) 14
218 0x15, 0x00, # ..Logical Minimum (0) 16
219 0x25, 0x01, # ..Logical Maximum (1) 18
220 0x95, 0x10, # ..Report Count (16) 20
221 0x75, 0x01, # ..Report Size (1) 22
222 0x81, 0x02, # ..Input (Data,Var,Abs) 24
223 0x05, 0x01, # ..Usage Page (Generic Desktop) 26
224 0x16, 0x01, 0x80, # ..Logical Minimum (-32767) 28
225 0x26, 0xff, 0x7f, # ..Logical Maximum (32767) 31
226 0x75, 0x10, # ..Report Size (16) 34
227 0x95, 0x02, # ..Report Count (2) 36
228 0x09, 0x30, # ..Usage (X) 38
229 0x09, 0x31, # ..Usage (Y) 40
230 0x81, 0x06, # ..Input (Data,Var,Rel) 42
231 0x15, 0x81, # ..Logical Minimum (-127) 44
232 0x25, 0x7f, # ..Logical Maximum (127) 46
233 0x75, 0x08, # ..Report Size (8) 48
234 0x95, 0x01, # ..Report Count (1) 50
235 0x09, 0x38, # ..Usage (Wheel) 52
236 0x81, 0x06, # ..Input (Data,Var,Rel) 54
237 0x05, 0x0c, # ..Usage Page (Consumer Devices) 56
238 0x0a, 0x38, 0x02, # ..Usage (AC Pan) 58
239 0x95, 0x01, # ..Report Count (1) 61
240 0x81, 0x06, # ..Input (Data,Var,Rel) 63
241 0xc0, # .End Collection 65
242 0xc0, # End Collection 66
244 # fmt: on
246 def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
247 super().__init__(rdesc, name, input_info)
248 self.hwheel_multiplier = 1
251 class MIDongleMIWirelessMouse(TwoWheelMouse):
252 # fmt: off
253 report_descriptor = [
254 0x05, 0x01, # Usage Page (Generic Desktop)
255 0x09, 0x02, # Usage (Mouse)
256 0xa1, 0x01, # Collection (Application)
257 0x85, 0x01, # .Report ID (1)
258 0x09, 0x01, # .Usage (Pointer)
259 0xa1, 0x00, # .Collection (Physical)
260 0x95, 0x05, # ..Report Count (5)
261 0x75, 0x01, # ..Report Size (1)
262 0x05, 0x09, # ..Usage Page (Button)
263 0x19, 0x01, # ..Usage Minimum (1)
264 0x29, 0x05, # ..Usage Maximum (5)
265 0x15, 0x00, # ..Logical Minimum (0)
266 0x25, 0x01, # ..Logical Maximum (1)
267 0x81, 0x02, # ..Input (Data,Var,Abs)
268 0x95, 0x01, # ..Report Count (1)
269 0x75, 0x03, # ..Report Size (3)
270 0x81, 0x01, # ..Input (Cnst,Arr,Abs)
271 0x75, 0x08, # ..Report Size (8)
272 0x95, 0x01, # ..Report Count (1)
273 0x05, 0x01, # ..Usage Page (Generic Desktop)
274 0x09, 0x38, # ..Usage (Wheel)
275 0x15, 0x81, # ..Logical Minimum (-127)
276 0x25, 0x7f, # ..Logical Maximum (127)
277 0x81, 0x06, # ..Input (Data,Var,Rel)
278 0x05, 0x0c, # ..Usage Page (Consumer Devices)
279 0x0a, 0x38, 0x02, # ..Usage (AC Pan)
280 0x95, 0x01, # ..Report Count (1)
281 0x81, 0x06, # ..Input (Data,Var,Rel)
282 0xc0, # .End Collection
283 0x85, 0x02, # .Report ID (2)
284 0x09, 0x01, # .Usage (Consumer Control)
285 0xa1, 0x00, # .Collection (Physical)
286 0x75, 0x0c, # ..Report Size (12)
287 0x95, 0x02, # ..Report Count (2)
288 0x05, 0x01, # ..Usage Page (Generic Desktop)
289 0x09, 0x30, # ..Usage (X)
290 0x09, 0x31, # ..Usage (Y)
291 0x16, 0x01, 0xf8, # ..Logical Minimum (-2047)
292 0x26, 0xff, 0x07, # ..Logical Maximum (2047)
293 0x81, 0x06, # ..Input (Data,Var,Rel)
294 0xc0, # .End Collection
295 0xc0, # End Collection
296 0x05, 0x0c, # Usage Page (Consumer Devices)
297 0x09, 0x01, # Usage (Consumer Control)
298 0xa1, 0x01, # Collection (Application)
299 0x85, 0x03, # .Report ID (3)
300 0x15, 0x00, # .Logical Minimum (0)
301 0x25, 0x01, # .Logical Maximum (1)
302 0x75, 0x01, # .Report Size (1)
303 0x95, 0x01, # .Report Count (1)
304 0x09, 0xcd, # .Usage (Play/Pause)
305 0x81, 0x06, # .Input (Data,Var,Rel)
306 0x0a, 0x83, 0x01, # .Usage (AL Consumer Control Config)
307 0x81, 0x06, # .Input (Data,Var,Rel)
308 0x09, 0xb5, # .Usage (Scan Next Track)
309 0x81, 0x06, # .Input (Data,Var,Rel)
310 0x09, 0xb6, # .Usage (Scan Previous Track)
311 0x81, 0x06, # .Input (Data,Var,Rel)
312 0x09, 0xea, # .Usage (Volume Down)
313 0x81, 0x06, # .Input (Data,Var,Rel)
314 0x09, 0xe9, # .Usage (Volume Up)
315 0x81, 0x06, # .Input (Data,Var,Rel)
316 0x0a, 0x25, 0x02, # .Usage (AC Forward)
317 0x81, 0x06, # .Input (Data,Var,Rel)
318 0x0a, 0x24, 0x02, # .Usage (AC Back)
319 0x81, 0x06, # .Input (Data,Var,Rel)
320 0xc0, # End Collection
322 # fmt: on
323 device_input_info = (BusType.USB, 0x2717, 0x003B)
324 device_name = "uhid test MI Dongle MI Wireless Mouse"
326 def __init__(
327 self, rdesc=report_descriptor, name=device_name, input_info=device_input_info
329 super().__init__(rdesc, name, input_info)
331 def event(self, x, y, buttons=None, wheels=None):
332 # this mouse spreads the relative pointer and the mouse buttons
333 # onto 2 distinct reports
334 rs = []
335 r = self.create_report(x, y, buttons, wheels, reportID=1)
336 self.call_input_event(r)
337 rs.append(r)
338 r = self.create_report(x, y, buttons, reportID=2)
339 self.call_input_event(r)
340 rs.append(r)
341 return rs
344 class ResolutionMultiplierMouse(TwoWheelMouse):
345 # fmt: off
346 report_descriptor = [
347 0x05, 0x01, # Usage Page (Generic Desktop) 83
348 0x09, 0x02, # Usage (Mouse) 85
349 0xa1, 0x01, # Collection (Application) 87
350 0x05, 0x01, # .Usage Page (Generic Desktop) 89
351 0x09, 0x02, # .Usage (Mouse) 91
352 0xa1, 0x02, # .Collection (Logical) 93
353 0x85, 0x11, # ..Report ID (17) 95
354 0x09, 0x01, # ..Usage (Pointer) 97
355 0xa1, 0x00, # ..Collection (Physical) 99
356 0x05, 0x09, # ...Usage Page (Button) 101
357 0x19, 0x01, # ...Usage Minimum (1) 103
358 0x29, 0x03, # ...Usage Maximum (3) 105
359 0x95, 0x03, # ...Report Count (3) 107
360 0x75, 0x01, # ...Report Size (1) 109
361 0x25, 0x01, # ...Logical Maximum (1) 111
362 0x81, 0x02, # ...Input (Data,Var,Abs) 113
363 0x95, 0x01, # ...Report Count (1) 115
364 0x81, 0x01, # ...Input (Cnst,Arr,Abs) 117
365 0x09, 0x05, # ...Usage (Vendor Usage 0x05) 119
366 0x81, 0x02, # ...Input (Data,Var,Abs) 121
367 0x95, 0x03, # ...Report Count (3) 123
368 0x81, 0x01, # ...Input (Cnst,Arr,Abs) 125
369 0x05, 0x01, # ...Usage Page (Generic Desktop) 127
370 0x09, 0x30, # ...Usage (X) 129
371 0x09, 0x31, # ...Usage (Y) 131
372 0x95, 0x02, # ...Report Count (2) 133
373 0x75, 0x08, # ...Report Size (8) 135
374 0x15, 0x81, # ...Logical Minimum (-127) 137
375 0x25, 0x7f, # ...Logical Maximum (127) 139
376 0x81, 0x06, # ...Input (Data,Var,Rel) 141
377 0xa1, 0x02, # ...Collection (Logical) 143
378 0x85, 0x12, # ....Report ID (18) 145
379 0x09, 0x48, # ....Usage (Resolution Multiplier) 147
380 0x95, 0x01, # ....Report Count (1) 149
381 0x75, 0x02, # ....Report Size (2) 151
382 0x15, 0x00, # ....Logical Minimum (0) 153
383 0x25, 0x01, # ....Logical Maximum (1) 155
384 0x35, 0x01, # ....Physical Minimum (1) 157
385 0x45, 0x04, # ....Physical Maximum (4) 159
386 0xb1, 0x02, # ....Feature (Data,Var,Abs) 161
387 0x35, 0x00, # ....Physical Minimum (0) 163
388 0x45, 0x00, # ....Physical Maximum (0) 165
389 0x75, 0x06, # ....Report Size (6) 167
390 0xb1, 0x01, # ....Feature (Cnst,Arr,Abs) 169
391 0x85, 0x11, # ....Report ID (17) 171
392 0x09, 0x38, # ....Usage (Wheel) 173
393 0x15, 0x81, # ....Logical Minimum (-127) 175
394 0x25, 0x7f, # ....Logical Maximum (127) 177
395 0x75, 0x08, # ....Report Size (8) 179
396 0x81, 0x06, # ....Input (Data,Var,Rel) 181
397 0xc0, # ...End Collection 183
398 0x05, 0x0c, # ...Usage Page (Consumer Devices) 184
399 0x75, 0x08, # ...Report Size (8) 186
400 0x0a, 0x38, 0x02, # ...Usage (AC Pan) 188
401 0x81, 0x06, # ...Input (Data,Var,Rel) 191
402 0xc0, # ..End Collection 193
403 0xc0, # .End Collection 194
404 0xc0, # End Collection 195
406 # fmt: on
408 def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
409 super().__init__(rdesc, name, input_info)
410 self.default_reportID = 0x11
412 # Feature Report 12, multiplier Feature value must be set to 0b01,
413 # i.e. 1. We should extract that from the descriptor instead
414 # of hardcoding it here, but meanwhile this will do.
415 self.set_feature_report = [0x12, 0x1]
417 def set_report(self, req, rnum, rtype, data):
418 if rtype != self.UHID_FEATURE_REPORT:
419 raise InvalidHIDCommunication(f"Unexpected report type: {rtype}")
420 if rnum != 0x12:
421 raise InvalidHIDCommunication(f"Unexpected report number: {rnum}")
423 if data != self.set_feature_report:
424 raise InvalidHIDCommunication(
425 f"Unexpected data: {data}, expected {self.set_feature_report}"
428 self.wheel_multiplier = 4
430 return 0
433 class BadResolutionMultiplierMouse(ResolutionMultiplierMouse):
434 def set_report(self, req, rnum, rtype, data):
435 super().set_report(req, rnum, rtype, data)
437 self.wheel_multiplier = 1
438 self.hwheel_multiplier = 1
439 return 32 # EPIPE
442 class ResolutionMultiplierHWheelMouse(TwoWheelMouse):
443 # fmt: off
444 report_descriptor = [
445 0x05, 0x01, # Usage Page (Generic Desktop) 0
446 0x09, 0x02, # Usage (Mouse) 2
447 0xa1, 0x01, # Collection (Application) 4
448 0x05, 0x01, # .Usage Page (Generic Desktop) 6
449 0x09, 0x02, # .Usage (Mouse) 8
450 0xa1, 0x02, # .Collection (Logical) 10
451 0x85, 0x1a, # ..Report ID (26) 12
452 0x09, 0x01, # ..Usage (Pointer) 14
453 0xa1, 0x00, # ..Collection (Physical) 16
454 0x05, 0x09, # ...Usage Page (Button) 18
455 0x19, 0x01, # ...Usage Minimum (1) 20
456 0x29, 0x05, # ...Usage Maximum (5) 22
457 0x95, 0x05, # ...Report Count (5) 24
458 0x75, 0x01, # ...Report Size (1) 26
459 0x15, 0x00, # ...Logical Minimum (0) 28
460 0x25, 0x01, # ...Logical Maximum (1) 30
461 0x81, 0x02, # ...Input (Data,Var,Abs) 32
462 0x75, 0x03, # ...Report Size (3) 34
463 0x95, 0x01, # ...Report Count (1) 36
464 0x81, 0x01, # ...Input (Cnst,Arr,Abs) 38
465 0x05, 0x01, # ...Usage Page (Generic Desktop) 40
466 0x09, 0x30, # ...Usage (X) 42
467 0x09, 0x31, # ...Usage (Y) 44
468 0x95, 0x02, # ...Report Count (2) 46
469 0x75, 0x10, # ...Report Size (16) 48
470 0x16, 0x01, 0x80, # ...Logical Minimum (-32767) 50
471 0x26, 0xff, 0x7f, # ...Logical Maximum (32767) 53
472 0x81, 0x06, # ...Input (Data,Var,Rel) 56
473 0xa1, 0x02, # ...Collection (Logical) 58
474 0x85, 0x12, # ....Report ID (18) 60
475 0x09, 0x48, # ....Usage (Resolution Multiplier) 62
476 0x95, 0x01, # ....Report Count (1) 64
477 0x75, 0x02, # ....Report Size (2) 66
478 0x15, 0x00, # ....Logical Minimum (0) 68
479 0x25, 0x01, # ....Logical Maximum (1) 70
480 0x35, 0x01, # ....Physical Minimum (1) 72
481 0x45, 0x0c, # ....Physical Maximum (12) 74
482 0xb1, 0x02, # ....Feature (Data,Var,Abs) 76
483 0x85, 0x1a, # ....Report ID (26) 78
484 0x09, 0x38, # ....Usage (Wheel) 80
485 0x35, 0x00, # ....Physical Minimum (0) 82
486 0x45, 0x00, # ....Physical Maximum (0) 84
487 0x95, 0x01, # ....Report Count (1) 86
488 0x75, 0x10, # ....Report Size (16) 88
489 0x16, 0x01, 0x80, # ....Logical Minimum (-32767) 90
490 0x26, 0xff, 0x7f, # ....Logical Maximum (32767) 93
491 0x81, 0x06, # ....Input (Data,Var,Rel) 96
492 0xc0, # ...End Collection 98
493 0xa1, 0x02, # ...Collection (Logical) 99
494 0x85, 0x12, # ....Report ID (18) 101
495 0x09, 0x48, # ....Usage (Resolution Multiplier) 103
496 0x75, 0x02, # ....Report Size (2) 105
497 0x15, 0x00, # ....Logical Minimum (0) 107
498 0x25, 0x01, # ....Logical Maximum (1) 109
499 0x35, 0x01, # ....Physical Minimum (1) 111
500 0x45, 0x0c, # ....Physical Maximum (12) 113
501 0xb1, 0x02, # ....Feature (Data,Var,Abs) 115
502 0x35, 0x00, # ....Physical Minimum (0) 117
503 0x45, 0x00, # ....Physical Maximum (0) 119
504 0x75, 0x04, # ....Report Size (4) 121
505 0xb1, 0x01, # ....Feature (Cnst,Arr,Abs) 123
506 0x85, 0x1a, # ....Report ID (26) 125
507 0x05, 0x0c, # ....Usage Page (Consumer Devices) 127
508 0x95, 0x01, # ....Report Count (1) 129
509 0x75, 0x10, # ....Report Size (16) 131
510 0x16, 0x01, 0x80, # ....Logical Minimum (-32767) 133
511 0x26, 0xff, 0x7f, # ....Logical Maximum (32767) 136
512 0x0a, 0x38, 0x02, # ....Usage (AC Pan) 139
513 0x81, 0x06, # ....Input (Data,Var,Rel) 142
514 0xc0, # ...End Collection 144
515 0xc0, # ..End Collection 145
516 0xc0, # .End Collection 146
517 0xc0, # End Collection 147
519 # fmt: on
521 def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
522 super().__init__(rdesc, name, input_info)
523 self.default_reportID = 0x1A
525 # Feature Report 12, multiplier Feature value must be set to 0b0101,
526 # i.e. 5. We should extract that from the descriptor instead
527 # of hardcoding it here, but meanwhile this will do.
528 self.set_feature_report = [0x12, 0x5]
530 def set_report(self, req, rnum, rtype, data):
531 super().set_report(req, rnum, rtype, data)
533 self.wheel_multiplier = 12
534 self.hwheel_multiplier = 12
536 return 0
539 class BaseTest:
540 class TestMouse(base.BaseTestCase.TestUhid):
541 def test_buttons(self):
542 """check for button reliability."""
543 uhdev = self.uhdev
544 evdev = uhdev.get_evdev()
545 syn_event = self.syn_event
547 r = uhdev.event(0, 0, (None, True, None))
548 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
549 events = uhdev.next_sync_events()
550 self.debug_reports(r, uhdev, events)
551 self.assertInputEventsIn((syn_event, expected_event), events)
552 assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
554 r = uhdev.event(0, 0, (None, False, None))
555 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
556 events = uhdev.next_sync_events()
557 self.debug_reports(r, uhdev, events)
558 self.assertInputEventsIn((syn_event, expected_event), events)
559 assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
561 r = uhdev.event(0, 0, (None, None, True))
562 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 1)
563 events = uhdev.next_sync_events()
564 self.debug_reports(r, uhdev, events)
565 self.assertInputEventsIn((syn_event, expected_event), events)
566 assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 1
568 r = uhdev.event(0, 0, (None, None, False))
569 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 0)
570 events = uhdev.next_sync_events()
571 self.debug_reports(r, uhdev, events)
572 self.assertInputEventsIn((syn_event, expected_event), events)
573 assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 0
575 r = uhdev.event(0, 0, (True, None, None))
576 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
577 events = uhdev.next_sync_events()
578 self.debug_reports(r, uhdev, events)
579 self.assertInputEventsIn((syn_event, expected_event), events)
580 assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
582 r = uhdev.event(0, 0, (False, None, None))
583 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
584 events = uhdev.next_sync_events()
585 self.debug_reports(r, uhdev, events)
586 self.assertInputEventsIn((syn_event, expected_event), events)
587 assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
589 r = uhdev.event(0, 0, (True, True, None))
590 expected_event0 = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
591 expected_event1 = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
592 events = uhdev.next_sync_events()
593 self.debug_reports(r, uhdev, events)
594 self.assertInputEventsIn(
595 (syn_event, expected_event0, expected_event1), events
597 assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
598 assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
600 r = uhdev.event(0, 0, (False, None, None))
601 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
602 events = uhdev.next_sync_events()
603 self.debug_reports(r, uhdev, events)
604 self.assertInputEventsIn((syn_event, expected_event), events)
605 assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
606 assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
608 r = uhdev.event(0, 0, (None, False, None))
609 expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
610 events = uhdev.next_sync_events()
611 self.debug_reports(r, uhdev, events)
612 self.assertInputEventsIn((syn_event, expected_event), events)
613 assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
614 assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
616 def test_relative(self):
617 """Check for relative events."""
618 uhdev = self.uhdev
620 syn_event = self.syn_event
622 r = uhdev.event(0, -1)
623 expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_Y, -1)
624 events = uhdev.next_sync_events()
625 self.debug_reports(r, uhdev, events)
626 self.assertInputEvents((syn_event, expected_event), events)
628 r = uhdev.event(1, 0)
629 expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_X, 1)
630 events = uhdev.next_sync_events()
631 self.debug_reports(r, uhdev, events)
632 self.assertInputEvents((syn_event, expected_event), events)
634 r = uhdev.event(-1, 2)
635 expected_event0 = libevdev.InputEvent(libevdev.EV_REL.REL_X, -1)
636 expected_event1 = libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2)
637 events = uhdev.next_sync_events()
638 self.debug_reports(r, uhdev, events)
639 self.assertInputEvents(
640 (syn_event, expected_event0, expected_event1), events
644 class TestSimpleMouse(BaseTest.TestMouse):
645 def create_device(self):
646 return ButtonMouse()
648 def test_rdesc(self):
649 """Check that the testsuite actually manages to format the
650 reports according to the report descriptors.
651 No kernel device is used here"""
652 uhdev = self.uhdev
654 event = (0, 0, (None, None, None))
655 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
657 event = (0, 0, (None, True, None))
658 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
660 event = (0, 0, (True, True, None))
661 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
663 event = (0, 0, (False, False, False))
664 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
666 event = (1, 0, (True, False, True))
667 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
669 event = (-1, 0, (True, False, True))
670 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
672 event = (-5, 5, (True, False, True))
673 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
675 event = (-127, 127, (True, False, True))
676 assert uhdev.fake_report(*event) == uhdev.create_report(*event)
678 event = (0, -128, (True, False, True))
679 with pytest.raises(hidtools.hid.RangeError):
680 uhdev.create_report(*event)
683 class TestWheelMouse(BaseTest.TestMouse):
684 def create_device(self):
685 return WheelMouse()
687 def is_wheel_highres(self, uhdev):
688 evdev = uhdev.get_evdev()
689 assert evdev.has(libevdev.EV_REL.REL_WHEEL)
690 return evdev.has(libevdev.EV_REL.REL_WHEEL_HI_RES)
692 def test_wheel(self):
693 uhdev = self.uhdev
695 # check if the kernel is high res wheel compatible
696 high_res_wheel = self.is_wheel_highres(uhdev)
698 syn_event = self.syn_event
699 # The Resolution Multiplier is applied to the HID reports, so we
700 # need to pre-multiply too.
701 mult = uhdev.wheel_multiplier
703 r = uhdev.event(0, 0, wheels=1 * mult)
704 expected = [syn_event]
705 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
706 if high_res_wheel:
707 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120))
708 events = uhdev.next_sync_events()
709 self.debug_reports(r, uhdev, events)
710 self.assertInputEvents(expected, events)
712 r = uhdev.event(0, 0, wheels=-1 * mult)
713 expected = [syn_event]
714 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -1))
715 if high_res_wheel:
716 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120))
717 events = uhdev.next_sync_events()
718 self.debug_reports(r, uhdev, events)
719 self.assertInputEvents(expected, events)
721 r = uhdev.event(-1, 2, wheels=3 * mult)
722 expected = [syn_event]
723 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
724 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
725 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 3))
726 if high_res_wheel:
727 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 360))
728 events = uhdev.next_sync_events()
729 self.debug_reports(r, uhdev, events)
730 self.assertInputEvents(expected, events)
733 class TestTwoWheelMouse(TestWheelMouse):
734 def create_device(self):
735 return TwoWheelMouse()
737 def is_hwheel_highres(self, uhdev):
738 evdev = uhdev.get_evdev()
739 assert evdev.has(libevdev.EV_REL.REL_HWHEEL)
740 return evdev.has(libevdev.EV_REL.REL_HWHEEL_HI_RES)
742 def test_ac_pan(self):
743 uhdev = self.uhdev
745 # check if the kernel is high res wheel compatible
746 high_res_wheel = self.is_wheel_highres(uhdev)
747 high_res_hwheel = self.is_hwheel_highres(uhdev)
748 assert high_res_wheel == high_res_hwheel
750 syn_event = self.syn_event
751 # The Resolution Multiplier is applied to the HID reports, so we
752 # need to pre-multiply too.
753 hmult = uhdev.hwheel_multiplier
754 vmult = uhdev.wheel_multiplier
756 r = uhdev.event(0, 0, wheels=(0, 1 * hmult))
757 expected = [syn_event]
758 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
759 if high_res_hwheel:
760 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120))
761 events = uhdev.next_sync_events()
762 self.debug_reports(r, uhdev, events)
763 self.assertInputEvents(expected, events)
765 r = uhdev.event(0, 0, wheels=(0, -1 * hmult))
766 expected = [syn_event]
767 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, -1))
768 if high_res_hwheel:
769 expected.append(
770 libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120)
772 events = uhdev.next_sync_events()
773 self.debug_reports(r, uhdev, events)
774 self.assertInputEvents(expected, events)
776 r = uhdev.event(-1, 2, wheels=(0, 3 * hmult))
777 expected = [syn_event]
778 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
779 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
780 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 3))
781 if high_res_hwheel:
782 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 360))
783 events = uhdev.next_sync_events()
784 self.debug_reports(r, uhdev, events)
785 self.assertInputEvents(expected, events)
787 r = uhdev.event(-1, 2, wheels=(-3 * vmult, 4 * hmult))
788 expected = [syn_event]
789 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
790 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
791 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -3))
792 if high_res_wheel:
793 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -360))
794 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 4))
795 if high_res_wheel:
796 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 480))
797 events = uhdev.next_sync_events()
798 self.debug_reports(r, uhdev, events)
799 self.assertInputEvents(expected, events)
802 class TestResolutionMultiplierMouse(TestTwoWheelMouse):
803 def create_device(self):
804 return ResolutionMultiplierMouse()
806 def is_wheel_highres(self, uhdev):
807 high_res = super().is_wheel_highres(uhdev)
809 if not high_res:
810 # the kernel doesn't seem to support the high res wheel mice,
811 # make sure we haven't triggered the feature
812 assert uhdev.wheel_multiplier == 1
814 return high_res
816 def test_resolution_multiplier_wheel(self):
817 uhdev = self.uhdev
819 if not self.is_wheel_highres(uhdev):
820 pytest.skip("Kernel not compatible, we can not trigger the conditions")
822 assert uhdev.wheel_multiplier > 1
823 assert 120 % uhdev.wheel_multiplier == 0
825 def test_wheel_with_multiplier(self):
826 uhdev = self.uhdev
828 if not self.is_wheel_highres(uhdev):
829 pytest.skip("Kernel not compatible, we can not trigger the conditions")
831 assert uhdev.wheel_multiplier > 1
833 syn_event = self.syn_event
834 mult = uhdev.wheel_multiplier
836 r = uhdev.event(0, 0, wheels=1)
837 expected = [syn_event]
838 expected.append(
839 libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
841 events = uhdev.next_sync_events()
842 self.debug_reports(r, uhdev, events)
843 self.assertInputEvents(expected, events)
845 r = uhdev.event(0, 0, wheels=-1)
846 expected = [syn_event]
847 expected.append(
848 libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120 / mult)
850 events = uhdev.next_sync_events()
851 self.debug_reports(r, uhdev, events)
852 self.assertInputEvents(expected, events)
854 expected = [syn_event]
855 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
856 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
857 expected.append(
858 libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
861 for _ in range(mult - 1):
862 r = uhdev.event(1, -2, wheels=1)
863 events = uhdev.next_sync_events()
864 self.debug_reports(r, uhdev, events)
865 self.assertInputEvents(expected, events)
867 r = uhdev.event(1, -2, wheels=1)
868 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
869 events = uhdev.next_sync_events()
870 self.debug_reports(r, uhdev, events)
871 self.assertInputEvents(expected, events)
874 class TestBadResolutionMultiplierMouse(TestTwoWheelMouse):
875 def create_device(self):
876 return BadResolutionMultiplierMouse()
878 def is_wheel_highres(self, uhdev):
879 high_res = super().is_wheel_highres(uhdev)
881 assert uhdev.wheel_multiplier == 1
883 return high_res
885 def test_resolution_multiplier_wheel(self):
886 uhdev = self.uhdev
888 assert uhdev.wheel_multiplier == 1
891 class TestResolutionMultiplierHWheelMouse(TestResolutionMultiplierMouse):
892 def create_device(self):
893 return ResolutionMultiplierHWheelMouse()
895 def is_hwheel_highres(self, uhdev):
896 high_res = super().is_hwheel_highres(uhdev)
898 if not high_res:
899 # the kernel doesn't seem to support the high res wheel mice,
900 # make sure we haven't triggered the feature
901 assert uhdev.hwheel_multiplier == 1
903 return high_res
905 def test_resolution_multiplier_ac_pan(self):
906 uhdev = self.uhdev
908 if not self.is_hwheel_highres(uhdev):
909 pytest.skip("Kernel not compatible, we can not trigger the conditions")
911 assert uhdev.hwheel_multiplier > 1
912 assert 120 % uhdev.hwheel_multiplier == 0
914 def test_ac_pan_with_multiplier(self):
915 uhdev = self.uhdev
917 if not self.is_hwheel_highres(uhdev):
918 pytest.skip("Kernel not compatible, we can not trigger the conditions")
920 assert uhdev.hwheel_multiplier > 1
922 syn_event = self.syn_event
923 hmult = uhdev.hwheel_multiplier
925 r = uhdev.event(0, 0, wheels=(0, 1))
926 expected = [syn_event]
927 expected.append(
928 libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
930 events = uhdev.next_sync_events()
931 self.debug_reports(r, uhdev, events)
932 self.assertInputEvents(expected, events)
934 r = uhdev.event(0, 0, wheels=(0, -1))
935 expected = [syn_event]
936 expected.append(
937 libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120 / hmult)
939 events = uhdev.next_sync_events()
940 self.debug_reports(r, uhdev, events)
941 self.assertInputEvents(expected, events)
943 expected = [syn_event]
944 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
945 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
946 expected.append(
947 libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
950 for _ in range(hmult - 1):
951 r = uhdev.event(1, -2, wheels=(0, 1))
952 events = uhdev.next_sync_events()
953 self.debug_reports(r, uhdev, events)
954 self.assertInputEvents(expected, events)
956 r = uhdev.event(1, -2, wheels=(0, 1))
957 expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
958 events = uhdev.next_sync_events()
959 self.debug_reports(r, uhdev, events)
960 self.assertInputEvents(expected, events)
963 class TestMiMouse(TestWheelMouse):
964 def create_device(self):
965 return MIDongleMIWirelessMouse()
967 def assertInputEvents(self, expected_events, effective_events):
968 # Buttons and x/y are spread over two HID reports, so we can get two
969 # event frames for this device.
970 remaining = self.assertInputEventsIn(expected_events, effective_events)
971 try:
972 remaining.remove(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT, 0))
973 except ValueError:
974 # If there's no SYN_REPORT in the list, continue and let the
975 # assert below print out the real error
976 pass
977 assert remaining == []