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

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

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

  1 #!/bin/env python3
  2 # SPDX-License-Identifier: GPL-2.0
  3 # -*- coding: utf-8 -*-
  4 #
  5 # Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
  6 # Copyright (c) 2017 Red Hat, Inc.
  7 #
  8 
  9 from . import base
 10 import hidtools.hid
 11 from hidtools.util import BusType
 12 import libevdev
 13 import logging
 14 import pytest
 15 
 16 logger = logging.getLogger("hidtools.test.mouse")
 17 
 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
 24 
 25 
 26 class InvalidHIDCommunication(Exception):
 27     pass
 28 
 29 
 30 class MouseData(object):
 31     pass
 32 
 33 
 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
 41 
 42     def create_report(self, x, y, buttons=None, wheels=None, reportID=None):
 43         """
 44         Return an input report for this device.
 45 
 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
 75 
 76         reportID = reportID or self.default_reportID
 77 
 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)
 87 
 88     def event(self, x, y, buttons=None, wheels=None):
 89         """
 90         Send an input event on the default report ID.
 91 
 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]
102 
103 
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
136     ]
137     # fmt: on
138 
139     def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
140         super().__init__(rdesc, name, input_info)
141 
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
155 
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]
162 
163 
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
199     ]
200     # fmt: on
201 
202     def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
203         super().__init__(rdesc, name, input_info)
204         self.wheel_multiplier = 1
205 
206 
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
243     ]
244     # fmt: on
245 
246     def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
247         super().__init__(rdesc, name, input_info)
248         self.hwheel_multiplier = 1
249 
250 
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
321     ]
322     # fmt: on
323     device_input_info = (BusType.USB, 0x2717, 0x003B)
324     device_name = "uhid test MI Dongle MI Wireless Mouse"
325 
326     def __init__(
327         self, rdesc=report_descriptor, name=device_name, input_info=device_input_info
328     ):
329         super().__init__(rdesc, name, input_info)
330 
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
342 
343 
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
405     ]
406     # fmt: on
407 
408     def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
409         super().__init__(rdesc, name, input_info)
410         self.default_reportID = 0x11
411 
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]
416 
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}")
422 
423         if data != self.set_feature_report:
424             raise InvalidHIDCommunication(
425                 f"Unexpected data: {data}, expected {self.set_feature_report}"
426             )
427 
428         self.wheel_multiplier = 4
429 
430         return 0
431 
432 
433 class BadResolutionMultiplierMouse(ResolutionMultiplierMouse):
434     def set_report(self, req, rnum, rtype, data):
435         super().set_report(req, rnum, rtype, data)
436 
437         self.wheel_multiplier = 1
438         self.hwheel_multiplier = 1
439         return 32  # EPIPE
440 
441 
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
518     ]
519     # fmt: on
520 
521     def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
522         super().__init__(rdesc, name, input_info)
523         self.default_reportID = 0x1A
524 
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]
529 
530     def set_report(self, req, rnum, rtype, data):
531         super().set_report(req, rnum, rtype, data)
532 
533         self.wheel_multiplier = 12
534         self.hwheel_multiplier = 12
535 
536         return 0
537 
538 
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
546 
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
553 
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
560 
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
567 
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
574 
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
581 
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
588 
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
596             )
597             assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
598             assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
599 
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
607 
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
615 
616         def test_relative(self):
617             """Check for relative events."""
618             uhdev = self.uhdev
619 
620             syn_event = self.syn_event
621 
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)
627 
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)
633 
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
641             )
642 
643 
644 class TestSimpleMouse(BaseTest.TestMouse):
645     def create_device(self):
646         return ButtonMouse()
647 
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
653 
654         event = (0, 0, (None, None, None))
655         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
656 
657         event = (0, 0, (None, True, None))
658         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
659 
660         event = (0, 0, (True, True, None))
661         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
662 
663         event = (0, 0, (False, False, False))
664         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
665 
666         event = (1, 0, (True, False, True))
667         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
668 
669         event = (-1, 0, (True, False, True))
670         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
671 
672         event = (-5, 5, (True, False, True))
673         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
674 
675         event = (-127, 127, (True, False, True))
676         assert uhdev.fake_report(*event) == uhdev.create_report(*event)
677 
678         event = (0, -128, (True, False, True))
679         with pytest.raises(hidtools.hid.RangeError):
680             uhdev.create_report(*event)
681 
682 
683 class TestWheelMouse(BaseTest.TestMouse):
684     def create_device(self):
685         return WheelMouse()
686 
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)
691 
692     def test_wheel(self):
693         uhdev = self.uhdev
694 
695         # check if the kernel is high res wheel compatible
696         high_res_wheel = self.is_wheel_highres(uhdev)
697 
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
702 
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)
711 
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)
720 
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)
731 
732 
733 class TestTwoWheelMouse(TestWheelMouse):
734     def create_device(self):
735         return TwoWheelMouse()
736 
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)
741 
742     def test_ac_pan(self):
743         uhdev = self.uhdev
744 
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
749 
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
755 
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)
764 
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)
771             )
772         events = uhdev.next_sync_events()
773         self.debug_reports(r, uhdev, events)
774         self.assertInputEvents(expected, events)
775 
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)
786 
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)
800 
801 
802 class TestResolutionMultiplierMouse(TestTwoWheelMouse):
803     def create_device(self):
804         return ResolutionMultiplierMouse()
805 
806     def is_wheel_highres(self, uhdev):
807         high_res = super().is_wheel_highres(uhdev)
808 
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
813 
814         return high_res
815 
816     def test_resolution_multiplier_wheel(self):
817         uhdev = self.uhdev
818 
819         if not self.is_wheel_highres(uhdev):
820             pytest.skip("Kernel not compatible, we can not trigger the conditions")
821 
822         assert uhdev.wheel_multiplier > 1
823         assert 120 % uhdev.wheel_multiplier == 0
824 
825     def test_wheel_with_multiplier(self):
826         uhdev = self.uhdev
827 
828         if not self.is_wheel_highres(uhdev):
829             pytest.skip("Kernel not compatible, we can not trigger the conditions")
830 
831         assert uhdev.wheel_multiplier > 1
832 
833         syn_event = self.syn_event
834         mult = uhdev.wheel_multiplier
835 
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)
840         )
841         events = uhdev.next_sync_events()
842         self.debug_reports(r, uhdev, events)
843         self.assertInputEvents(expected, events)
844 
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)
849         )
850         events = uhdev.next_sync_events()
851         self.debug_reports(r, uhdev, events)
852         self.assertInputEvents(expected, events)
853 
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)
859         )
860 
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)
866 
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)
872 
873 
874 class TestBadResolutionMultiplierMouse(TestTwoWheelMouse):
875     def create_device(self):
876         return BadResolutionMultiplierMouse()
877 
878     def is_wheel_highres(self, uhdev):
879         high_res = super().is_wheel_highres(uhdev)
880 
881         assert uhdev.wheel_multiplier == 1
882 
883         return high_res
884 
885     def test_resolution_multiplier_wheel(self):
886         uhdev = self.uhdev
887 
888         assert uhdev.wheel_multiplier == 1
889 
890 
891 class TestResolutionMultiplierHWheelMouse(TestResolutionMultiplierMouse):
892     def create_device(self):
893         return ResolutionMultiplierHWheelMouse()
894 
895     def is_hwheel_highres(self, uhdev):
896         high_res = super().is_hwheel_highres(uhdev)
897 
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
902 
903         return high_res
904 
905     def test_resolution_multiplier_ac_pan(self):
906         uhdev = self.uhdev
907 
908         if not self.is_hwheel_highres(uhdev):
909             pytest.skip("Kernel not compatible, we can not trigger the conditions")
910 
911         assert uhdev.hwheel_multiplier > 1
912         assert 120 % uhdev.hwheel_multiplier == 0
913 
914     def test_ac_pan_with_multiplier(self):
915         uhdev = self.uhdev
916 
917         if not self.is_hwheel_highres(uhdev):
918             pytest.skip("Kernel not compatible, we can not trigger the conditions")
919 
920         assert uhdev.hwheel_multiplier > 1
921 
922         syn_event = self.syn_event
923         hmult = uhdev.hwheel_multiplier
924 
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)
929         )
930         events = uhdev.next_sync_events()
931         self.debug_reports(r, uhdev, events)
932         self.assertInputEvents(expected, events)
933 
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)
938         )
939         events = uhdev.next_sync_events()
940         self.debug_reports(r, uhdev, events)
941         self.assertInputEvents(expected, events)
942 
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)
948         )
949 
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)
955 
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)
961 
962 
963 class TestMiMouse(TestWheelMouse):
964     def create_device(self):
965         return MIDongleMIWirelessMouse()
966 
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 == []

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

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

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

sflogo.php