drm/panel: panel-himax-hx83102: support for csot-pna957qt1-1 MIPI-DSI panel
[drm/drm-misc.git] / tools / testing / selftests / hid / tests / base_gamepad.py
blobec74d75767a22b5b3ed7a8b0ac232e7d63d721c5
1 # SPDX-License-Identifier: GPL-2.0
2 import libevdev
4 from .base_device import BaseDevice
5 from hidtools.util import BusType
8 class InvalidHIDCommunication(Exception):
9 pass
12 class GamepadData(object):
13 pass
16 class AxisMapping(object):
17 """Represents a mapping between a HID type
18 and an evdev event"""
20 def __init__(self, hid, evdev=None):
21 self.hid = hid.lower()
23 if evdev is None:
24 evdev = f"ABS_{hid.upper()}"
26 self.evdev = libevdev.evbit("EV_ABS", evdev)
29 class BaseGamepad(BaseDevice):
30 buttons_map = {
31 1: "BTN_SOUTH",
32 2: "BTN_EAST",
33 3: "BTN_C",
34 4: "BTN_NORTH",
35 5: "BTN_WEST",
36 6: "BTN_Z",
37 7: "BTN_TL",
38 8: "BTN_TR",
39 9: "BTN_TL2",
40 10: "BTN_TR2",
41 11: "BTN_SELECT",
42 12: "BTN_START",
43 13: "BTN_MODE",
44 14: "BTN_THUMBL",
45 15: "BTN_THUMBR",
48 axes_map = {
49 "left_stick": {
50 "x": AxisMapping("x"),
51 "y": AxisMapping("y"),
53 "right_stick": {
54 "x": AxisMapping("z"),
55 "y": AxisMapping("Rz"),
59 def __init__(self, rdesc, application="Game Pad", name=None, input_info=None):
60 assert rdesc is not None
61 super().__init__(name, application, input_info=input_info, rdesc=rdesc)
62 self.buttons = (1, 2, 3)
63 self._buttons = {}
64 self.left = (127, 127)
65 self.right = (127, 127)
66 self.hat_switch = 15
67 assert self.parsed_rdesc is not None
69 self.fields = []
70 for r in self.parsed_rdesc.input_reports.values():
71 if r.application_name == self.application:
72 self.fields.extend([f.usage_name for f in r])
74 def store_axes(self, which, gamepad, data):
75 amap = self.axes_map[which]
76 x, y = data
77 setattr(gamepad, amap["x"].hid, x)
78 setattr(gamepad, amap["y"].hid, y)
80 def create_report(
81 self,
83 left=(None, None),
84 right=(None, None),
85 hat_switch=None,
86 buttons=None,
87 reportID=None,
88 application="Game Pad",
90 """
91 Return an input report for this device.
93 :param left: a tuple of absolute (x, y) value of the left joypad
94 where ``None`` is "leave unchanged"
95 :param right: a tuple of absolute (x, y) value of the right joypad
96 where ``None`` is "leave unchanged"
97 :param hat_switch: an absolute angular value of the hat switch
98 (expressed in 1/8 of circle, 0 being North, 2 East)
99 where ``None`` is "leave unchanged"
100 :param buttons: a dict of index/bool for the button states,
101 where ``None`` is "leave unchanged"
102 :param reportID: the numeric report ID for this report, if needed
103 :param application: the application used to report the values
105 if buttons is not None:
106 for i, b in buttons.items():
107 if i not in self.buttons:
108 raise InvalidHIDCommunication(
109 f"button {i} is not part of this {self.application}"
111 if b is not None:
112 self._buttons[i] = b
114 def replace_none_in_tuple(item, default):
115 if item is None:
116 item = (None, None)
118 if None in item:
119 if item[0] is None:
120 item = (default[0], item[1])
121 if item[1] is None:
122 item = (item[0], default[1])
124 return item
126 right = replace_none_in_tuple(right, self.right)
127 self.right = right
128 left = replace_none_in_tuple(left, self.left)
129 self.left = left
131 if hat_switch is None:
132 hat_switch = self.hat_switch
133 else:
134 self.hat_switch = hat_switch
136 reportID = reportID or self.default_reportID
138 gamepad = GamepadData()
139 for i, b in self._buttons.items():
140 gamepad.__setattr__(f"b{i}", int(b) if b is not None else 0)
142 self.store_axes("left_stick", gamepad, left)
143 self.store_axes("right_stick", gamepad, right)
144 gamepad.hatswitch = hat_switch # type: ignore ### gamepad is by default empty
145 return super().create_report(
146 gamepad, reportID=reportID, application=application
149 def event(
150 self, *, left=(None, None), right=(None, None), hat_switch=None, buttons=None
153 Send an input event on the default report ID.
155 :param left: a tuple of absolute (x, y) value of the left joypad
156 where ``None`` is "leave unchanged"
157 :param right: a tuple of absolute (x, y) value of the right joypad
158 where ``None`` is "leave unchanged"
159 :param hat_switch: an absolute angular value of the hat switch
160 where ``None`` is "leave unchanged"
161 :param buttons: a dict of index/bool for the button states,
162 where ``None`` is "leave unchanged"
164 r = self.create_report(
165 left=left, right=right, hat_switch=hat_switch, buttons=buttons
167 self.call_input_event(r)
168 return [r]
171 class JoystickGamepad(BaseGamepad):
172 buttons_map = {
173 1: "BTN_TRIGGER",
174 2: "BTN_THUMB",
175 3: "BTN_THUMB2",
176 4: "BTN_TOP",
177 5: "BTN_TOP2",
178 6: "BTN_PINKIE",
179 7: "BTN_BASE",
180 8: "BTN_BASE2",
181 9: "BTN_BASE3",
182 10: "BTN_BASE4",
183 11: "BTN_BASE5",
184 12: "BTN_BASE6",
185 13: "BTN_DEAD",
188 axes_map = {
189 "left_stick": {
190 "x": AxisMapping("x"),
191 "y": AxisMapping("y"),
193 "right_stick": {
194 "x": AxisMapping("rudder"),
195 "y": AxisMapping("throttle"),
199 def __init__(self, rdesc, application="Joystick", name=None, input_info=None):
200 super().__init__(rdesc, application, name, input_info)
202 def create_report(
203 self,
205 left=(None, None),
206 right=(None, None),
207 hat_switch=None,
208 buttons=None,
209 reportID=None,
210 application=None,
213 Return an input report for this device.
215 :param left: a tuple of absolute (x, y) value of the left joypad
216 where ``None`` is "leave unchanged"
217 :param right: a tuple of absolute (x, y) value of the right joypad
218 where ``None`` is "leave unchanged"
219 :param hat_switch: an absolute angular value of the hat switch
220 where ``None`` is "leave unchanged"
221 :param buttons: a dict of index/bool for the button states,
222 where ``None`` is "leave unchanged"
223 :param reportID: the numeric report ID for this report, if needed
224 :param application: the application for this report, if needed
226 if application is None:
227 application = "Joystick"
228 return super().create_report(
229 left=left,
230 right=right,
231 hat_switch=hat_switch,
232 buttons=buttons,
233 reportID=reportID,
234 application=application,
237 def store_right_joystick(self, gamepad, data):
238 gamepad.rudder, gamepad.throttle = data