-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Gamecontroller setup under mac #126
Comments
code.py import board
import usb_hid
import board
from micropython import const
from hid_gamepad import Gamepad
gp = Gamepad(usb_hid.devices)
from adafruit_seesaw.seesaw import Seesaw
# Equivalent of Arduino's map() function.
def range_map(x, in_min, in_max, out_min, out_max):
return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
BUTTON_X = const(6)
BUTTON_Y = const(2)
BUTTON_A = const(5)
BUTTON_B = const(1)
BUTTON_SELECT = const(0)
BUTTON_START = const(16)
button_mask = const(
(1 << BUTTON_X)
| (1 << BUTTON_Y)
| (1 << BUTTON_A)
| (1 << BUTTON_B)
| (1 << BUTTON_SELECT)
| (1 << BUTTON_START)
)
i2c_bus = board.STEMMA_I2C() # The built-in STEMMA QT connector on the microcontroller
# i2c_bus = board.I2C() # Uses board.SCL and board.SDA. Use with breadboard.
gamepad1 = Seesaw(i2c_bus, addr=0x50)
gamepad1.pin_mode_bulk(button_mask, gamepad1.INPUT_PULLUP)
# Equivalent of Arduino's map() function.
def range_map(x, in_min, in_max, out_min, out_max):
return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
last_x = 0
last_y = 0
while True:
x = 1023 - gamepad1.analog_read(14)
y = 1023 - gamepad1.analog_read(15)
if (abs(x - last_x) > 3) or (abs(y - last_y) > 3):
print(x, y)
last_x = x
last_y = y
buttons = gamepad1.digital_read_bulk(button_mask)
if not buttons & (1 << BUTTON_X):
print("Button x pressed")
gp.click_buttons(5)
# # Buttons are grounded when pressed (.value = False).
# for i, button in enumerate(buttons):
# gamepad_button_num = gamepad_buttons[i]
# if button.value:
# gp.release_buttons(gamepad_button_num)
# print(" release", gamepad_button_num, end="")
# else:
# gp.press_buttons(gamepad_button_num)
# print(" press", gamepad_button_num, end="")
# Convert range[0, 65535] to -127 to 127
gp.move_joysticks(
x=range_map(x, 0, 1023, -127, 127),
y=range_map(y, 0, 1023, -127, 127),
)
# print(" x", ax.value, "y", ay.value) boot.py import usb_hid
# This is only one example of a gamepad report descriptor,
# and may not suit your needs.
GAMEPAD_REPORT_DESCRIPTOR = bytes((
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x05, # Usage (Game Pad)
0xA1, 0x01, # Collection (Application)
0x85, 0x04, # Report ID (4)
0x05, 0x09, # Usage Page (Button)
0x19, 0x01, # Usage Minimum (Button 1)
0x29, 0x10, # Usage Maximum (Button 16)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x10, # Report Count (16)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x15, 0x81, # Logical Minimum (-127)
0x25, 0x7F, # Logical Maximum (127)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x09, 0x32, # Usage (Z)
0x09, 0x35, # Usage (Rz)
0x75, 0x08, # Report Size (8)
0x95, 0x04, # Report Count (4)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
))
gamepad = usb_hid.Device(
report_descriptor=GAMEPAD_REPORT_DESCRIPTOR,
usage_page=0x01, # Generic Desktop Control
usage=0x05, # Gamepad
report_ids=(4,), # Descriptor uses report ID 4.
in_report_lengths=(6,), # This gamepad sends 6 bytes in its report.
out_report_lengths=(0,), # It does not receive any reports.
)
usb_hid.enable(
(usb_hid.Device.KEYBOARD,
usb_hid.Device.MOUSE,
usb_hid.Device.CONSUMER_CONTROL,
gamepad)
) |
Check that Try this also on a Windows machine, if you have one, and see if it shows up. |
Thanks for the quick reply!
I cannot test this on a windows machine. |
I put your boot.py on a CircuitPython board. It works, and presents a gamepad device, which the OS is aware of. This is true on Linux, Windows, and macOS Sonoma 14.5 (I tested on an M1 Mac Mini). I verified the gamepad's presence with this tool: % hidapitester --vidpid 239a --list-detail
[other stuff omitted]
239A/8100: Adafruit Industries LLC - NeoKey Trinkey M0
vendorId: 0x239A
productId: 0x8100
usagePage: 0x0001
usage: 0x0005
serial_number: D517091D4C51535020312E37301619FF
interface: 3
path: DevSrvsID:4294974679 However, the question is what macOS is going to do with the gamepad, whether the game can find it, and what your game is expecting. That I don't know, unfortunately. We found in the past that which gamepads are usable on which OS's varies. It can even depend on the range of the X/Y/Z values. You might ask in our discord, https://adafru.it/discord, whether anyone has succeeded in making a usable gamepad on macOS |
Here is another "proof of life" for the Gamepad controller. I installed a free app, Controllers Lite, from the App Store. You have to give it permission to monitor input events (when you run it the first time it will be obvious what to do, I think). Here you can see that it is seeing the Gamepad in boot.py: A hypothesis is that your game doesn't like this particular gamepad definition, for some reason. If you know of a gamepad that works with the game, you could find out its HID report descriptor and emulate that. I know there are also remappers that will transform one kind of gamepad into another, though I know very little about them other than that they exist. |
Thanks for the input, this is great. I am trying to run STEAM games, but those do not recognize my (custom) controller as valid input device, nor does STEAM itself. I have reached out on Discord, hoping somebody tried something similar. Also tried https://steamcommunity.com/discussions/forum/2/3117025249776480006/?ctp=6 |
I have not gotten much further on this. Any input would be appreciated! |
Hi I know I'm pretty late on this and I haven't quite broken through to getting things to work fully, but I managed to get Final Fantasy XIV to recognize my device as a GamePad by setting a BLE Vendor ID and Product ID. I haven't made my jump to macOS Sequoia just yet so I can't confirm if this will work but maybe using As for my current status, I have been able to get my mac to recognize my gamepad by haven't been able to actually send reports that yield any action in game yet. I've confirmed that the reports are being received on the mac using the https://hardwaretester.com/gamepad website so my current hypothesis is that the game requires a properly crafted HID descriptor to accept input. FYI here's the descriptor that I'm trying to get to work for Vendor ID GAMEPAD_REPORT_DESCRIPTOR = bytes([
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x05, # Usage (Game Pad)
0xA1, 0x01, # Collection (Application)
0x85, 0x01, # Report ID (1)
0x09, 0x01, # Usage (Pointer)
0xA1, 0x00, # Collection (Physical)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x15, 0x00, # Logical Minimum (0)
0x27, 0xFF, 0xFF, 0x00, 0x00, # Logical Maximum (65534)
0x95, 0x02, # Report Count (2)
0x75, 0x10, # Report Size (16)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
0x09, 0x01, # Usage (Pointer)
0xA1, 0x00, # Collection (Physical)
0x09, 0x33, # Usage (Rx)
0x09, 0x34, # Usage (Ry)
0x15, 0x00, # Logical Minimum (0)
0x27, 0xFF, 0xFF, 0x00, 0x00, # Logical Maximum (65534)
0x95, 0x02, # Report Count (2)
0x75, 0x10, # Report Size (16)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
0x05, 0x02, # Usage Page (Generic Desktop Ctrls)
0x09, 0x32, # Usage (Z)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x03, # Logical Maximum (1023)
0x95, 0x01, # Report Count (1)
0x75, 0x0A, # Report Size (10)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x00, # Logical Maximum (0)
0x75, 0x06, # Report Size (6)
0x95, 0x01, # Report Count (1)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x35, # Usage (Rz)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x03, # Logical Maximum (1023)
0x95, 0x01, # Report Count (1)
0x75, 0x0A, # Report Size (10)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x00, # Logical Maximum (0)
0x75, 0x06, # Report Size (6)
0x95, 0x01, # Report Count (1)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x39, # Usage (Hat switch)
0x15, 0x01, # Logical Minimum (1)
0x25, 0x08, # Logical Maximum (8)
0x35, 0x00, # Physical Minimum (0)
0x46, 0x3B, 0x01, # Physical Maximum (315)
0x66, 0x14, 0x00, # Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, # Report Size (4)
0x95, 0x01, # Report Count (1)
0x81, 0x42, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x75, 0x04, # Report Size (4)
0x95, 0x01, # Report Count (1)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x00, # Logical Maximum (0)
0x35, 0x00, # Physical Minimum (0)
0x45, 0x00, # Physical Maximum (0)
0x65, 0x00, # Unit (None)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x09, # Usage Page (Button)
0x19, 0x01, # Usage Minimum (0x01)
0x29, 0x0A, # Usage Maximum (0x0A)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x0A, # Report Count (10)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x00, # Logical Maximum (0)
0x75, 0x06, # Report Size (6)
0x95, 0x01, # Report Count (1)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x80, # Usage (Sys Control)
0x85, 0x02, # Report ID (2)
0xA1, 0x00, # Collection (Physical)
0x09, 0x85, # Usage (Sys Main Menu)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x95, 0x01, # Report Count (1)
0x75, 0x01, # Report Size (1)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x00, # Logical Maximum (0)
0x75, 0x07, # Report Size (7)
0x95, 0x01, # Report Count (1)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
0x05, 0x0F, # Usage Page (PID Page)
0x09, 0x21, # Usage (0x21)
0x85, 0x03, # Report ID (3)
0xA1, 0x02, # Collection (Logical)
0x09, 0x97, # Usage (0x97)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x04, # Report Size (4)
0x95, 0x01, # Report Count (1)
0x91, 0x02, # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x00, # Logical Maximum (0)
0x75, 0x04, # Report Size (4)
0x95, 0x01, # Report Count (1)
0x91, 0x03, # Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x70, # Usage (0x70)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x64, # Logical Maximum (100)
0x75, 0x08, # Report Size (8)
0x95, 0x04, # Report Count (4)
0x91, 0x02, # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x50, # Usage (0x50)
0x66, 0x01, 0x10, # Unit (System: SI Linear, Time: Seconds)
0x55, 0x0E, # Unit Exponent (-2)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x00, # Logical Maximum (255)
0x75, 0x08, # Report Size (8)
0x95, 0x01, # Report Count (1)
0x91, 0x02, # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0xA7, # Usage (0xA7)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x00, # Logical Maximum (255)
0x75, 0x08, # Report Size (8)
0x95, 0x01, # Report Count (1)
0x91, 0x02, # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x65, 0x00, # Unit (None)
0x55, 0x00, # Unit Exponent (0)
0x09, 0x7C, # Usage (0x7C)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x00, # Logical Maximum (255)
0x75, 0x08, # Report Size (8)
0x95, 0x01, # Report Count (1)
0x91, 0x02, # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, # End Collection
0x85, 0x04, # Report ID (4)
0x05, 0x06, # Usage Page (Generic Dev Ctrls)
0x09, 0x20, # Usage (Battery Strength)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x00, # Logical Maximum (255)
0x75, 0x08, # Report Size (8)
0x95, 0x01, # Report Count (1)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
]) |
Hi a very quick update indeed: I got this to work and it was just as I speculated! |
I am using https://learn.adafruit.com/gamepad-qt with https://learn.adafruit.com/esp32-s3-reverse-tft-feather.
My goal is to let the gamepad be recognized as gamecontroller input on my Mac to play a game with it.
I have looked at the gamepad example here: https://docs.circuitpython.org/projects/hid/en/latest/examples.html#id4
and added the gamepad boiler plate code shown here: https://learn.adafruit.com/customizing-usb-devices-in-circuitpython/hid-devices#custom-hid-devices-3096614-9 to my boot.py.
This doesn't run into any errors, but also does not lead to recognition of a gamecontroller as input device under MacOS.
Has anybody tried this?
The text was updated successfully, but these errors were encountered: