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.
11 from hidtools
.util
import BusType
16 logger
= logging
.getLogger("hidtools.test.mouse")
18 # workaround https://gitlab.freedesktop.org/libevdev/python-libevdev/issues/6
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):
30 class MouseData(object):
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
)
42 def create_report(self
, x
, y
, buttons
=None, wheels
=None, reportID
=None):
44 Return an input report for this device.
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
52 :param reportID: the numeric report ID for this report, if needed
54 if buttons
is not None:
55 left
, right
, middle
= buttons
60 if middle
is not None:
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.
69 if wheels
is not None:
70 if isinstance(wheels
, tuple):
76 reportID
= reportID
or self
.default_reportID
81 mouse
.b3
= int(middle
)
86 return super().create_report(mouse
, reportID
=reportID
)
88 def event(self
, x
, y
, buttons
=None, wheels
=None):
90 Send an input event on the default report ID.
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
99 r
= self
.create_report(x
, y
, buttons
, wheels
)
100 self
.call_input_event(r
)
104 class ButtonMouse(BaseMouse
):
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
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
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
):
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
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
):
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
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
):
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
323 device_input_info
= (BusType
.USB
, 0x2717, 0x003B)
324 device_name
= "uhid test MI Dongle MI Wireless Mouse"
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
335 r
= self
.create_report(x
, y
, buttons
, wheels
, reportID
=1)
336 self
.call_input_event(r
)
338 r
= self
.create_report(x
, y
, buttons
, reportID
=2)
339 self
.call_input_event(r
)
344 class ResolutionMultiplierMouse(TwoWheelMouse
):
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
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}")
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
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
442 class ResolutionMultiplierHWheelMouse(TwoWheelMouse
):
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
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
540 class TestMouse(base
.BaseTestCase
.TestUhid
):
541 def test_buttons(self
):
542 """check for button reliability."""
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."""
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
):
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"""
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
):
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
):
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))
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))
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))
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
):
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))
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))
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))
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))
793 expected
.append(libevdev
.InputEvent(libevdev
.EV_REL
.REL_WHEEL_HI_RES
, -360))
794 expected
.append(libevdev
.InputEvent(libevdev
.EV_REL
.REL_HWHEEL
, 4))
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
)
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
816 def test_resolution_multiplier_wheel(self
):
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
):
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
]
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
]
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))
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
885 def test_resolution_multiplier_wheel(self
):
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
)
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
905 def test_resolution_multiplier_ac_pan(self
):
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
):
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
]
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
]
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))
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
)
972 remaining
.remove(libevdev
.InputEvent(libevdev
.EV_SYN
.SYN_REPORT
, 0))
974 # If there's no SYN_REPORT in the list, continue and let the
975 # assert below print out the real error
977 assert remaining
== []