162306a36Sopenharmony_ci#!/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci# -*- coding: utf-8 -*-
462306a36Sopenharmony_ci#
562306a36Sopenharmony_ci# Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
662306a36Sopenharmony_ci# Copyright (c) 2017 Red Hat, Inc.
762306a36Sopenharmony_ci#
862306a36Sopenharmony_ci
962306a36Sopenharmony_cifrom . import base
1062306a36Sopenharmony_ciimport hidtools.hid
1162306a36Sopenharmony_cifrom hidtools.util import BusType
1262306a36Sopenharmony_ciimport libevdev
1362306a36Sopenharmony_ciimport logging
1462306a36Sopenharmony_ciimport pytest
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cilogger = logging.getLogger("hidtools.test.mouse")
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci# workaround https://gitlab.freedesktop.org/libevdev/python-libevdev/issues/6
1962306a36Sopenharmony_citry:
2062306a36Sopenharmony_ci    libevdev.EV_REL.REL_WHEEL_HI_RES
2162306a36Sopenharmony_ciexcept AttributeError:
2262306a36Sopenharmony_ci    libevdev.EV_REL.REL_WHEEL_HI_RES = libevdev.EV_REL.REL_0B
2362306a36Sopenharmony_ci    libevdev.EV_REL.REL_HWHEEL_HI_RES = libevdev.EV_REL.REL_0C
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciclass InvalidHIDCommunication(Exception):
2762306a36Sopenharmony_ci    pass
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciclass MouseData(object):
3162306a36Sopenharmony_ci    pass
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciclass BaseMouse(base.UHIDTestDevice):
3562306a36Sopenharmony_ci    def __init__(self, rdesc, name=None, input_info=None):
3662306a36Sopenharmony_ci        assert rdesc is not None
3762306a36Sopenharmony_ci        super().__init__(name, "Mouse", input_info=input_info, rdesc=rdesc)
3862306a36Sopenharmony_ci        self.left = False
3962306a36Sopenharmony_ci        self.right = False
4062306a36Sopenharmony_ci        self.middle = False
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci    def create_report(self, x, y, buttons=None, wheels=None, reportID=None):
4362306a36Sopenharmony_ci        """
4462306a36Sopenharmony_ci        Return an input report for this device.
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci        :param x: relative x
4762306a36Sopenharmony_ci        :param y: relative y
4862306a36Sopenharmony_ci        :param buttons: a (l, r, m) tuple of bools for the button states,
4962306a36Sopenharmony_ci            where ``None`` is "leave unchanged"
5062306a36Sopenharmony_ci        :param wheels: a single value for the vertical wheel or a (vertical, horizontal) tuple for
5162306a36Sopenharmony_ci            the two wheels
5262306a36Sopenharmony_ci        :param reportID: the numeric report ID for this report, if needed
5362306a36Sopenharmony_ci        """
5462306a36Sopenharmony_ci        if buttons is not None:
5562306a36Sopenharmony_ci            l, r, m = buttons
5662306a36Sopenharmony_ci            if l is not None:
5762306a36Sopenharmony_ci                self.left = l
5862306a36Sopenharmony_ci            if r is not None:
5962306a36Sopenharmony_ci                self.right = r
6062306a36Sopenharmony_ci            if m is not None:
6162306a36Sopenharmony_ci                self.middle = m
6262306a36Sopenharmony_ci        left = self.left
6362306a36Sopenharmony_ci        right = self.right
6462306a36Sopenharmony_ci        middle = self.middle
6562306a36Sopenharmony_ci        # Note: the BaseMouse doesn't actually have a wheel but the
6662306a36Sopenharmony_ci        # create_report magic only fills in those fields exist, so let's
6762306a36Sopenharmony_ci        # make this generic here.
6862306a36Sopenharmony_ci        wheel, acpan = 0, 0
6962306a36Sopenharmony_ci        if wheels is not None:
7062306a36Sopenharmony_ci            if isinstance(wheels, tuple):
7162306a36Sopenharmony_ci                wheel = wheels[0]
7262306a36Sopenharmony_ci                acpan = wheels[1]
7362306a36Sopenharmony_ci            else:
7462306a36Sopenharmony_ci                wheel = wheels
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci        reportID = reportID or self.default_reportID
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci        mouse = MouseData()
7962306a36Sopenharmony_ci        mouse.b1 = int(left)
8062306a36Sopenharmony_ci        mouse.b2 = int(right)
8162306a36Sopenharmony_ci        mouse.b3 = int(middle)
8262306a36Sopenharmony_ci        mouse.x = x
8362306a36Sopenharmony_ci        mouse.y = y
8462306a36Sopenharmony_ci        mouse.wheel = wheel
8562306a36Sopenharmony_ci        mouse.acpan = acpan
8662306a36Sopenharmony_ci        return super().create_report(mouse, reportID=reportID)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci    def event(self, x, y, buttons=None, wheels=None):
8962306a36Sopenharmony_ci        """
9062306a36Sopenharmony_ci        Send an input event on the default report ID.
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci        :param x: relative x
9362306a36Sopenharmony_ci        :param y: relative y
9462306a36Sopenharmony_ci        :param buttons: a (l, r, m) tuple of bools for the button states,
9562306a36Sopenharmony_ci            where ``None`` is "leave unchanged"
9662306a36Sopenharmony_ci        :param wheels: a single value for the vertical wheel or a (vertical, horizontal) tuple for
9762306a36Sopenharmony_ci            the two wheels
9862306a36Sopenharmony_ci        """
9962306a36Sopenharmony_ci        r = self.create_report(x, y, buttons, wheels)
10062306a36Sopenharmony_ci        self.call_input_event(r)
10162306a36Sopenharmony_ci        return [r]
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciclass ButtonMouse(BaseMouse):
10562306a36Sopenharmony_ci    # fmt: off
10662306a36Sopenharmony_ci    report_descriptor = [
10762306a36Sopenharmony_ci        0x05, 0x01,  # .Usage Page (Generic Desktop)        0
10862306a36Sopenharmony_ci        0x09, 0x02,  # .Usage (Mouse)                       2
10962306a36Sopenharmony_ci        0xa1, 0x01,  # .Collection (Application)            4
11062306a36Sopenharmony_ci        0x09, 0x02,  # ..Usage (Mouse)                      6
11162306a36Sopenharmony_ci        0xa1, 0x02,  # ..Collection (Logical)               8
11262306a36Sopenharmony_ci        0x09, 0x01,  # ...Usage (Pointer)                   10
11362306a36Sopenharmony_ci        0xa1, 0x00,  # ...Collection (Physical)             12
11462306a36Sopenharmony_ci        0x05, 0x09,  # ....Usage Page (Button)              14
11562306a36Sopenharmony_ci        0x19, 0x01,  # ....Usage Minimum (1)                16
11662306a36Sopenharmony_ci        0x29, 0x03,  # ....Usage Maximum (3)                18
11762306a36Sopenharmony_ci        0x15, 0x00,  # ....Logical Minimum (0)              20
11862306a36Sopenharmony_ci        0x25, 0x01,  # ....Logical Maximum (1)              22
11962306a36Sopenharmony_ci        0x75, 0x01,  # ....Report Size (1)                  24
12062306a36Sopenharmony_ci        0x95, 0x03,  # ....Report Count (3)                 26
12162306a36Sopenharmony_ci        0x81, 0x02,  # ....Input (Data,Var,Abs)             28
12262306a36Sopenharmony_ci        0x75, 0x05,  # ....Report Size (5)                  30
12362306a36Sopenharmony_ci        0x95, 0x01,  # ....Report Count (1)                 32
12462306a36Sopenharmony_ci        0x81, 0x03,  # ....Input (Cnst,Var,Abs)             34
12562306a36Sopenharmony_ci        0x05, 0x01,  # ....Usage Page (Generic Desktop)     36
12662306a36Sopenharmony_ci        0x09, 0x30,  # ....Usage (X)                        38
12762306a36Sopenharmony_ci        0x09, 0x31,  # ....Usage (Y)                        40
12862306a36Sopenharmony_ci        0x15, 0x81,  # ....Logical Minimum (-127)           42
12962306a36Sopenharmony_ci        0x25, 0x7f,  # ....Logical Maximum (127)            44
13062306a36Sopenharmony_ci        0x75, 0x08,  # ....Report Size (8)                  46
13162306a36Sopenharmony_ci        0x95, 0x02,  # ....Report Count (2)                 48
13262306a36Sopenharmony_ci        0x81, 0x06,  # ....Input (Data,Var,Rel)             50
13362306a36Sopenharmony_ci        0xc0,        # ...End Collection                    52
13462306a36Sopenharmony_ci        0xc0,        # ..End Collection                     53
13562306a36Sopenharmony_ci        0xc0,        # .End Collection                      54
13662306a36Sopenharmony_ci    ]
13762306a36Sopenharmony_ci    # fmt: on
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
14062306a36Sopenharmony_ci        super().__init__(rdesc, name, input_info)
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci    def fake_report(self, x, y, buttons):
14362306a36Sopenharmony_ci        if buttons is not None:
14462306a36Sopenharmony_ci            left, right, middle = buttons
14562306a36Sopenharmony_ci            if left is None:
14662306a36Sopenharmony_ci                left = self.left
14762306a36Sopenharmony_ci            if right is None:
14862306a36Sopenharmony_ci                right = self.right
14962306a36Sopenharmony_ci            if middle is None:
15062306a36Sopenharmony_ci                middle = self.middle
15162306a36Sopenharmony_ci        else:
15262306a36Sopenharmony_ci            left = self.left
15362306a36Sopenharmony_ci            right = self.right
15462306a36Sopenharmony_ci            middle = self.middle
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci        button_mask = sum(1 << i for i, b in enumerate([left, right, middle]) if b)
15762306a36Sopenharmony_ci        x = max(-127, min(127, x))
15862306a36Sopenharmony_ci        y = max(-127, min(127, y))
15962306a36Sopenharmony_ci        x = hidtools.util.to_twos_comp(x, 8)
16062306a36Sopenharmony_ci        y = hidtools.util.to_twos_comp(y, 8)
16162306a36Sopenharmony_ci        return [button_mask, x, y]
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciclass WheelMouse(ButtonMouse):
16562306a36Sopenharmony_ci    # fmt: off
16662306a36Sopenharmony_ci    report_descriptor = [
16762306a36Sopenharmony_ci        0x05, 0x01,  # Usage Page (Generic Desktop)        0
16862306a36Sopenharmony_ci        0x09, 0x02,  # Usage (Mouse)                       2
16962306a36Sopenharmony_ci        0xa1, 0x01,  # Collection (Application)            4
17062306a36Sopenharmony_ci        0x05, 0x09,  # .Usage Page (Button)                6
17162306a36Sopenharmony_ci        0x19, 0x01,  # .Usage Minimum (1)                  8
17262306a36Sopenharmony_ci        0x29, 0x03,  # .Usage Maximum (3)                  10
17362306a36Sopenharmony_ci        0x15, 0x00,  # .Logical Minimum (0)                12
17462306a36Sopenharmony_ci        0x25, 0x01,  # .Logical Maximum (1)                14
17562306a36Sopenharmony_ci        0x95, 0x03,  # .Report Count (3)                   16
17662306a36Sopenharmony_ci        0x75, 0x01,  # .Report Size (1)                    18
17762306a36Sopenharmony_ci        0x81, 0x02,  # .Input (Data,Var,Abs)               20
17862306a36Sopenharmony_ci        0x95, 0x01,  # .Report Count (1)                   22
17962306a36Sopenharmony_ci        0x75, 0x05,  # .Report Size (5)                    24
18062306a36Sopenharmony_ci        0x81, 0x03,  # .Input (Cnst,Var,Abs)               26
18162306a36Sopenharmony_ci        0x05, 0x01,  # .Usage Page (Generic Desktop)       28
18262306a36Sopenharmony_ci        0x09, 0x01,  # .Usage (Pointer)                    30
18362306a36Sopenharmony_ci        0xa1, 0x00,  # .Collection (Physical)              32
18462306a36Sopenharmony_ci        0x09, 0x30,  # ..Usage (X)                         34
18562306a36Sopenharmony_ci        0x09, 0x31,  # ..Usage (Y)                         36
18662306a36Sopenharmony_ci        0x15, 0x81,  # ..Logical Minimum (-127)            38
18762306a36Sopenharmony_ci        0x25, 0x7f,  # ..Logical Maximum (127)             40
18862306a36Sopenharmony_ci        0x75, 0x08,  # ..Report Size (8)                   42
18962306a36Sopenharmony_ci        0x95, 0x02,  # ..Report Count (2)                  44
19062306a36Sopenharmony_ci        0x81, 0x06,  # ..Input (Data,Var,Rel)              46
19162306a36Sopenharmony_ci        0xc0,        # .End Collection                     48
19262306a36Sopenharmony_ci        0x09, 0x38,  # .Usage (Wheel)                      49
19362306a36Sopenharmony_ci        0x15, 0x81,  # .Logical Minimum (-127)             51
19462306a36Sopenharmony_ci        0x25, 0x7f,  # .Logical Maximum (127)              53
19562306a36Sopenharmony_ci        0x75, 0x08,  # .Report Size (8)                    55
19662306a36Sopenharmony_ci        0x95, 0x01,  # .Report Count (1)                   57
19762306a36Sopenharmony_ci        0x81, 0x06,  # .Input (Data,Var,Rel)               59
19862306a36Sopenharmony_ci        0xc0,        # End Collection                      61
19962306a36Sopenharmony_ci    ]
20062306a36Sopenharmony_ci    # fmt: on
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
20362306a36Sopenharmony_ci        super().__init__(rdesc, name, input_info)
20462306a36Sopenharmony_ci        self.wheel_multiplier = 1
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciclass TwoWheelMouse(WheelMouse):
20862306a36Sopenharmony_ci    # fmt: off
20962306a36Sopenharmony_ci    report_descriptor = [
21062306a36Sopenharmony_ci        0x05, 0x01,        # Usage Page (Generic Desktop)        0
21162306a36Sopenharmony_ci        0x09, 0x02,        # Usage (Mouse)                       2
21262306a36Sopenharmony_ci        0xa1, 0x01,        # Collection (Application)            4
21362306a36Sopenharmony_ci        0x09, 0x01,        # .Usage (Pointer)                    6
21462306a36Sopenharmony_ci        0xa1, 0x00,        # .Collection (Physical)              8
21562306a36Sopenharmony_ci        0x05, 0x09,        # ..Usage Page (Button)               10
21662306a36Sopenharmony_ci        0x19, 0x01,        # ..Usage Minimum (1)                 12
21762306a36Sopenharmony_ci        0x29, 0x10,        # ..Usage Maximum (16)                14
21862306a36Sopenharmony_ci        0x15, 0x00,        # ..Logical Minimum (0)               16
21962306a36Sopenharmony_ci        0x25, 0x01,        # ..Logical Maximum (1)               18
22062306a36Sopenharmony_ci        0x95, 0x10,        # ..Report Count (16)                 20
22162306a36Sopenharmony_ci        0x75, 0x01,        # ..Report Size (1)                   22
22262306a36Sopenharmony_ci        0x81, 0x02,        # ..Input (Data,Var,Abs)              24
22362306a36Sopenharmony_ci        0x05, 0x01,        # ..Usage Page (Generic Desktop)      26
22462306a36Sopenharmony_ci        0x16, 0x01, 0x80,  # ..Logical Minimum (-32767)          28
22562306a36Sopenharmony_ci        0x26, 0xff, 0x7f,  # ..Logical Maximum (32767)           31
22662306a36Sopenharmony_ci        0x75, 0x10,        # ..Report Size (16)                  34
22762306a36Sopenharmony_ci        0x95, 0x02,        # ..Report Count (2)                  36
22862306a36Sopenharmony_ci        0x09, 0x30,        # ..Usage (X)                         38
22962306a36Sopenharmony_ci        0x09, 0x31,        # ..Usage (Y)                         40
23062306a36Sopenharmony_ci        0x81, 0x06,        # ..Input (Data,Var,Rel)              42
23162306a36Sopenharmony_ci        0x15, 0x81,        # ..Logical Minimum (-127)            44
23262306a36Sopenharmony_ci        0x25, 0x7f,        # ..Logical Maximum (127)             46
23362306a36Sopenharmony_ci        0x75, 0x08,        # ..Report Size (8)                   48
23462306a36Sopenharmony_ci        0x95, 0x01,        # ..Report Count (1)                  50
23562306a36Sopenharmony_ci        0x09, 0x38,        # ..Usage (Wheel)                     52
23662306a36Sopenharmony_ci        0x81, 0x06,        # ..Input (Data,Var,Rel)              54
23762306a36Sopenharmony_ci        0x05, 0x0c,        # ..Usage Page (Consumer Devices)     56
23862306a36Sopenharmony_ci        0x0a, 0x38, 0x02,  # ..Usage (AC Pan)                    58
23962306a36Sopenharmony_ci        0x95, 0x01,        # ..Report Count (1)                  61
24062306a36Sopenharmony_ci        0x81, 0x06,        # ..Input (Data,Var,Rel)              63
24162306a36Sopenharmony_ci        0xc0,              # .End Collection                     65
24262306a36Sopenharmony_ci        0xc0,              # End Collection                      66
24362306a36Sopenharmony_ci    ]
24462306a36Sopenharmony_ci    # fmt: on
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
24762306a36Sopenharmony_ci        super().__init__(rdesc, name, input_info)
24862306a36Sopenharmony_ci        self.hwheel_multiplier = 1
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ciclass MIDongleMIWirelessMouse(TwoWheelMouse):
25262306a36Sopenharmony_ci    # fmt: off
25362306a36Sopenharmony_ci    report_descriptor = [
25462306a36Sopenharmony_ci        0x05, 0x01,         # Usage Page (Generic Desktop)
25562306a36Sopenharmony_ci        0x09, 0x02,         # Usage (Mouse)
25662306a36Sopenharmony_ci        0xa1, 0x01,         # Collection (Application)
25762306a36Sopenharmony_ci        0x85, 0x01,         # .Report ID (1)
25862306a36Sopenharmony_ci        0x09, 0x01,         # .Usage (Pointer)
25962306a36Sopenharmony_ci        0xa1, 0x00,         # .Collection (Physical)
26062306a36Sopenharmony_ci        0x95, 0x05,         # ..Report Count (5)
26162306a36Sopenharmony_ci        0x75, 0x01,         # ..Report Size (1)
26262306a36Sopenharmony_ci        0x05, 0x09,         # ..Usage Page (Button)
26362306a36Sopenharmony_ci        0x19, 0x01,         # ..Usage Minimum (1)
26462306a36Sopenharmony_ci        0x29, 0x05,         # ..Usage Maximum (5)
26562306a36Sopenharmony_ci        0x15, 0x00,         # ..Logical Minimum (0)
26662306a36Sopenharmony_ci        0x25, 0x01,         # ..Logical Maximum (1)
26762306a36Sopenharmony_ci        0x81, 0x02,         # ..Input (Data,Var,Abs)
26862306a36Sopenharmony_ci        0x95, 0x01,         # ..Report Count (1)
26962306a36Sopenharmony_ci        0x75, 0x03,         # ..Report Size (3)
27062306a36Sopenharmony_ci        0x81, 0x01,         # ..Input (Cnst,Arr,Abs)
27162306a36Sopenharmony_ci        0x75, 0x08,         # ..Report Size (8)
27262306a36Sopenharmony_ci        0x95, 0x01,         # ..Report Count (1)
27362306a36Sopenharmony_ci        0x05, 0x01,         # ..Usage Page (Generic Desktop)
27462306a36Sopenharmony_ci        0x09, 0x38,         # ..Usage (Wheel)
27562306a36Sopenharmony_ci        0x15, 0x81,         # ..Logical Minimum (-127)
27662306a36Sopenharmony_ci        0x25, 0x7f,         # ..Logical Maximum (127)
27762306a36Sopenharmony_ci        0x81, 0x06,         # ..Input (Data,Var,Rel)
27862306a36Sopenharmony_ci        0x05, 0x0c,         # ..Usage Page (Consumer Devices)
27962306a36Sopenharmony_ci        0x0a, 0x38, 0x02,   # ..Usage (AC Pan)
28062306a36Sopenharmony_ci        0x95, 0x01,         # ..Report Count (1)
28162306a36Sopenharmony_ci        0x81, 0x06,         # ..Input (Data,Var,Rel)
28262306a36Sopenharmony_ci        0xc0,               # .End Collection
28362306a36Sopenharmony_ci        0x85, 0x02,         # .Report ID (2)
28462306a36Sopenharmony_ci        0x09, 0x01,         # .Usage (Consumer Control)
28562306a36Sopenharmony_ci        0xa1, 0x00,         # .Collection (Physical)
28662306a36Sopenharmony_ci        0x75, 0x0c,         # ..Report Size (12)
28762306a36Sopenharmony_ci        0x95, 0x02,         # ..Report Count (2)
28862306a36Sopenharmony_ci        0x05, 0x01,         # ..Usage Page (Generic Desktop)
28962306a36Sopenharmony_ci        0x09, 0x30,         # ..Usage (X)
29062306a36Sopenharmony_ci        0x09, 0x31,         # ..Usage (Y)
29162306a36Sopenharmony_ci        0x16, 0x01, 0xf8,   # ..Logical Minimum (-2047)
29262306a36Sopenharmony_ci        0x26, 0xff, 0x07,   # ..Logical Maximum (2047)
29362306a36Sopenharmony_ci        0x81, 0x06,         # ..Input (Data,Var,Rel)
29462306a36Sopenharmony_ci        0xc0,               # .End Collection
29562306a36Sopenharmony_ci        0xc0,               # End Collection
29662306a36Sopenharmony_ci        0x05, 0x0c,         # Usage Page (Consumer Devices)
29762306a36Sopenharmony_ci        0x09, 0x01,         # Usage (Consumer Control)
29862306a36Sopenharmony_ci        0xa1, 0x01,         # Collection (Application)
29962306a36Sopenharmony_ci        0x85, 0x03,         # .Report ID (3)
30062306a36Sopenharmony_ci        0x15, 0x00,         # .Logical Minimum (0)
30162306a36Sopenharmony_ci        0x25, 0x01,         # .Logical Maximum (1)
30262306a36Sopenharmony_ci        0x75, 0x01,         # .Report Size (1)
30362306a36Sopenharmony_ci        0x95, 0x01,         # .Report Count (1)
30462306a36Sopenharmony_ci        0x09, 0xcd,         # .Usage (Play/Pause)
30562306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
30662306a36Sopenharmony_ci        0x0a, 0x83, 0x01,   # .Usage (AL Consumer Control Config)
30762306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
30862306a36Sopenharmony_ci        0x09, 0xb5,         # .Usage (Scan Next Track)
30962306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
31062306a36Sopenharmony_ci        0x09, 0xb6,         # .Usage (Scan Previous Track)
31162306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
31262306a36Sopenharmony_ci        0x09, 0xea,         # .Usage (Volume Down)
31362306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
31462306a36Sopenharmony_ci        0x09, 0xe9,         # .Usage (Volume Up)
31562306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
31662306a36Sopenharmony_ci        0x0a, 0x25, 0x02,   # .Usage (AC Forward)
31762306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
31862306a36Sopenharmony_ci        0x0a, 0x24, 0x02,   # .Usage (AC Back)
31962306a36Sopenharmony_ci        0x81, 0x06,         # .Input (Data,Var,Rel)
32062306a36Sopenharmony_ci        0xc0,               # End Collection
32162306a36Sopenharmony_ci    ]
32262306a36Sopenharmony_ci    # fmt: on
32362306a36Sopenharmony_ci    device_input_info = (BusType.USB, 0x2717, 0x003B)
32462306a36Sopenharmony_ci    device_name = "uhid test MI Dongle MI Wireless Mouse"
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci    def __init__(
32762306a36Sopenharmony_ci        self, rdesc=report_descriptor, name=device_name, input_info=device_input_info
32862306a36Sopenharmony_ci    ):
32962306a36Sopenharmony_ci        super().__init__(rdesc, name, input_info)
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci    def event(self, x, y, buttons=None, wheels=None):
33262306a36Sopenharmony_ci        # this mouse spreads the relative pointer and the mouse buttons
33362306a36Sopenharmony_ci        # onto 2 distinct reports
33462306a36Sopenharmony_ci        rs = []
33562306a36Sopenharmony_ci        r = self.create_report(x, y, buttons, wheels, reportID=1)
33662306a36Sopenharmony_ci        self.call_input_event(r)
33762306a36Sopenharmony_ci        rs.append(r)
33862306a36Sopenharmony_ci        r = self.create_report(x, y, buttons, reportID=2)
33962306a36Sopenharmony_ci        self.call_input_event(r)
34062306a36Sopenharmony_ci        rs.append(r)
34162306a36Sopenharmony_ci        return rs
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ciclass ResolutionMultiplierMouse(TwoWheelMouse):
34562306a36Sopenharmony_ci    # fmt: off
34662306a36Sopenharmony_ci    report_descriptor = [
34762306a36Sopenharmony_ci        0x05, 0x01,        # Usage Page (Generic Desktop)        83
34862306a36Sopenharmony_ci        0x09, 0x02,        # Usage (Mouse)                       85
34962306a36Sopenharmony_ci        0xa1, 0x01,        # Collection (Application)            87
35062306a36Sopenharmony_ci        0x05, 0x01,        # .Usage Page (Generic Desktop)       89
35162306a36Sopenharmony_ci        0x09, 0x02,        # .Usage (Mouse)                      91
35262306a36Sopenharmony_ci        0xa1, 0x02,        # .Collection (Logical)               93
35362306a36Sopenharmony_ci        0x85, 0x11,        # ..Report ID (17)                    95
35462306a36Sopenharmony_ci        0x09, 0x01,        # ..Usage (Pointer)                   97
35562306a36Sopenharmony_ci        0xa1, 0x00,        # ..Collection (Physical)             99
35662306a36Sopenharmony_ci        0x05, 0x09,        # ...Usage Page (Button)              101
35762306a36Sopenharmony_ci        0x19, 0x01,        # ...Usage Minimum (1)                103
35862306a36Sopenharmony_ci        0x29, 0x03,        # ...Usage Maximum (3)                105
35962306a36Sopenharmony_ci        0x95, 0x03,        # ...Report Count (3)                 107
36062306a36Sopenharmony_ci        0x75, 0x01,        # ...Report Size (1)                  109
36162306a36Sopenharmony_ci        0x25, 0x01,        # ...Logical Maximum (1)              111
36262306a36Sopenharmony_ci        0x81, 0x02,        # ...Input (Data,Var,Abs)             113
36362306a36Sopenharmony_ci        0x95, 0x01,        # ...Report Count (1)                 115
36462306a36Sopenharmony_ci        0x81, 0x01,        # ...Input (Cnst,Arr,Abs)             117
36562306a36Sopenharmony_ci        0x09, 0x05,        # ...Usage (Vendor Usage 0x05)        119
36662306a36Sopenharmony_ci        0x81, 0x02,        # ...Input (Data,Var,Abs)             121
36762306a36Sopenharmony_ci        0x95, 0x03,        # ...Report Count (3)                 123
36862306a36Sopenharmony_ci        0x81, 0x01,        # ...Input (Cnst,Arr,Abs)             125
36962306a36Sopenharmony_ci        0x05, 0x01,        # ...Usage Page (Generic Desktop)     127
37062306a36Sopenharmony_ci        0x09, 0x30,        # ...Usage (X)                        129
37162306a36Sopenharmony_ci        0x09, 0x31,        # ...Usage (Y)                        131
37262306a36Sopenharmony_ci        0x95, 0x02,        # ...Report Count (2)                 133
37362306a36Sopenharmony_ci        0x75, 0x08,        # ...Report Size (8)                  135
37462306a36Sopenharmony_ci        0x15, 0x81,        # ...Logical Minimum (-127)           137
37562306a36Sopenharmony_ci        0x25, 0x7f,        # ...Logical Maximum (127)            139
37662306a36Sopenharmony_ci        0x81, 0x06,        # ...Input (Data,Var,Rel)             141
37762306a36Sopenharmony_ci        0xa1, 0x02,        # ...Collection (Logical)             143
37862306a36Sopenharmony_ci        0x85, 0x12,        # ....Report ID (18)                  145
37962306a36Sopenharmony_ci        0x09, 0x48,        # ....Usage (Resolution Multiplier)   147
38062306a36Sopenharmony_ci        0x95, 0x01,        # ....Report Count (1)                149
38162306a36Sopenharmony_ci        0x75, 0x02,        # ....Report Size (2)                 151
38262306a36Sopenharmony_ci        0x15, 0x00,        # ....Logical Minimum (0)             153
38362306a36Sopenharmony_ci        0x25, 0x01,        # ....Logical Maximum (1)             155
38462306a36Sopenharmony_ci        0x35, 0x01,        # ....Physical Minimum (1)            157
38562306a36Sopenharmony_ci        0x45, 0x04,        # ....Physical Maximum (4)            159
38662306a36Sopenharmony_ci        0xb1, 0x02,        # ....Feature (Data,Var,Abs)          161
38762306a36Sopenharmony_ci        0x35, 0x00,        # ....Physical Minimum (0)            163
38862306a36Sopenharmony_ci        0x45, 0x00,        # ....Physical Maximum (0)            165
38962306a36Sopenharmony_ci        0x75, 0x06,        # ....Report Size (6)                 167
39062306a36Sopenharmony_ci        0xb1, 0x01,        # ....Feature (Cnst,Arr,Abs)          169
39162306a36Sopenharmony_ci        0x85, 0x11,        # ....Report ID (17)                  171
39262306a36Sopenharmony_ci        0x09, 0x38,        # ....Usage (Wheel)                   173
39362306a36Sopenharmony_ci        0x15, 0x81,        # ....Logical Minimum (-127)          175
39462306a36Sopenharmony_ci        0x25, 0x7f,        # ....Logical Maximum (127)           177
39562306a36Sopenharmony_ci        0x75, 0x08,        # ....Report Size (8)                 179
39662306a36Sopenharmony_ci        0x81, 0x06,        # ....Input (Data,Var,Rel)            181
39762306a36Sopenharmony_ci        0xc0,              # ...End Collection                   183
39862306a36Sopenharmony_ci        0x05, 0x0c,        # ...Usage Page (Consumer Devices)    184
39962306a36Sopenharmony_ci        0x75, 0x08,        # ...Report Size (8)                  186
40062306a36Sopenharmony_ci        0x0a, 0x38, 0x02,  # ...Usage (AC Pan)                   188
40162306a36Sopenharmony_ci        0x81, 0x06,        # ...Input (Data,Var,Rel)             191
40262306a36Sopenharmony_ci        0xc0,              # ..End Collection                    193
40362306a36Sopenharmony_ci        0xc0,              # .End Collection                     194
40462306a36Sopenharmony_ci        0xc0,              # End Collection                      195
40562306a36Sopenharmony_ci    ]
40662306a36Sopenharmony_ci    # fmt: on
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
40962306a36Sopenharmony_ci        super().__init__(rdesc, name, input_info)
41062306a36Sopenharmony_ci        self.default_reportID = 0x11
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci        # Feature Report 12, multiplier Feature value must be set to 0b01,
41362306a36Sopenharmony_ci        # i.e. 1. We should extract that from the descriptor instead
41462306a36Sopenharmony_ci        # of hardcoding it here, but meanwhile this will do.
41562306a36Sopenharmony_ci        self.set_feature_report = [0x12, 0x1]
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci    def set_report(self, req, rnum, rtype, data):
41862306a36Sopenharmony_ci        if rtype != self.UHID_FEATURE_REPORT:
41962306a36Sopenharmony_ci            raise InvalidHIDCommunication(f"Unexpected report type: {rtype}")
42062306a36Sopenharmony_ci        if rnum != 0x12:
42162306a36Sopenharmony_ci            raise InvalidHIDCommunication(f"Unexpected report number: {rnum}")
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci        if data != self.set_feature_report:
42462306a36Sopenharmony_ci            raise InvalidHIDCommunication(
42562306a36Sopenharmony_ci                f"Unexpected data: {data}, expected {self.set_feature_report}"
42662306a36Sopenharmony_ci            )
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci        self.wheel_multiplier = 4
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci        return 0
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ciclass BadResolutionMultiplierMouse(ResolutionMultiplierMouse):
43462306a36Sopenharmony_ci    def set_report(self, req, rnum, rtype, data):
43562306a36Sopenharmony_ci        super().set_report(req, rnum, rtype, data)
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci        self.wheel_multiplier = 1
43862306a36Sopenharmony_ci        self.hwheel_multiplier = 1
43962306a36Sopenharmony_ci        return 32  # EPIPE
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ciclass ResolutionMultiplierHWheelMouse(TwoWheelMouse):
44362306a36Sopenharmony_ci    # fmt: off
44462306a36Sopenharmony_ci    report_descriptor = [
44562306a36Sopenharmony_ci        0x05, 0x01,         # Usage Page (Generic Desktop)        0
44662306a36Sopenharmony_ci        0x09, 0x02,         # Usage (Mouse)                       2
44762306a36Sopenharmony_ci        0xa1, 0x01,         # Collection (Application)            4
44862306a36Sopenharmony_ci        0x05, 0x01,         # .Usage Page (Generic Desktop)       6
44962306a36Sopenharmony_ci        0x09, 0x02,         # .Usage (Mouse)                      8
45062306a36Sopenharmony_ci        0xa1, 0x02,         # .Collection (Logical)               10
45162306a36Sopenharmony_ci        0x85, 0x1a,         # ..Report ID (26)                    12
45262306a36Sopenharmony_ci        0x09, 0x01,         # ..Usage (Pointer)                   14
45362306a36Sopenharmony_ci        0xa1, 0x00,         # ..Collection (Physical)             16
45462306a36Sopenharmony_ci        0x05, 0x09,         # ...Usage Page (Button)              18
45562306a36Sopenharmony_ci        0x19, 0x01,         # ...Usage Minimum (1)                20
45662306a36Sopenharmony_ci        0x29, 0x05,         # ...Usage Maximum (5)                22
45762306a36Sopenharmony_ci        0x95, 0x05,         # ...Report Count (5)                 24
45862306a36Sopenharmony_ci        0x75, 0x01,         # ...Report Size (1)                  26
45962306a36Sopenharmony_ci        0x15, 0x00,         # ...Logical Minimum (0)              28
46062306a36Sopenharmony_ci        0x25, 0x01,         # ...Logical Maximum (1)              30
46162306a36Sopenharmony_ci        0x81, 0x02,         # ...Input (Data,Var,Abs)             32
46262306a36Sopenharmony_ci        0x75, 0x03,         # ...Report Size (3)                  34
46362306a36Sopenharmony_ci        0x95, 0x01,         # ...Report Count (1)                 36
46462306a36Sopenharmony_ci        0x81, 0x01,         # ...Input (Cnst,Arr,Abs)             38
46562306a36Sopenharmony_ci        0x05, 0x01,         # ...Usage Page (Generic Desktop)     40
46662306a36Sopenharmony_ci        0x09, 0x30,         # ...Usage (X)                        42
46762306a36Sopenharmony_ci        0x09, 0x31,         # ...Usage (Y)                        44
46862306a36Sopenharmony_ci        0x95, 0x02,         # ...Report Count (2)                 46
46962306a36Sopenharmony_ci        0x75, 0x10,         # ...Report Size (16)                 48
47062306a36Sopenharmony_ci        0x16, 0x01, 0x80,   # ...Logical Minimum (-32767)         50
47162306a36Sopenharmony_ci        0x26, 0xff, 0x7f,   # ...Logical Maximum (32767)          53
47262306a36Sopenharmony_ci        0x81, 0x06,         # ...Input (Data,Var,Rel)             56
47362306a36Sopenharmony_ci        0xa1, 0x02,         # ...Collection (Logical)             58
47462306a36Sopenharmony_ci        0x85, 0x12,         # ....Report ID (18)                  60
47562306a36Sopenharmony_ci        0x09, 0x48,         # ....Usage (Resolution Multiplier)   62
47662306a36Sopenharmony_ci        0x95, 0x01,         # ....Report Count (1)                64
47762306a36Sopenharmony_ci        0x75, 0x02,         # ....Report Size (2)                 66
47862306a36Sopenharmony_ci        0x15, 0x00,         # ....Logical Minimum (0)             68
47962306a36Sopenharmony_ci        0x25, 0x01,         # ....Logical Maximum (1)             70
48062306a36Sopenharmony_ci        0x35, 0x01,         # ....Physical Minimum (1)            72
48162306a36Sopenharmony_ci        0x45, 0x0c,         # ....Physical Maximum (12)           74
48262306a36Sopenharmony_ci        0xb1, 0x02,         # ....Feature (Data,Var,Abs)          76
48362306a36Sopenharmony_ci        0x85, 0x1a,         # ....Report ID (26)                  78
48462306a36Sopenharmony_ci        0x09, 0x38,         # ....Usage (Wheel)                   80
48562306a36Sopenharmony_ci        0x35, 0x00,         # ....Physical Minimum (0)            82
48662306a36Sopenharmony_ci        0x45, 0x00,         # ....Physical Maximum (0)            84
48762306a36Sopenharmony_ci        0x95, 0x01,         # ....Report Count (1)                86
48862306a36Sopenharmony_ci        0x75, 0x10,         # ....Report Size (16)                88
48962306a36Sopenharmony_ci        0x16, 0x01, 0x80,   # ....Logical Minimum (-32767)        90
49062306a36Sopenharmony_ci        0x26, 0xff, 0x7f,   # ....Logical Maximum (32767)         93
49162306a36Sopenharmony_ci        0x81, 0x06,         # ....Input (Data,Var,Rel)            96
49262306a36Sopenharmony_ci        0xc0,               # ...End Collection                   98
49362306a36Sopenharmony_ci        0xa1, 0x02,         # ...Collection (Logical)             99
49462306a36Sopenharmony_ci        0x85, 0x12,         # ....Report ID (18)                  101
49562306a36Sopenharmony_ci        0x09, 0x48,         # ....Usage (Resolution Multiplier)   103
49662306a36Sopenharmony_ci        0x75, 0x02,         # ....Report Size (2)                 105
49762306a36Sopenharmony_ci        0x15, 0x00,         # ....Logical Minimum (0)             107
49862306a36Sopenharmony_ci        0x25, 0x01,         # ....Logical Maximum (1)             109
49962306a36Sopenharmony_ci        0x35, 0x01,         # ....Physical Minimum (1)            111
50062306a36Sopenharmony_ci        0x45, 0x0c,         # ....Physical Maximum (12)           113
50162306a36Sopenharmony_ci        0xb1, 0x02,         # ....Feature (Data,Var,Abs)          115
50262306a36Sopenharmony_ci        0x35, 0x00,         # ....Physical Minimum (0)            117
50362306a36Sopenharmony_ci        0x45, 0x00,         # ....Physical Maximum (0)            119
50462306a36Sopenharmony_ci        0x75, 0x04,         # ....Report Size (4)                 121
50562306a36Sopenharmony_ci        0xb1, 0x01,         # ....Feature (Cnst,Arr,Abs)          123
50662306a36Sopenharmony_ci        0x85, 0x1a,         # ....Report ID (26)                  125
50762306a36Sopenharmony_ci        0x05, 0x0c,         # ....Usage Page (Consumer Devices)   127
50862306a36Sopenharmony_ci        0x95, 0x01,         # ....Report Count (1)                129
50962306a36Sopenharmony_ci        0x75, 0x10,         # ....Report Size (16)                131
51062306a36Sopenharmony_ci        0x16, 0x01, 0x80,   # ....Logical Minimum (-32767)        133
51162306a36Sopenharmony_ci        0x26, 0xff, 0x7f,   # ....Logical Maximum (32767)         136
51262306a36Sopenharmony_ci        0x0a, 0x38, 0x02,   # ....Usage (AC Pan)                  139
51362306a36Sopenharmony_ci        0x81, 0x06,         # ....Input (Data,Var,Rel)            142
51462306a36Sopenharmony_ci        0xc0,               # ...End Collection                   144
51562306a36Sopenharmony_ci        0xc0,               # ..End Collection                    145
51662306a36Sopenharmony_ci        0xc0,               # .End Collection                     146
51762306a36Sopenharmony_ci        0xc0,               # End Collection                      147
51862306a36Sopenharmony_ci    ]
51962306a36Sopenharmony_ci    # fmt: on
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
52262306a36Sopenharmony_ci        super().__init__(rdesc, name, input_info)
52362306a36Sopenharmony_ci        self.default_reportID = 0x1A
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci        # Feature Report 12, multiplier Feature value must be set to 0b0101,
52662306a36Sopenharmony_ci        # i.e. 5. We should extract that from the descriptor instead
52762306a36Sopenharmony_ci        # of hardcoding it here, but meanwhile this will do.
52862306a36Sopenharmony_ci        self.set_feature_report = [0x12, 0x5]
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci    def set_report(self, req, rnum, rtype, data):
53162306a36Sopenharmony_ci        super().set_report(req, rnum, rtype, data)
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci        self.wheel_multiplier = 12
53462306a36Sopenharmony_ci        self.hwheel_multiplier = 12
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci        return 0
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ciclass BaseTest:
54062306a36Sopenharmony_ci    class TestMouse(base.BaseTestCase.TestUhid):
54162306a36Sopenharmony_ci        def test_buttons(self):
54262306a36Sopenharmony_ci            """check for button reliability."""
54362306a36Sopenharmony_ci            uhdev = self.uhdev
54462306a36Sopenharmony_ci            evdev = uhdev.get_evdev()
54562306a36Sopenharmony_ci            syn_event = self.syn_event
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci            r = uhdev.event(0, 0, (None, True, None))
54862306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
54962306a36Sopenharmony_ci            events = uhdev.next_sync_events()
55062306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
55162306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
55262306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci            r = uhdev.event(0, 0, (None, False, None))
55562306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
55662306a36Sopenharmony_ci            events = uhdev.next_sync_events()
55762306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
55862306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
55962306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci            r = uhdev.event(0, 0, (None, None, True))
56262306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 1)
56362306a36Sopenharmony_ci            events = uhdev.next_sync_events()
56462306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
56562306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
56662306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 1
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci            r = uhdev.event(0, 0, (None, None, False))
56962306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 0)
57062306a36Sopenharmony_ci            events = uhdev.next_sync_events()
57162306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
57262306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
57362306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 0
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci            r = uhdev.event(0, 0, (True, None, None))
57662306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
57762306a36Sopenharmony_ci            events = uhdev.next_sync_events()
57862306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
57962306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
58062306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci            r = uhdev.event(0, 0, (False, None, None))
58362306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
58462306a36Sopenharmony_ci            events = uhdev.next_sync_events()
58562306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
58662306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
58762306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci            r = uhdev.event(0, 0, (True, True, None))
59062306a36Sopenharmony_ci            expected_event0 = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
59162306a36Sopenharmony_ci            expected_event1 = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
59262306a36Sopenharmony_ci            events = uhdev.next_sync_events()
59362306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
59462306a36Sopenharmony_ci            self.assertInputEventsIn(
59562306a36Sopenharmony_ci                (syn_event, expected_event0, expected_event1), events
59662306a36Sopenharmony_ci            )
59762306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
59862306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci            r = uhdev.event(0, 0, (False, None, None))
60162306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
60262306a36Sopenharmony_ci            events = uhdev.next_sync_events()
60362306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
60462306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
60562306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
60662306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci            r = uhdev.event(0, 0, (None, False, None))
60962306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
61062306a36Sopenharmony_ci            events = uhdev.next_sync_events()
61162306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
61262306a36Sopenharmony_ci            self.assertInputEventsIn((syn_event, expected_event), events)
61362306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
61462306a36Sopenharmony_ci            assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci        def test_relative(self):
61762306a36Sopenharmony_ci            """Check for relative events."""
61862306a36Sopenharmony_ci            uhdev = self.uhdev
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci            syn_event = self.syn_event
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci            r = uhdev.event(0, -1)
62362306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_Y, -1)
62462306a36Sopenharmony_ci            events = uhdev.next_sync_events()
62562306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
62662306a36Sopenharmony_ci            self.assertInputEvents((syn_event, expected_event), events)
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci            r = uhdev.event(1, 0)
62962306a36Sopenharmony_ci            expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_X, 1)
63062306a36Sopenharmony_ci            events = uhdev.next_sync_events()
63162306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
63262306a36Sopenharmony_ci            self.assertInputEvents((syn_event, expected_event), events)
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci            r = uhdev.event(-1, 2)
63562306a36Sopenharmony_ci            expected_event0 = libevdev.InputEvent(libevdev.EV_REL.REL_X, -1)
63662306a36Sopenharmony_ci            expected_event1 = libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2)
63762306a36Sopenharmony_ci            events = uhdev.next_sync_events()
63862306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
63962306a36Sopenharmony_ci            self.assertInputEvents(
64062306a36Sopenharmony_ci                (syn_event, expected_event0, expected_event1), events
64162306a36Sopenharmony_ci            )
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciclass TestSimpleMouse(BaseTest.TestMouse):
64562306a36Sopenharmony_ci    def create_device(self):
64662306a36Sopenharmony_ci        return ButtonMouse()
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci    def test_rdesc(self):
64962306a36Sopenharmony_ci        """Check that the testsuite actually manages to format the
65062306a36Sopenharmony_ci        reports according to the report descriptors.
65162306a36Sopenharmony_ci        No kernel device is used here"""
65262306a36Sopenharmony_ci        uhdev = self.uhdev
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci        event = (0, 0, (None, None, None))
65562306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci        event = (0, 0, (None, True, None))
65862306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci        event = (0, 0, (True, True, None))
66162306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci        event = (0, 0, (False, False, False))
66462306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci        event = (1, 0, (True, False, True))
66762306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci        event = (-1, 0, (True, False, True))
67062306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci        event = (-5, 5, (True, False, True))
67362306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci        event = (-127, 127, (True, False, True))
67662306a36Sopenharmony_ci        assert uhdev.fake_report(*event) == uhdev.create_report(*event)
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci        event = (0, -128, (True, False, True))
67962306a36Sopenharmony_ci        with pytest.raises(hidtools.hid.RangeError):
68062306a36Sopenharmony_ci            uhdev.create_report(*event)
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ciclass TestWheelMouse(BaseTest.TestMouse):
68462306a36Sopenharmony_ci    def create_device(self):
68562306a36Sopenharmony_ci        return WheelMouse()
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci    def is_wheel_highres(self, uhdev):
68862306a36Sopenharmony_ci        evdev = uhdev.get_evdev()
68962306a36Sopenharmony_ci        assert evdev.has(libevdev.EV_REL.REL_WHEEL)
69062306a36Sopenharmony_ci        return evdev.has(libevdev.EV_REL.REL_WHEEL_HI_RES)
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci    def test_wheel(self):
69362306a36Sopenharmony_ci        uhdev = self.uhdev
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci        # check if the kernel is high res wheel compatible
69662306a36Sopenharmony_ci        high_res_wheel = self.is_wheel_highres(uhdev)
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci        syn_event = self.syn_event
69962306a36Sopenharmony_ci        # The Resolution Multiplier is applied to the HID reports, so we
70062306a36Sopenharmony_ci        # need to pre-multiply too.
70162306a36Sopenharmony_ci        mult = uhdev.wheel_multiplier
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=1 * mult)
70462306a36Sopenharmony_ci        expected = [syn_event]
70562306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
70662306a36Sopenharmony_ci        if high_res_wheel:
70762306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120))
70862306a36Sopenharmony_ci        events = uhdev.next_sync_events()
70962306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
71062306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=-1 * mult)
71362306a36Sopenharmony_ci        expected = [syn_event]
71462306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -1))
71562306a36Sopenharmony_ci        if high_res_wheel:
71662306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120))
71762306a36Sopenharmony_ci        events = uhdev.next_sync_events()
71862306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
71962306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci        r = uhdev.event(-1, 2, wheels=3 * mult)
72262306a36Sopenharmony_ci        expected = [syn_event]
72362306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
72462306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
72562306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 3))
72662306a36Sopenharmony_ci        if high_res_wheel:
72762306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 360))
72862306a36Sopenharmony_ci        events = uhdev.next_sync_events()
72962306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
73062306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ciclass TestTwoWheelMouse(TestWheelMouse):
73462306a36Sopenharmony_ci    def create_device(self):
73562306a36Sopenharmony_ci        return TwoWheelMouse()
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci    def is_hwheel_highres(self, uhdev):
73862306a36Sopenharmony_ci        evdev = uhdev.get_evdev()
73962306a36Sopenharmony_ci        assert evdev.has(libevdev.EV_REL.REL_HWHEEL)
74062306a36Sopenharmony_ci        return evdev.has(libevdev.EV_REL.REL_HWHEEL_HI_RES)
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci    def test_ac_pan(self):
74362306a36Sopenharmony_ci        uhdev = self.uhdev
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci        # check if the kernel is high res wheel compatible
74662306a36Sopenharmony_ci        high_res_wheel = self.is_wheel_highres(uhdev)
74762306a36Sopenharmony_ci        high_res_hwheel = self.is_hwheel_highres(uhdev)
74862306a36Sopenharmony_ci        assert high_res_wheel == high_res_hwheel
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci        syn_event = self.syn_event
75162306a36Sopenharmony_ci        # The Resolution Multiplier is applied to the HID reports, so we
75262306a36Sopenharmony_ci        # need to pre-multiply too.
75362306a36Sopenharmony_ci        hmult = uhdev.hwheel_multiplier
75462306a36Sopenharmony_ci        vmult = uhdev.wheel_multiplier
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=(0, 1 * hmult))
75762306a36Sopenharmony_ci        expected = [syn_event]
75862306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
75962306a36Sopenharmony_ci        if high_res_hwheel:
76062306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120))
76162306a36Sopenharmony_ci        events = uhdev.next_sync_events()
76262306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
76362306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=(0, -1 * hmult))
76662306a36Sopenharmony_ci        expected = [syn_event]
76762306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, -1))
76862306a36Sopenharmony_ci        if high_res_hwheel:
76962306a36Sopenharmony_ci            expected.append(
77062306a36Sopenharmony_ci                libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120)
77162306a36Sopenharmony_ci            )
77262306a36Sopenharmony_ci        events = uhdev.next_sync_events()
77362306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
77462306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci        r = uhdev.event(-1, 2, wheels=(0, 3 * hmult))
77762306a36Sopenharmony_ci        expected = [syn_event]
77862306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
77962306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
78062306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 3))
78162306a36Sopenharmony_ci        if high_res_hwheel:
78262306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 360))
78362306a36Sopenharmony_ci        events = uhdev.next_sync_events()
78462306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
78562306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci        r = uhdev.event(-1, 2, wheels=(-3 * vmult, 4 * hmult))
78862306a36Sopenharmony_ci        expected = [syn_event]
78962306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
79062306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
79162306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -3))
79262306a36Sopenharmony_ci        if high_res_wheel:
79362306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -360))
79462306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 4))
79562306a36Sopenharmony_ci        if high_res_wheel:
79662306a36Sopenharmony_ci            expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 480))
79762306a36Sopenharmony_ci        events = uhdev.next_sync_events()
79862306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
79962306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ciclass TestResolutionMultiplierMouse(TestTwoWheelMouse):
80362306a36Sopenharmony_ci    def create_device(self):
80462306a36Sopenharmony_ci        return ResolutionMultiplierMouse()
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci    def is_wheel_highres(self, uhdev):
80762306a36Sopenharmony_ci        high_res = super().is_wheel_highres(uhdev)
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci        if not high_res:
81062306a36Sopenharmony_ci            # the kernel doesn't seem to support the high res wheel mice,
81162306a36Sopenharmony_ci            # make sure we haven't triggered the feature
81262306a36Sopenharmony_ci            assert uhdev.wheel_multiplier == 1
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci        return high_res
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci    def test_resolution_multiplier_wheel(self):
81762306a36Sopenharmony_ci        uhdev = self.uhdev
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci        if not self.is_wheel_highres(uhdev):
82062306a36Sopenharmony_ci            pytest.skip("Kernel not compatible, we can not trigger the conditions")
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci        assert uhdev.wheel_multiplier > 1
82362306a36Sopenharmony_ci        assert 120 % uhdev.wheel_multiplier == 0
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci    def test_wheel_with_multiplier(self):
82662306a36Sopenharmony_ci        uhdev = self.uhdev
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci        if not self.is_wheel_highres(uhdev):
82962306a36Sopenharmony_ci            pytest.skip("Kernel not compatible, we can not trigger the conditions")
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci        assert uhdev.wheel_multiplier > 1
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci        syn_event = self.syn_event
83462306a36Sopenharmony_ci        mult = uhdev.wheel_multiplier
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=1)
83762306a36Sopenharmony_ci        expected = [syn_event]
83862306a36Sopenharmony_ci        expected.append(
83962306a36Sopenharmony_ci            libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
84062306a36Sopenharmony_ci        )
84162306a36Sopenharmony_ci        events = uhdev.next_sync_events()
84262306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
84362306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=-1)
84662306a36Sopenharmony_ci        expected = [syn_event]
84762306a36Sopenharmony_ci        expected.append(
84862306a36Sopenharmony_ci            libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120 / mult)
84962306a36Sopenharmony_ci        )
85062306a36Sopenharmony_ci        events = uhdev.next_sync_events()
85162306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
85262306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci        expected = [syn_event]
85562306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
85662306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
85762306a36Sopenharmony_ci        expected.append(
85862306a36Sopenharmony_ci            libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
85962306a36Sopenharmony_ci        )
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci        for _ in range(mult - 1):
86262306a36Sopenharmony_ci            r = uhdev.event(1, -2, wheels=1)
86362306a36Sopenharmony_ci            events = uhdev.next_sync_events()
86462306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
86562306a36Sopenharmony_ci            self.assertInputEvents(expected, events)
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci        r = uhdev.event(1, -2, wheels=1)
86862306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
86962306a36Sopenharmony_ci        events = uhdev.next_sync_events()
87062306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
87162306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ciclass TestBadResolutionMultiplierMouse(TestTwoWheelMouse):
87562306a36Sopenharmony_ci    def create_device(self):
87662306a36Sopenharmony_ci        return BadResolutionMultiplierMouse()
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci    def is_wheel_highres(self, uhdev):
87962306a36Sopenharmony_ci        high_res = super().is_wheel_highres(uhdev)
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci        assert uhdev.wheel_multiplier == 1
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci        return high_res
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci    def test_resolution_multiplier_wheel(self):
88662306a36Sopenharmony_ci        uhdev = self.uhdev
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci        assert uhdev.wheel_multiplier == 1
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ciclass TestResolutionMultiplierHWheelMouse(TestResolutionMultiplierMouse):
89262306a36Sopenharmony_ci    def create_device(self):
89362306a36Sopenharmony_ci        return ResolutionMultiplierHWheelMouse()
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci    def is_hwheel_highres(self, uhdev):
89662306a36Sopenharmony_ci        high_res = super().is_hwheel_highres(uhdev)
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci        if not high_res:
89962306a36Sopenharmony_ci            # the kernel doesn't seem to support the high res wheel mice,
90062306a36Sopenharmony_ci            # make sure we haven't triggered the feature
90162306a36Sopenharmony_ci            assert uhdev.hwheel_multiplier == 1
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci        return high_res
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci    def test_resolution_multiplier_ac_pan(self):
90662306a36Sopenharmony_ci        uhdev = self.uhdev
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci        if not self.is_hwheel_highres(uhdev):
90962306a36Sopenharmony_ci            pytest.skip("Kernel not compatible, we can not trigger the conditions")
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci        assert uhdev.hwheel_multiplier > 1
91262306a36Sopenharmony_ci        assert 120 % uhdev.hwheel_multiplier == 0
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci    def test_ac_pan_with_multiplier(self):
91562306a36Sopenharmony_ci        uhdev = self.uhdev
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci        if not self.is_hwheel_highres(uhdev):
91862306a36Sopenharmony_ci            pytest.skip("Kernel not compatible, we can not trigger the conditions")
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci        assert uhdev.hwheel_multiplier > 1
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci        syn_event = self.syn_event
92362306a36Sopenharmony_ci        hmult = uhdev.hwheel_multiplier
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=(0, 1))
92662306a36Sopenharmony_ci        expected = [syn_event]
92762306a36Sopenharmony_ci        expected.append(
92862306a36Sopenharmony_ci            libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
92962306a36Sopenharmony_ci        )
93062306a36Sopenharmony_ci        events = uhdev.next_sync_events()
93162306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
93262306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci        r = uhdev.event(0, 0, wheels=(0, -1))
93562306a36Sopenharmony_ci        expected = [syn_event]
93662306a36Sopenharmony_ci        expected.append(
93762306a36Sopenharmony_ci            libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120 / hmult)
93862306a36Sopenharmony_ci        )
93962306a36Sopenharmony_ci        events = uhdev.next_sync_events()
94062306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
94162306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci        expected = [syn_event]
94462306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
94562306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
94662306a36Sopenharmony_ci        expected.append(
94762306a36Sopenharmony_ci            libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
94862306a36Sopenharmony_ci        )
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci        for _ in range(hmult - 1):
95162306a36Sopenharmony_ci            r = uhdev.event(1, -2, wheels=(0, 1))
95262306a36Sopenharmony_ci            events = uhdev.next_sync_events()
95362306a36Sopenharmony_ci            self.debug_reports(r, uhdev, events)
95462306a36Sopenharmony_ci            self.assertInputEvents(expected, events)
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci        r = uhdev.event(1, -2, wheels=(0, 1))
95762306a36Sopenharmony_ci        expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
95862306a36Sopenharmony_ci        events = uhdev.next_sync_events()
95962306a36Sopenharmony_ci        self.debug_reports(r, uhdev, events)
96062306a36Sopenharmony_ci        self.assertInputEvents(expected, events)
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ciclass TestMiMouse(TestWheelMouse):
96462306a36Sopenharmony_ci    def create_device(self):
96562306a36Sopenharmony_ci        return MIDongleMIWirelessMouse()
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci    def assertInputEvents(self, expected_events, effective_events):
96862306a36Sopenharmony_ci        # Buttons and x/y are spread over two HID reports, so we can get two
96962306a36Sopenharmony_ci        # event frames for this device.
97062306a36Sopenharmony_ci        remaining = self.assertInputEventsIn(expected_events, effective_events)
97162306a36Sopenharmony_ci        try:
97262306a36Sopenharmony_ci            remaining.remove(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT, 0))
97362306a36Sopenharmony_ci        except ValueError:
97462306a36Sopenharmony_ci            # If there's no SYN_REPORT in the list, continue and let the
97562306a36Sopenharmony_ci            # assert below print out the real error
97662306a36Sopenharmony_ci            pass
97762306a36Sopenharmony_ci        assert remaining == []
978