Skip to content

Instantly share code, notes, and snippets.

@pickeditmate
Forked from ktemkin/USBSwitchRandomizer.py
Created February 6, 2023 19:48
Show Gist options
  • Save pickeditmate/6cfdba43c67ede506447f9d8f5aa9c4d to your computer and use it in GitHub Desktop.
Save pickeditmate/6cfdba43c67ede506447f9d8f5aa9c4d to your computer and use it in GitHub Desktop.
# USBKeyboard.py
#
# Contains class definitions to implement a USB keyboard.
import greatfet
import random
import inputs
from facedancer.USB import *
from facedancer.USBDevice import *
from facedancer.USBConfiguration import *
from facedancer.USBInterface import *
from facedancer.USBEndpoint import *
class USBSwitchTASInterface(USBInterface):
name = "Switch TAS Interface"
input = [b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00',
b'\x00\x00\x0f\x80\x80\x80\x80\x00']
# copied from the horipad
hid_descriptor = b'\x09\x21\x11\x01\x00\x01\x22\x50\x00'
report_descriptor = b'\x05\x01\t\x05\xa1\x01\x15\x00%\x015\x00E\x01u\x01\x95\x0e\x05\t\x19\x01)\x0e\x81\x02\x95\x02\x81\x01\x05\x01%\x07F;\x01u\x04\x95\x01e\x14\t9\x81Be\x00\x95\x01\x81\x01&\xff\x00F\xff\x00\t0\t1\t2\t5u\x08\x95\x04\x81\x02u\x08\x95\x01\x81\x01\xc0'
def __init__(self, verbose=0):
descriptors = {
USB.desc_type_hid : self.hid_descriptor,
USB.desc_type_report : self.report_descriptor
}
self.out_endpoint = USBEndpoint(
2, # endpoint number
USBEndpoint.direction_out,
USBEndpoint.transfer_type_interrupt,
USBEndpoint.sync_type_none,
USBEndpoint.usage_type_data,
64, # max packet size
5, # polling interval, see USB 2.0 spec Table 9-13
self.handle_out_data # handler function
)
self.endpoint = USBEndpoint(
1, # endpoint number
USBEndpoint.direction_in,
USBEndpoint.transfer_type_interrupt,
USBEndpoint.sync_type_none,
USBEndpoint.usage_type_data,
64, # max packet size
5, # polling interval, see USB 2.0 spec Table 9-13
#None,
self.handle_buffer_available # handler function
)
# TODO: un-hardcode string index (last arg before "verbose")
USBInterface.__init__(
self,
0, # interface number
0, # alternate setting
3, # interface class
0, # subclass
0, # protocol
0, # string index
verbose,
[ self.out_endpoint, self.endpoint ],
descriptors
)
self.packets_to_send = self.input
self.counter = 0
MINUS = 0x0001
PLUS = 0x0002
L3 = 0x0004
R3 = 0x0008
HOME = 0x0010
CAPTURE = 0x0020
# probably SL and SR?
Y = 0x0100
B = 0x0200
A = 0x0400
X = 0x0800
L = 0x1000
R = 0x2000
ZL = 0x4000
ZR = 0x8000
DPAD_UP = 0x0
DPAD_RIGHT = 0x2
DPAD_DOWN = 0x4
DPAD_LEFT = 0x6
self.direction_interval = 32
self.fast_button_interval = 16
self.slow_button_interval = 32
self.rare_button_interval = 256
# odyssey
self.fast_button_mask = A | L | R
self.slow_button_mask = B | X | Y
self.rare_button_mask = ZL | ZR
# botw
self.fast_button_mask = X | B | L | Y
self.slow_button_mask = L | A | Y
self.rare_button_mask = ZL | ZR
# minecraft
self.fast_button_mask = A | ZL | ZR | L | R
self.slow_button_mask = L | R |B
self.rare_button_mask = X | Y
self.randomize_buttons_fast()
self.randomize_buttons_slow()
self.randomize_buttons_rare()
self.randomize_directions()
def randomize_directions(self):
min = 0x40
max = 0xc0
self.random_dir_y = random.randint(self.bias_low, self.bias_high)
self.random_dir_x = random.randint(min, max)
self.random_dir_z = random.randint(min, max)
self.random_dir_w = random.randint(min, max)
def randomize_buttons_fast(self):
self.random_buttons_fast = random.randint(0, 65535) & self.fast_button_mask
def randomize_buttons_slow(self):
self.random_buttons_slow = random.randint(0, 65535) & self.slow_button_mask
def randomize_buttons_rare(self):
self.random_buttons_rare = random.randint(0, 65535) & self.rare_button_mask
bias_type = random.randint(0, 3)
self.override_type = random.randint(0, 2)
if bias_type == 0:
self.bias_low = random.randint(0xc0, 0xff)
self.bias_high = 255
else:
self.bias_low = 0
self.bias_high = random.randint(0, 0x40)
def handle_buffer_available(self):
# two bytes buttons
# hat switch
# four joysticks
# one byte padding
min = 0
max = 255
self.counter += 1
if (self.counter % self.direction_interval) == 0:
self.randomize_directions()
if (self.counter % self.fast_button_interval) == 0:
self.randomize_buttons_fast()
if (self.counter % self.slow_button_interval) == 0:
self.randomize_buttons_slow()
if (self.counter % self.rare_button_interval) == 0:
self.randomize_buttons_rare()
random_dir = self.random_dir_x.to_bytes(1, byteorder='little') + self.random_dir_y.to_bytes(1, byteorder='little')
random_dir += self.random_dir_w.to_bytes(1, byteorder='little') + self.random_dir_w.to_bytes(1, byteorder='little')
MINUS = 0x0001
PLUS = 0x0002
L3 = 0x0004
R3 = 0x0008
HOME = 0x0010
CAPTURE = 0x0020
# probably SL and SR?
Y = 0x0100
B = 0x0200
A = 0x0400
X = 0x0800
L = 0x1000
R = 0x2000
ZL = 0x4000
ZR = 0x8000
DPAD_UP = 0x0
DPAD_RIGHT = 0x2
DPAD_DOWN = 0x4
DPAD_LEFT = 0x6
lookup = {
'BTN_C': A,
'BTN_EAST': B,
'BTN_SOUTH': Y,
'BTN_NORTH': X,
'BTN_TR2': PLUS,
'BTN_TL2': MINUS,
'BTL_TL': ZL,
'BTL_TR': ZL,
'BTL_WEST': L,
'BTL_Z': R,
'BTN_SELECT': L3,
'BTN_START': R3,
}
if self.override_type:
random_buttons_raw = self.random_buttons_fast
else:
random_buttons_raw = self.random_buttons_fast | self.random_buttons_slow | self.random_buttons_rare
#try:
# events = inputs.devices.gamepads[0].read()
# if events:
# random_buttons_raw = 0
# for ev in events:
# if ev.ev_type == 'Key':
# random_buttons_raw |= lookup[ev.code]
# if ev.ev_type == 'Absolute':
# if ev.code == 'ABS_X':
# random_x_raw = ev.state
# elif ev.code == 'ABS_Y':
# random_y_raw = ev.state
# elif ev.code == 'ABS_Z':
# random_z_raw = ev.state
# elif ev.code == 'ABS_RZ':
# random_w_raw = ev.state
#except Exception as e:
# print(e)
random_buttons = random_buttons_raw.to_bytes(2, byteorder='big')
#if self.packets_to_send:
# to_send = self.packets_to_send.pop(0)
# self.endpoint.send(to_send)
self.endpoint.send(random_buttons + b'\x0f' + random_dir + b'\x00')
def handle_out_data(self, data):
print("??? Got out data! {}".format(data))
class USBSwitchTASDevice(USBDevice):
name = "USB keyboard device"
def __init__(self, maxusb_app, verbose=0):
config = USBConfiguration(
1, # index
None, # string desc
[ USBSwitchTASInterface() ], # interfaces
0x80, # attributes
250 # power
)
USBDevice.__init__(
self,
maxusb_app,
0, # device class
0, # device subclass
0, # protocol release number
64, # max packet size for endpoint 0
0x0f0d, # vendor id
0x00c1, # product id
0x0572, # device revision
"HORI CO.,LTD.", # manufacturer string
"HORIPAD S", # product string
None, # serial number string
[ config ],
verbose=verbose
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment