pretend to be a Playstation DS4 controller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ds4_fakey_boot.py -- pretend to be a Playstation DS4 controller, using MacroPad RP2040 | |
# doesn't quite seem to work yet | |
# 8 Jan 2023 - @todbot / Tod Kurt | |
import usb_hid | |
import usb_midi | |
import supervisor | |
ds4_vid = 0x054C | |
ds4_pid = 0x05C4 | |
ds4_mfg_str = "JP Fakey Corp" | |
ds4_prod_str = "JP Fakey DS4" | |
usb_midi.disable() | |
# abbreviated from https://gimx.fr/wiki/index.php?title=DualShock_4 | |
GAMEPAD_DS4_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, 0x30, # Usage (X) | |
0x09, 0x31, # Usage (Y) | |
0x09, 0x32, # Usage (Z) | |
0x09, 0x35, # Usage (Rz) | |
0x15, 0x00, # Logical Minimum (0) | |
0x26, 0xFF, 0x00, # Logical Maximum (255) | |
0x75, 0x08, # Report Size (8) | |
0x95, 0x04, # Report Count (4) | |
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x09, 0x39, # Usage (Hat switch) | |
0x15, 0x00, # Logical Minimum (0) | |
0x25, 0x07, # Logical Maximum (7) | |
0x35, 0x00, # Physical Minimum (0) | |
0x46, 0x3B, 0x01, # Physical Maximum (315) | |
0x65, 0x14, # 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) | |
0x65, 0x00, # Unit (None) | |
0x05, 0x09, # Usage Page (Button) | |
0x19, 0x01, # Usage Minimum (0x01) | |
0x29, 0x0E, # Usage Maximum (0x0E) | |
0x15, 0x00, # Logical Minimum (0) | |
0x25, 0x01, # Logical Maximum (1) | |
0x75, 0x01, # Report Size (1) | |
0x95, 0x0E, # Report Count (14) | |
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x06, 0x00, 0xFF, # Usage Page (Vendor Defined 0xFF00) | |
0x09, 0x20, # Usage (0x20) | |
0x75, 0x06, # Report Size (6) | |
0x95, 0x01, # Report Count (1) | |
0x15, 0x00, # Logical Minimum (0) | |
0x25, 0x7F, # Logical Maximum (127) | |
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x05, 0x01, # Usage Page (Generic Desktop Ctrls) | |
0x09, 0x33, # Usage (Rx) | |
0x09, 0x34, # Usage (Ry) | |
0x15, 0x00, # Logical Minimum (0) | |
0x26, 0xFF, 0x00, # Logical Maximum (255) | |
0x75, 0x08, # Report Size (8) | |
0x95, 0x02, # Report Count (2) | |
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x06, 0x00, 0xFF, # Usage Page (Vendor Defined 0xFF00) | |
0x09, 0x21, # Usage (0x21) | |
0x95, 0x36, # Report Count (54) | |
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0xC0, # End Collection | |
)) | |
print("setting new vid/pid") | |
supervisor.set_usb_identification(vid=ds4_vid, pid=ds4_pid, manufacturer=ds4_mfg_str, product=ds4_prod_str) | |
print("setting up gamepad hid descriptor") | |
gamepad_ds4 = usb_hid.Device( | |
report_descriptor=GAMEPAD_DS4_REPORT_DESCRIPTOR, | |
usage_page=0x01, # Generic Desktop Control (must match byte1 of above) | |
usage=0x05, # Gamepad (must match byte3 of above) | |
report_ids=(1,), # Descriptor uses report ID 1. | |
in_report_lengths=(64,), # This gamepad sends 64 bytes in its report. | |
out_report_lengths=(0,), # It does not receive any reports. | |
) | |
usb_hid.enable( (gamepad_ds4,) ) | |
print("boot.py done") | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ds4_fakey_code.py -- pretend to be a Playstation DS4 controller, using MacroPad RP2040 | |
# doesn't quite seem to work yet | |
# 8 Jan 2023 - @todbot / Tod Kurt | |
# Also need to install accompanying "boot.py" and press RESET to load it | |
import time | |
import board, keypad | |
import neopixel | |
import usb_hid | |
import adafruit_hid | |
leds = neopixel.NeoPixel(board.NEOPIXEL, 12, brightness=0.2, auto_write=True) | |
leds.fill(0x111111); | |
key_pins = (board.KEY1, board.KEY2, board.KEY3, | |
board.KEY4, board.KEY5, board.KEY6, | |
board.KEY7, board.KEY8, board.KEY9, | |
board.KEY10, board.KEY11, board.KEY12) | |
keys = keypad.Keys(key_pins, value_when_pressed=False, pull=True) | |
gamepad = adafruit_hid.find_device(usb_hid.devices, usage_page=0x1, usage=0x05) | |
key_U = 7 # aka "board.KEY8" (0-indexed) | |
key_D = 10 | |
key_L = 9 | |
key_R = 11 | |
key_TRI = 1 | |
key_CIR = 2 | |
key_XXX = 4 | |
key_SQR = 5 | |
for l in (key_U, key_D, key_L, key_R): | |
leds[l] = 0xFF0000 | |
for l in (key_TRI, key_CIR, key_XXX, key_SQR): | |
leds[l] = 0x00FF00 | |
# for sending HID report | |
report = bytearray(64) | |
buttons = 0x00 | |
dpad = 0x08 # no press | |
def set_key(keynum,pressed): | |
global dpad, buttons | |
dpad = 0x08 # no press | |
buttons = 0x00 # no press | |
if not pressed: return # for now | |
if keynum == key_U: dpad = 0x00 | |
elif keynum == key_L: dpad = 0x06 | |
elif keynum == key_D: dpad = 0x04 | |
elif keynum == key_R: dpad = 0x02 | |
elif keynum == key_TRI: buttons = 0x80 | |
elif keynum == key_CIR: buttons = 0x40 | |
elif keynum == key_XXX: buttons = 0x20 | |
elif keynum == key_SQR: buttons = 0x10 | |
def send_report(): | |
report[0] = 127 # left stick X, 0=left | |
report[1] = 127 # left stick Y, 0=up | |
report[2] = 127 # right stick X | |
report[3] = 127 # right stick Y | |
report[4] = buttons | dpad # buttons and dpad | |
report[5] = 0x00 # buttons R3, L3, OPT, Share, R2, L2, R1, L1 | |
report[6] = 0x00 # counter (should go up one per report?) | |
report[7] = 0x00 # left trigger (0-ff) | |
report[8] = 0x00 # right trigger | |
gamepad.send_report(report) | |
while True: | |
key = keys.events.get() | |
if key: | |
keynum = key.key_number | |
press = key.pressed | |
set_key(keynum, press) | |
print("key:",keynum, press, hex(buttons), hex(dpad)) | |
send_report() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment