Created
November 27, 2018 14:43
-
-
Save ktemkin/22e795e43dac5b9d4a7d07b34275b650 to your computer and use it in GitHub Desktop.
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
# 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