1
0
mirror of https://github.com/dperelman/wii-u-gc-adapter synced 2019-03-20 22:32:19 -04:00
wii-u-gc-adapter/old/wii-u-gc-adapter.py

231 lines
5.9 KiB
Python
Executable File

#!/usr/bin/env python
# Original Author: Michael Lelli <toadking@toadking.com>
import usb.core
import usb.util
import uinput
import sys
import getopt
if sys.version_info.major < 3:
iteritems = lambda x: x.iteritems()
else:
iteritems = lambda x: x.items()
controllers = [None, None, None, None]
controllers_state = [None, None, None, None]
DIGITAL_BUTTONS = {
uinput.BTN_DPAD_UP: 0x8000,
uinput.BTN_DPAD_DOWN: 0x4000,
uinput.BTN_DPAD_LEFT: 0x1000,
uinput.BTN_DPAD_RIGHT: 0x2000,
uinput.BTN_NORTH: 0x0800,
uinput.BTN_SOUTH: 0x0100,
uinput.BTN_EAST: 0x0400,
uinput.BTN_WEST: 0x0200,
uinput.BTN_START: 0x0001,
uinput.BTN_TL: 0x0008,
uinput.BTN_TR: 0x0004,
uinput.BTN_TR2: 0x0002
}
AXIS_BYTES = {
uinput.ABS_X: 3,
uinput.ABS_Y: 4,
uinput.ABS_RX: 5,
uinput.ABS_RY: 6,
uinput.ABS_Z: 7,
uinput.ABS_RZ: 8
}
STATE_NORMAL = 0x10
STATE_WAVEBIRD = 0x20
def controller_type(status):
return status & (STATE_NORMAL | STATE_WAVEBIRD)
def is_connected(status):
return status & (STATE_NORMAL | STATE_WAVEBIRD) in (STATE_NORMAL, STATE_WAVEBIRD)
def controller_type_string(controller_type):
if controller_type == STATE_NORMAL:
return "GameCube Controller"
elif controller_type == STATE_WAVEBIRD:
return "WaveBird Controller"
else:
return "Unknown Controller"
def create_device(index, status, raw):
if raw:
axis_cal = (0, 255, 0, 0)
cstick_cal = (0, 255, 0, 0)
trigger_cal = (0, 255, 0, 0)
else:
axis_cal = (20, 235, 0, 0)
cstick_cal = (30, 225, 0, 0)
trigger_cal = (25, 225, 0, 0)
events = (
uinput.BTN_NORTH,
uinput.BTN_SOUTH,
uinput.BTN_EAST,
uinput.BTN_WEST,
uinput.BTN_START,
uinput.BTN_DPAD_UP,
uinput.BTN_DPAD_DOWN,
uinput.BTN_DPAD_LEFT,
uinput.BTN_DPAD_RIGHT,
uinput.ABS_X + axis_cal,
uinput.ABS_Y + axis_cal,
uinput.ABS_RX + cstick_cal,
uinput.ABS_RY + cstick_cal,
uinput.BTN_TL,
uinput.ABS_Z + trigger_cal,
uinput.BTN_TR,
uinput.ABS_RZ + trigger_cal,
uinput.BTN_TR2
)
controllers[index] = uinput.Device(events, name="Wii U GameCube Adapter Port {}".format(index+1))
controllers_state[index] = (
controller_type(status),
0,
{
uinput.ABS_X: -1,
uinput.ABS_Y: -1,
uinput.ABS_RX: -1,
uinput.ABS_RY: -1,
uinput.ABS_Z: -1,
uinput.ABS_RZ: -1
}
)
print("{} connected on port {}".format(controller_type_string(controllers_state[index][0]), index+1))
def destroy_device(index):
print("disconnecting {} on port {}".format(controller_type_string(controllers_state[index][0]), index+1))
controllers[index] = None
def help():
print("usage: " + sys.argv[0] + " [-h/--help] [-r/--raw]\n\n"
" -h/--help: display this message\n"
" -r/--raw: do not do scaling on axis")
sys.exit(-1)
def main():
dev = usb.core.find(idVendor=0x057e, idProduct=0x0337)
raw_mode = False
try:
opts, args = getopt.getopt(sys.argv[1:], "hr", ["help", "raw"])
except getopt.GetoptError:
help()
for opt, arg in opts:
if opt in ("-h", "--help"):
help()
elif opt in ("-r", "--raw"):
print("raw mode")
raw_mode = True
if dev is None:
raise ValueError('GC adapter not found')
if dev.is_kernel_driver_active(0):
reattach = True
dev.detach_kernel_driver(0)
dev.set_configuration()
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
out_ep = usb.util.find_descriptor(
intf,
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
in_ep = usb.util.find_descriptor(
intf,
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
# might not be necessary, but doesn't hurt
dev.ctrl_transfer(0x21, 11, 0x0001, 0, [])
out_ep.write([0x13])
try:
while 1:
try:
data = in_ep.read(37)
except (KeyboardInterrupt, SystemExit):
raise
except:
print("read error")
continue
if data[0] != 0x21:
print("unknown message {:02x}}".format(data[0]))
continue
payloads = [data[1:10], data[10:19], data[19:28], data[28:37]]
index = 0
for i, d in enumerate(payloads):
status = d[0]
# check for connected
if is_connected(status) and controllers[i] is None:
create_device(i, status, raw_mode)
elif not is_connected(status) and controllers[i] is not None:
destroy_device(i)
if controllers[i] is None:
continue
# if status & 0x04 != 0:
# do something about having both USB plugs connected
if controller_type(status) != controllers_state[i][0]:
print("controller on port {} changed from {} to {}???".format(i+1,
controller_type_string(controllers_state[i][0]), controller_type_string(controller_type(status))))
btns = d[1] << 8 | d[2]
newmask = 0
for btn, mask in iteritems(DIGITAL_BUTTONS):
pressed = btns & mask
newmask |= pressed
# state change
if controllers_state[i][1] & mask != pressed:
controllers[i].emit(btn, 1 if pressed != 0 else 0, syn=False)
newaxis = {}
for axis, offset in iteritems(AXIS_BYTES):
value = d[offset]
newaxis[axis] = value
if axis == uinput.ABS_Y or axis == uinput.ABS_RY:
# flip from 0 - 255 to 255 - 0
value ^= 0xFF
#elif axis == uinput.ABS_RZ or axis == uinput.ABS_Z:
# scale from 0 - 255 to 127 - 255
#value = (value >> 1) + 127
if controllers_state[i][2][axis] != value:
controllers[i].emit(axis, value, syn=False)
controllers[i].syn()
controllers_state[i] = (
controller_type(status),
newmask,
newaxis
)
except:
raise
if __name__ == "__main__":
main()