I spent far too much time trying to simply get data from an Xbox controller with Python. This is the cleaned up result, classified. This requires xinput1_3 or possibly 1_4 - I'm running Windows 7 and cannot use 1_4.
import ctypes
import threading
import time
xinput = ctypes.windll.xinput1_3
class controller_manager():
def __init__(self,checkfrequency=.2,controllernumber = 0,**kwargs):
""" Xbox 360 controller manager using xinput1_3. kwargs is for functions that should be called on events. If these
are not defined, it will default to setting these values equal to the current value of that piece."""
self.state = xinput_state()
self.controller = controllernumber
self.variables = ["y_button","x_button","b_button","a_button","right_shoulder","left_shoulder","right_bumper","left_bumper",
"right_stick","left_stick","right_dpad","left_dpad","down_dpad","up_dpad","left_trigger","right_trigger",
"thumb_lx","thumb_ly","thumb_rx","thumb_ry"]
for a in kwargs:
setattr(self,a,kwargs[a])
threading.Thread(target=self.control_manager,args=(checkfrequency,)).start()
def control_manager(self,checkfrequency):
defined_funcs = {}
prev_packet = 0
for a in self.variables:
try:
defined_funcs[a] = getattr(self,a)
except AttributeError:
pass
print(defined_funcs)
while 1:
time.sleep(checkfrequency)
xinput.XInputGetState(self.controller,ctypes.pointer(self.state))
if self.state.dwPacketNumber == prev_packet:
continue
prev_packet = self.state.dwPacketNumber
res = self.get_state()
self.state_dict = res
for value in defined_funcs:
defined_funcs[value](res[value])
for value in [a for a in res if not a in defined_funcs]: # we don't want to override user-defined functions
setattr(self,value,res[value])
def vibrate(self,lmotor,rmotor):
vibration_struct = xinput_vibration()
vibration_struct.wLeftMotorSpeed = ctypes.c_ushort(lmotor)
vibration_struct.wRightMotorSpeed = ctypes.c_ushort(rmotor)
xinput.XInputSetState(self.controller,vibration_struct)
def wbuttonstodict(self,wbuttons):
total = 0x10000
dicty = {}
for a in ["y_button","x_button","b_button","a_button","right_shoulder","left_shoulder","right_bumper","left_bumper",
"right_stick","left_stick","right_dpad","left_dpad","down_dpad","up_dpad"]:
total = total >> 1
if wbuttons >= total:
wbuttons -= total
dicty[a] = True
else:
dicty[a] = False
total >> 1
return dicty
def get_state(self):
m = self.wbuttonstodict(self.state.XINPUT_GAMEPAD.wButtons)
for a in ["left_trigger","right_trigger","thumb_lx","thumb_ly","thumb_rx","thumb_ry"]:
m[a] = getattr(self.state.XINPUT_GAMEPAD,a)
return m
class xinput_gamepad(ctypes.Structure):
_fields_ = [("wButtons",ctypes.c_ushort), ("left_trigger",ctypes.c_ubyte), ("right_trigger",ctypes.c_ubyte),("thumb_lx",ctypes.c_short),
("thumb_ly",ctypes.c_short), ("thumb_rx",ctypes.c_short), ("thumb_ry",ctypes.c_short)]
class xinput_state(ctypes.Structure):
_fields_ = [("dwPacketNumber",ctypes.c_uint),
("XINPUT_GAMEPAD",xinput_gamepad)]
class xinput_vibration(ctypes.Structure):
_fields_ = [("wLeftMotorSpeed",ctypes.c_ushort),
("wRightMotorSpeed",ctypes.c_ushort)]