aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py')
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py157
1 files changed, 157 insertions, 0 deletions
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py
new file mode 100644
index 0000000..01a9653
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py
@@ -0,0 +1,157 @@
+# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`Gamepad`
+====================================================
+
+* Author(s): Dan Halbert
+"""
+
+import struct
+import time
+
+from adafruit_hid import find_device
+
+
+class Gamepad:
+ """Emulate a generic gamepad controller with 16 buttons,
+ numbered 1-16, and two joysticks, one controlling
+ ``x` and ``y`` values, and the other controlling ``z`` and
+ ``r_z`` (z rotation or ``Rz``) values.
+
+ The joystick values could be interpreted
+ differently by the receiving program: those are just the names used here.
+ The joystick values are in the range -127 to 127."""
+
+ def __init__(self, devices):
+ """Create a Gamepad object that will send USB gamepad HID reports.
+
+ Devices can be a list of devices that includes a gamepad device or a gamepad device
+ itself. A device is any object that implements ``send_report()``, ``usage_page`` and
+ ``usage``.
+ """
+ self._gamepad_device = find_device(devices, usage_page=0x1, usage=0x05)
+
+ # Reuse this bytearray to send mouse reports.
+ # Typically controllers start numbering buttons at 1 rather than 0.
+ # report[0] buttons 1-8 (LSB is button 1)
+ # report[1] buttons 9-16
+ # report[2] joystick 0 x: -127 to 127
+ # report[3] joystick 0 y: -127 to 127
+ # report[4] joystick 1 x: -127 to 127
+ # report[5] joystick 1 y: -127 to 127
+ self._report = bytearray(6)
+
+ # Remember the last report as well, so we can avoid sending
+ # duplicate reports.
+ self._last_report = bytearray(6)
+
+ # Store settings separately before putting into report. Saves code
+ # especially for buttons.
+ self._buttons_state = 0
+ self._joy_x = 0
+ self._joy_y = 0
+ self._joy_z = 0
+ self._joy_r_z = 0
+
+ # Send an initial report to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self.reset_all()
+ except OSError:
+ time.sleep(1)
+ self.reset_all()
+
+ def press_buttons(self, *buttons):
+ """Press and hold the given buttons."""
+ for button in buttons:
+ self._buttons_state |= 1 << self._validate_button_number(button) - 1
+ self._send()
+
+ def release_buttons(self, *buttons):
+ """Release the given buttons."""
+ for button in buttons:
+ self._buttons_state &= ~(1 << self._validate_button_number(button) - 1)
+ self._send()
+
+ def release_all_buttons(self):
+ """Release all the buttons."""
+
+ self._buttons_state = 0
+ self._send()
+
+ def click_buttons(self, *buttons):
+ """Press and release the given buttons."""
+ self.press_buttons(*buttons)
+ self.release_buttons(*buttons)
+
+ def move_joysticks(self, x=None, y=None, z=None, r_z=None):
+ """Set and send the given joystick values.
+ The joysticks will remain set with the given values until changed
+
+ One joystick provides ``x`` and ``y`` values,
+ and the other provides ``z`` and ``r_z`` (z rotation).
+ Any values left as ``None`` will not be changed.
+
+ All values must be in the range -127 to 127 inclusive.
+
+ Examples::
+
+ # Change x and y values only.
+ gp.move_joysticks(x=100, y=-50)
+
+ # Reset all joystick values to center position.
+ gp.move_joysticks(0, 0, 0, 0)
+ """
+ if x is not None:
+ self._joy_x = self._validate_joystick_value(x)
+ if y is not None:
+ self._joy_y = self._validate_joystick_value(y)
+ if z is not None:
+ self._joy_z = self._validate_joystick_value(z)
+ if r_z is not None:
+ self._joy_r_z = self._validate_joystick_value(r_z)
+ self._send()
+
+ def reset_all(self):
+ """Release all buttons and set joysticks to zero."""
+ self._buttons_state = 0
+ self._joy_x = 0
+ self._joy_y = 0
+ self._joy_z = 0
+ self._joy_r_z = 0
+ self._send(always=True)
+
+ def _send(self, always=False):
+ """Send a report with all the existing settings.
+ If ``always`` is ``False`` (the default), send only if there have been changes.
+ """
+ struct.pack_into(
+ "<Hbbbb",
+ self._report,
+ 0,
+ self._buttons_state,
+ self._joy_x,
+ self._joy_y,
+ self._joy_z,
+ self._joy_r_z,
+ )
+
+ if always or self._last_report != self._report:
+ self._gamepad_device.send_report(self._report)
+ # Remember what we sent, without allocating new storage.
+ self._last_report[:] = self._report
+
+ @staticmethod
+ def _validate_button_number(button):
+ if not 1 <= button <= 16:
+ raise ValueError("Button number must in range 1 to 16")
+ return button
+
+ @staticmethod
+ def _validate_joystick_value(value):
+ if not -127 <= value <= 127:
+ raise ValueError("Joystick value must be in range -127 to 127")
+ return value