xref: /linux/tools/testing/selftests/hid/tests/test_mouse.py (revision f61389a9cd26b424485acade726ccfff96c749de)
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
9from . import base
10import hidtools.hid
11from hidtools.util import BusType
12import libevdev
13import logging
14import pytest
15
16logger = logging.getLogger("hidtools.test.mouse")
17
18# workaround https://gitlab.freedesktop.org/libevdev/python-libevdev/issues/6
19try:
20    libevdev.EV_REL.REL_WHEEL_HI_RES
21except 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
26class InvalidHIDCommunication(Exception):
27    pass
28
29
30class MouseData(object):
31    pass
32
33
34class 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
104class 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
164class 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
207class 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
251class 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
344class 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
433class 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
442class BadReportDescriptorMouse(BaseMouse):
443    """
444    This "device" was one autogenerated by syzbot. There are a lot of issues in
445    it, and the most problematic is that it declares features that have no
446    size.
447
448    This leads to report->size being set to 0 and can mess up with usbhid
449    internals.  Fortunately, uhid merely passes the incoming buffer, without
450    touching it so a buffer of size 0 will be translated to [] without
451    triggering a kernel oops.
452
453    Because the report descriptor is wrong, no input are created, and we need
454    to tweak a little bit the parameters to make it look correct.
455    """
456
457    # fmt: off
458    report_descriptor = [
459        0x96, 0x01, 0x00,              # Report Count (1)                    0
460        0x06, 0x01, 0x00,              # Usage Page (Generic Desktop)        3
461        # 0x03, 0x00, 0x00, 0x00, 0x00,  # Ignored by the kernel somehow
462        0x2a, 0x90, 0xa0,              # Usage Maximum (41104)               6
463        0x27, 0x00, 0x00, 0x00, 0x00,  # Logical Maximum (0)                 9
464        0xb3, 0x81, 0x3e, 0x25, 0x03,  # Feature (Cnst,Arr,Abs,Vol)          14
465        0x1b, 0xdd, 0xe8, 0x40, 0x50,  # Usage Minimum (1346431197)          19
466        0x3b, 0x5d, 0x8c, 0x3d, 0xda,  # Designator Index                    24
467    ]
468    # fmt: on
469
470    def __init__(
471        self, rdesc=report_descriptor, name=None, input_info=(3, 0x045E, 0x07DA)
472    ):
473        super().__init__(rdesc, name, input_info)
474        self.high_resolution_report_called = False
475
476    def get_evdev(self, application=None):
477        assert self._input_nodes is None
478        return (
479            "Ok"  # should be a list or None, but both would fail, so abusing the system
480        )
481
482    def next_sync_events(self, application=None):
483        # there are no evdev nodes, so no events
484        return []
485
486    def is_ready(self):
487        # we wait for the SET_REPORT command to come
488        return self.high_resolution_report_called
489
490    def set_report(self, req, rnum, rtype, data):
491        if rtype != self.UHID_FEATURE_REPORT:
492            raise InvalidHIDCommunication(f"Unexpected report type: {rtype}")
493        if rnum != 0x0:
494            raise InvalidHIDCommunication(f"Unexpected report number: {rnum}")
495
496        if len(data) != 1:
497            raise InvalidHIDCommunication(f"Unexpected data: {data}, expected '[0]'")
498
499        self.high_resolution_report_called = True
500
501        return 0
502
503
504class ResolutionMultiplierHWheelMouse(TwoWheelMouse):
505    # fmt: off
506    report_descriptor = [
507        0x05, 0x01,         # Usage Page (Generic Desktop)        0
508        0x09, 0x02,         # Usage (Mouse)                       2
509        0xa1, 0x01,         # Collection (Application)            4
510        0x05, 0x01,         # .Usage Page (Generic Desktop)       6
511        0x09, 0x02,         # .Usage (Mouse)                      8
512        0xa1, 0x02,         # .Collection (Logical)               10
513        0x85, 0x1a,         # ..Report ID (26)                    12
514        0x09, 0x01,         # ..Usage (Pointer)                   14
515        0xa1, 0x00,         # ..Collection (Physical)             16
516        0x05, 0x09,         # ...Usage Page (Button)              18
517        0x19, 0x01,         # ...Usage Minimum (1)                20
518        0x29, 0x05,         # ...Usage Maximum (5)                22
519        0x95, 0x05,         # ...Report Count (5)                 24
520        0x75, 0x01,         # ...Report Size (1)                  26
521        0x15, 0x00,         # ...Logical Minimum (0)              28
522        0x25, 0x01,         # ...Logical Maximum (1)              30
523        0x81, 0x02,         # ...Input (Data,Var,Abs)             32
524        0x75, 0x03,         # ...Report Size (3)                  34
525        0x95, 0x01,         # ...Report Count (1)                 36
526        0x81, 0x01,         # ...Input (Cnst,Arr,Abs)             38
527        0x05, 0x01,         # ...Usage Page (Generic Desktop)     40
528        0x09, 0x30,         # ...Usage (X)                        42
529        0x09, 0x31,         # ...Usage (Y)                        44
530        0x95, 0x02,         # ...Report Count (2)                 46
531        0x75, 0x10,         # ...Report Size (16)                 48
532        0x16, 0x01, 0x80,   # ...Logical Minimum (-32767)         50
533        0x26, 0xff, 0x7f,   # ...Logical Maximum (32767)          53
534        0x81, 0x06,         # ...Input (Data,Var,Rel)             56
535        0xa1, 0x02,         # ...Collection (Logical)             58
536        0x85, 0x12,         # ....Report ID (18)                  60
537        0x09, 0x48,         # ....Usage (Resolution Multiplier)   62
538        0x95, 0x01,         # ....Report Count (1)                64
539        0x75, 0x02,         # ....Report Size (2)                 66
540        0x15, 0x00,         # ....Logical Minimum (0)             68
541        0x25, 0x01,         # ....Logical Maximum (1)             70
542        0x35, 0x01,         # ....Physical Minimum (1)            72
543        0x45, 0x0c,         # ....Physical Maximum (12)           74
544        0xb1, 0x02,         # ....Feature (Data,Var,Abs)          76
545        0x85, 0x1a,         # ....Report ID (26)                  78
546        0x09, 0x38,         # ....Usage (Wheel)                   80
547        0x35, 0x00,         # ....Physical Minimum (0)            82
548        0x45, 0x00,         # ....Physical Maximum (0)            84
549        0x95, 0x01,         # ....Report Count (1)                86
550        0x75, 0x10,         # ....Report Size (16)                88
551        0x16, 0x01, 0x80,   # ....Logical Minimum (-32767)        90
552        0x26, 0xff, 0x7f,   # ....Logical Maximum (32767)         93
553        0x81, 0x06,         # ....Input (Data,Var,Rel)            96
554        0xc0,               # ...End Collection                   98
555        0xa1, 0x02,         # ...Collection (Logical)             99
556        0x85, 0x12,         # ....Report ID (18)                  101
557        0x09, 0x48,         # ....Usage (Resolution Multiplier)   103
558        0x75, 0x02,         # ....Report Size (2)                 105
559        0x15, 0x00,         # ....Logical Minimum (0)             107
560        0x25, 0x01,         # ....Logical Maximum (1)             109
561        0x35, 0x01,         # ....Physical Minimum (1)            111
562        0x45, 0x0c,         # ....Physical Maximum (12)           113
563        0xb1, 0x02,         # ....Feature (Data,Var,Abs)          115
564        0x35, 0x00,         # ....Physical Minimum (0)            117
565        0x45, 0x00,         # ....Physical Maximum (0)            119
566        0x75, 0x04,         # ....Report Size (4)                 121
567        0xb1, 0x01,         # ....Feature (Cnst,Arr,Abs)          123
568        0x85, 0x1a,         # ....Report ID (26)                  125
569        0x05, 0x0c,         # ....Usage Page (Consumer Devices)   127
570        0x95, 0x01,         # ....Report Count (1)                129
571        0x75, 0x10,         # ....Report Size (16)                131
572        0x16, 0x01, 0x80,   # ....Logical Minimum (-32767)        133
573        0x26, 0xff, 0x7f,   # ....Logical Maximum (32767)         136
574        0x0a, 0x38, 0x02,   # ....Usage (AC Pan)                  139
575        0x81, 0x06,         # ....Input (Data,Var,Rel)            142
576        0xc0,               # ...End Collection                   144
577        0xc0,               # ..End Collection                    145
578        0xc0,               # .End Collection                     146
579        0xc0,               # End Collection                      147
580    ]
581    # fmt: on
582
583    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
584        super().__init__(rdesc, name, input_info)
585        self.default_reportID = 0x1A
586
587        # Feature Report 12, multiplier Feature value must be set to 0b0101,
588        # i.e. 5. We should extract that from the descriptor instead
589        # of hardcoding it here, but meanwhile this will do.
590        self.set_feature_report = [0x12, 0x5]
591
592    def set_report(self, req, rnum, rtype, data):
593        super().set_report(req, rnum, rtype, data)
594
595        self.wheel_multiplier = 12
596        self.hwheel_multiplier = 12
597
598        return 0
599
600
601class BaseTest:
602    class TestMouse(base.BaseTestCase.TestUhid):
603        def test_buttons(self):
604            """check for button reliability."""
605            uhdev = self.uhdev
606            evdev = uhdev.get_evdev()
607            syn_event = self.syn_event
608
609            r = uhdev.event(0, 0, (None, True, None))
610            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
611            events = uhdev.next_sync_events()
612            self.debug_reports(r, uhdev, events)
613            self.assertInputEventsIn((syn_event, expected_event), events)
614            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
615
616            r = uhdev.event(0, 0, (None, False, None))
617            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
618            events = uhdev.next_sync_events()
619            self.debug_reports(r, uhdev, events)
620            self.assertInputEventsIn((syn_event, expected_event), events)
621            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
622
623            r = uhdev.event(0, 0, (None, None, True))
624            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 1)
625            events = uhdev.next_sync_events()
626            self.debug_reports(r, uhdev, events)
627            self.assertInputEventsIn((syn_event, expected_event), events)
628            assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 1
629
630            r = uhdev.event(0, 0, (None, None, False))
631            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 0)
632            events = uhdev.next_sync_events()
633            self.debug_reports(r, uhdev, events)
634            self.assertInputEventsIn((syn_event, expected_event), events)
635            assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 0
636
637            r = uhdev.event(0, 0, (True, None, None))
638            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
639            events = uhdev.next_sync_events()
640            self.debug_reports(r, uhdev, events)
641            self.assertInputEventsIn((syn_event, expected_event), events)
642            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
643
644            r = uhdev.event(0, 0, (False, None, None))
645            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
646            events = uhdev.next_sync_events()
647            self.debug_reports(r, uhdev, events)
648            self.assertInputEventsIn((syn_event, expected_event), events)
649            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
650
651            r = uhdev.event(0, 0, (True, True, None))
652            expected_event0 = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
653            expected_event1 = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
654            events = uhdev.next_sync_events()
655            self.debug_reports(r, uhdev, events)
656            self.assertInputEventsIn(
657                (syn_event, expected_event0, expected_event1), events
658            )
659            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
660            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
661
662            r = uhdev.event(0, 0, (False, None, None))
663            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
664            events = uhdev.next_sync_events()
665            self.debug_reports(r, uhdev, events)
666            self.assertInputEventsIn((syn_event, expected_event), events)
667            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
668            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
669
670            r = uhdev.event(0, 0, (None, False, None))
671            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
672            events = uhdev.next_sync_events()
673            self.debug_reports(r, uhdev, events)
674            self.assertInputEventsIn((syn_event, expected_event), events)
675            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
676            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
677
678        def test_relative(self):
679            """Check for relative events."""
680            uhdev = self.uhdev
681
682            syn_event = self.syn_event
683
684            r = uhdev.event(0, -1)
685            expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_Y, -1)
686            events = uhdev.next_sync_events()
687            self.debug_reports(r, uhdev, events)
688            self.assertInputEvents((syn_event, expected_event), events)
689
690            r = uhdev.event(1, 0)
691            expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_X, 1)
692            events = uhdev.next_sync_events()
693            self.debug_reports(r, uhdev, events)
694            self.assertInputEvents((syn_event, expected_event), events)
695
696            r = uhdev.event(-1, 2)
697            expected_event0 = libevdev.InputEvent(libevdev.EV_REL.REL_X, -1)
698            expected_event1 = libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2)
699            events = uhdev.next_sync_events()
700            self.debug_reports(r, uhdev, events)
701            self.assertInputEvents(
702                (syn_event, expected_event0, expected_event1), events
703            )
704
705
706class TestSimpleMouse(BaseTest.TestMouse):
707    def create_device(self):
708        return ButtonMouse()
709
710    def test_rdesc(self):
711        """Check that the testsuite actually manages to format the
712        reports according to the report descriptors.
713        No kernel device is used here"""
714        uhdev = self.uhdev
715
716        event = (0, 0, (None, None, None))
717        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
718
719        event = (0, 0, (None, True, None))
720        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
721
722        event = (0, 0, (True, True, None))
723        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
724
725        event = (0, 0, (False, False, False))
726        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
727
728        event = (1, 0, (True, False, True))
729        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
730
731        event = (-1, 0, (True, False, True))
732        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
733
734        event = (-5, 5, (True, False, True))
735        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
736
737        event = (-127, 127, (True, False, True))
738        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
739
740        event = (0, -128, (True, False, True))
741        with pytest.raises(hidtools.hid.RangeError):
742            uhdev.create_report(*event)
743
744
745class TestWheelMouse(BaseTest.TestMouse):
746    def create_device(self):
747        return WheelMouse()
748
749    def is_wheel_highres(self, uhdev):
750        evdev = uhdev.get_evdev()
751        assert evdev.has(libevdev.EV_REL.REL_WHEEL)
752        return evdev.has(libevdev.EV_REL.REL_WHEEL_HI_RES)
753
754    def test_wheel(self):
755        uhdev = self.uhdev
756
757        # check if the kernel is high res wheel compatible
758        high_res_wheel = self.is_wheel_highres(uhdev)
759
760        syn_event = self.syn_event
761        # The Resolution Multiplier is applied to the HID reports, so we
762        # need to pre-multiply too.
763        mult = uhdev.wheel_multiplier
764
765        r = uhdev.event(0, 0, wheels=1 * mult)
766        expected = [syn_event]
767        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
768        if high_res_wheel:
769            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120))
770        events = uhdev.next_sync_events()
771        self.debug_reports(r, uhdev, events)
772        self.assertInputEvents(expected, events)
773
774        r = uhdev.event(0, 0, wheels=-1 * mult)
775        expected = [syn_event]
776        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -1))
777        if high_res_wheel:
778            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120))
779        events = uhdev.next_sync_events()
780        self.debug_reports(r, uhdev, events)
781        self.assertInputEvents(expected, events)
782
783        r = uhdev.event(-1, 2, wheels=3 * mult)
784        expected = [syn_event]
785        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
786        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
787        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 3))
788        if high_res_wheel:
789            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 360))
790        events = uhdev.next_sync_events()
791        self.debug_reports(r, uhdev, events)
792        self.assertInputEvents(expected, events)
793
794
795class TestTwoWheelMouse(TestWheelMouse):
796    def create_device(self):
797        return TwoWheelMouse()
798
799    def is_hwheel_highres(self, uhdev):
800        evdev = uhdev.get_evdev()
801        assert evdev.has(libevdev.EV_REL.REL_HWHEEL)
802        return evdev.has(libevdev.EV_REL.REL_HWHEEL_HI_RES)
803
804    def test_ac_pan(self):
805        uhdev = self.uhdev
806
807        # check if the kernel is high res wheel compatible
808        high_res_wheel = self.is_wheel_highres(uhdev)
809        high_res_hwheel = self.is_hwheel_highres(uhdev)
810        assert high_res_wheel == high_res_hwheel
811
812        syn_event = self.syn_event
813        # The Resolution Multiplier is applied to the HID reports, so we
814        # need to pre-multiply too.
815        hmult = uhdev.hwheel_multiplier
816        vmult = uhdev.wheel_multiplier
817
818        r = uhdev.event(0, 0, wheels=(0, 1 * hmult))
819        expected = [syn_event]
820        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
821        if high_res_hwheel:
822            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120))
823        events = uhdev.next_sync_events()
824        self.debug_reports(r, uhdev, events)
825        self.assertInputEvents(expected, events)
826
827        r = uhdev.event(0, 0, wheels=(0, -1 * hmult))
828        expected = [syn_event]
829        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, -1))
830        if high_res_hwheel:
831            expected.append(
832                libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120)
833            )
834        events = uhdev.next_sync_events()
835        self.debug_reports(r, uhdev, events)
836        self.assertInputEvents(expected, events)
837
838        r = uhdev.event(-1, 2, wheels=(0, 3 * hmult))
839        expected = [syn_event]
840        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
841        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
842        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 3))
843        if high_res_hwheel:
844            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 360))
845        events = uhdev.next_sync_events()
846        self.debug_reports(r, uhdev, events)
847        self.assertInputEvents(expected, events)
848
849        r = uhdev.event(-1, 2, wheels=(-3 * vmult, 4 * hmult))
850        expected = [syn_event]
851        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
852        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
853        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -3))
854        if high_res_wheel:
855            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -360))
856        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 4))
857        if high_res_wheel:
858            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 480))
859        events = uhdev.next_sync_events()
860        self.debug_reports(r, uhdev, events)
861        self.assertInputEvents(expected, events)
862
863
864class TestResolutionMultiplierMouse(TestTwoWheelMouse):
865    def create_device(self):
866        return ResolutionMultiplierMouse()
867
868    def is_wheel_highres(self, uhdev):
869        high_res = super().is_wheel_highres(uhdev)
870
871        if not high_res:
872            # the kernel doesn't seem to support the high res wheel mice,
873            # make sure we haven't triggered the feature
874            assert uhdev.wheel_multiplier == 1
875
876        return high_res
877
878    def test_resolution_multiplier_wheel(self):
879        uhdev = self.uhdev
880
881        if not self.is_wheel_highres(uhdev):
882            pytest.skip("Kernel not compatible, we can not trigger the conditions")
883
884        assert uhdev.wheel_multiplier > 1
885        assert 120 % uhdev.wheel_multiplier == 0
886
887    def test_wheel_with_multiplier(self):
888        uhdev = self.uhdev
889
890        if not self.is_wheel_highres(uhdev):
891            pytest.skip("Kernel not compatible, we can not trigger the conditions")
892
893        assert uhdev.wheel_multiplier > 1
894
895        syn_event = self.syn_event
896        mult = uhdev.wheel_multiplier
897
898        r = uhdev.event(0, 0, wheels=1)
899        expected = [syn_event]
900        expected.append(
901            libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
902        )
903        events = uhdev.next_sync_events()
904        self.debug_reports(r, uhdev, events)
905        self.assertInputEvents(expected, events)
906
907        r = uhdev.event(0, 0, wheels=-1)
908        expected = [syn_event]
909        expected.append(
910            libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120 / mult)
911        )
912        events = uhdev.next_sync_events()
913        self.debug_reports(r, uhdev, events)
914        self.assertInputEvents(expected, events)
915
916        expected = [syn_event]
917        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
918        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
919        expected.append(
920            libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
921        )
922
923        for _ in range(mult - 1):
924            r = uhdev.event(1, -2, wheels=1)
925            events = uhdev.next_sync_events()
926            self.debug_reports(r, uhdev, events)
927            self.assertInputEvents(expected, events)
928
929        r = uhdev.event(1, -2, wheels=1)
930        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
931        events = uhdev.next_sync_events()
932        self.debug_reports(r, uhdev, events)
933        self.assertInputEvents(expected, events)
934
935
936class TestBadResolutionMultiplierMouse(TestTwoWheelMouse):
937    def create_device(self):
938        return BadResolutionMultiplierMouse()
939
940    def is_wheel_highres(self, uhdev):
941        high_res = super().is_wheel_highres(uhdev)
942
943        assert uhdev.wheel_multiplier == 1
944
945        return high_res
946
947    def test_resolution_multiplier_wheel(self):
948        uhdev = self.uhdev
949
950        assert uhdev.wheel_multiplier == 1
951
952
953class TestResolutionMultiplierHWheelMouse(TestResolutionMultiplierMouse):
954    def create_device(self):
955        return ResolutionMultiplierHWheelMouse()
956
957    def is_hwheel_highres(self, uhdev):
958        high_res = super().is_hwheel_highres(uhdev)
959
960        if not high_res:
961            # the kernel doesn't seem to support the high res wheel mice,
962            # make sure we haven't triggered the feature
963            assert uhdev.hwheel_multiplier == 1
964
965        return high_res
966
967    def test_resolution_multiplier_ac_pan(self):
968        uhdev = self.uhdev
969
970        if not self.is_hwheel_highres(uhdev):
971            pytest.skip("Kernel not compatible, we can not trigger the conditions")
972
973        assert uhdev.hwheel_multiplier > 1
974        assert 120 % uhdev.hwheel_multiplier == 0
975
976    def test_ac_pan_with_multiplier(self):
977        uhdev = self.uhdev
978
979        if not self.is_hwheel_highres(uhdev):
980            pytest.skip("Kernel not compatible, we can not trigger the conditions")
981
982        assert uhdev.hwheel_multiplier > 1
983
984        syn_event = self.syn_event
985        hmult = uhdev.hwheel_multiplier
986
987        r = uhdev.event(0, 0, wheels=(0, 1))
988        expected = [syn_event]
989        expected.append(
990            libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
991        )
992        events = uhdev.next_sync_events()
993        self.debug_reports(r, uhdev, events)
994        self.assertInputEvents(expected, events)
995
996        r = uhdev.event(0, 0, wheels=(0, -1))
997        expected = [syn_event]
998        expected.append(
999            libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120 / hmult)
1000        )
1001        events = uhdev.next_sync_events()
1002        self.debug_reports(r, uhdev, events)
1003        self.assertInputEvents(expected, events)
1004
1005        expected = [syn_event]
1006        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
1007        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
1008        expected.append(
1009            libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
1010        )
1011
1012        for _ in range(hmult - 1):
1013            r = uhdev.event(1, -2, wheels=(0, 1))
1014            events = uhdev.next_sync_events()
1015            self.debug_reports(r, uhdev, events)
1016            self.assertInputEvents(expected, events)
1017
1018        r = uhdev.event(1, -2, wheels=(0, 1))
1019        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
1020        events = uhdev.next_sync_events()
1021        self.debug_reports(r, uhdev, events)
1022        self.assertInputEvents(expected, events)
1023
1024
1025class TestMiMouse(TestWheelMouse):
1026    def create_device(self):
1027        return MIDongleMIWirelessMouse()
1028
1029    def assertInputEvents(self, expected_events, effective_events):
1030        # Buttons and x/y are spread over two HID reports, so we can get two
1031        # event frames for this device.
1032        remaining = self.assertInputEventsIn(expected_events, effective_events)
1033        try:
1034            remaining.remove(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT, 0))
1035        except ValueError:
1036            # If there's no SYN_REPORT in the list, continue and let the
1037            # assert below print out the real error
1038            pass
1039        assert remaining == []
1040
1041
1042class TestBadReportDescriptorMouse(base.BaseTestCase.TestUhid):
1043    def create_device(self):
1044        return BadReportDescriptorMouse()
1045
1046    def assertName(self, uhdev):
1047        pass
1048