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

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

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

  1 # SPDX-License-Identifier: GPL-2.0
  2 import libevdev
  3 
  4 from .base_device import BaseDevice
  5 from hidtools.util import BusType
  6 
  7 
  8 class InvalidHIDCommunication(Exception):
  9     pass
 10 
 11 
 12 class GamepadData(object):
 13     pass
 14 
 15 
 16 class AxisMapping(object):
 17     """Represents a mapping between a HID type
 18     and an evdev event"""
 19 
 20     def __init__(self, hid, evdev=None):
 21         self.hid = hid.lower()
 22 
 23         if evdev is None:
 24             evdev = f"ABS_{hid.upper()}"
 25 
 26         self.evdev = libevdev.evbit("EV_ABS", evdev)
 27 
 28 
 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",
 46     }
 47 
 48     axes_map = {
 49         "left_stick": {
 50             "x": AxisMapping("x"),
 51             "y": AxisMapping("y"),
 52         },
 53         "right_stick": {
 54             "x": AxisMapping("z"),
 55             "y": AxisMapping("Rz"),
 56         },
 57     }
 58 
 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
 68 
 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])
 73 
 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)
 79 
 80     def create_report(
 81         self,
 82         *,
 83         left=(None, None),
 84         right=(None, None),
 85         hat_switch=None,
 86         buttons=None,
 87         reportID=None,
 88         application="Game Pad",
 89     ):
 90         """
 91         Return an input report for this device.
 92 
 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
104         """
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}"
110                     )
111                 if b is not None:
112                     self._buttons[i] = b
113 
114         def replace_none_in_tuple(item, default):
115             if item is None:
116                 item = (None, None)
117 
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])
123 
124             return item
125 
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
130 
131         if hat_switch is None:
132             hat_switch = self.hat_switch
133         else:
134             self.hat_switch = hat_switch
135 
136         reportID = reportID or self.default_reportID
137 
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)
141 
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
147         )
148 
149     def event(
150         self, *, left=(None, None), right=(None, None), hat_switch=None, buttons=None
151     ):
152         """
153         Send an input event on the default report ID.
154 
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"
163         """
164         r = self.create_report(
165             left=left, right=right, hat_switch=hat_switch, buttons=buttons
166         )
167         self.call_input_event(r)
168         return [r]
169 
170 
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",
186     }
187 
188     axes_map = {
189         "left_stick": {
190             "x": AxisMapping("x"),
191             "y": AxisMapping("y"),
192         },
193         "right_stick": {
194             "x": AxisMapping("rudder"),
195             "y": AxisMapping("throttle"),
196         },
197     }
198 
199     def __init__(self, rdesc, application="Joystick", name=None, input_info=None):
200         super().__init__(rdesc, application, name, input_info)
201 
202     def create_report(
203         self,
204         *,
205         left=(None, None),
206         right=(None, None),
207         hat_switch=None,
208         buttons=None,
209         reportID=None,
210         application=None,
211     ):
212         """
213         Return an input report for this device.
214 
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
225         """
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,
235         )
236 
237     def store_right_joystick(self, gamepad, data):
238         gamepad.rudder, gamepad.throttle = data

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

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

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

sflogo.php