-
Notifications
You must be signed in to change notification settings - Fork 1
/
xbox.py
123 lines (99 loc) · 4.26 KB
/
xbox.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import sys
import signal
import threading
import Queue
from namedtuple import namedtuple
from EventThread import EventThread
def clamp(a, low, high):
return min(max(a, low), high)
def roundBelowToZero(x, threshold):
if abs(x) <= threshold:
return 0
return x
ButtonEvent = namedtuple("ButtonEvent", "button down")
AxisEvent = namedtuple("AxisEvent", "left x y")
DPadEvent = namedtuple("DPadEvent", "x y")
class XboxPadSubscription(EventThread):
AXIS_DEAD_ZONE = 0.1
TRIGGER_ACTIVATION = 0.5
@classmethod
def __getAdjustedAxis(cls, pad, axis):
return roundBelowToZero(clamp(pad.get_axis(axis), -1.0, 1.0), cls.AXIS_DEAD_ZONE)
@classmethod
def __getStickState(cls, pad, axisStart):
return (cls.__getAdjustedAxis(pad, axisStart), cls.__getAdjustedAxis(pad, axisStart+1))
@classmethod
def getStickState(cls, left, pad):
return cls.__getStickState(pad, 0 if left else 2)
def __call__(self):
import pygame
pygame.init()
pygame.joystick.init()
clock = pygame.time.Clock()
# TODO: make configurable
xboxpads = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())]
oldStickState = []
for i, pad in enumerate(xboxpads):
pad.init()
oldStickState.append({ True : self.getStickState(True, pad),
False : self.getStickState(False, pad)})
buttons = { 0 : "A",
1 : "B",
2 : "X",
3 : "Y",
4 : "LB",
5 : "RB",
6 : "Back",
7 : "Start",
8 : "Guide",
9 : "RStick",
10 : "LStick" }
oldTriggerState = { 4 : False, 5 : False}
while self.run:
evlist = pygame.event.get()
for ev in evlist:
if ev.type == pygame.QUIT:
break
elif ev.type == pygame.JOYBUTTONUP:
self.pushQ.put(ButtonEvent(buttons[ev.button], False))
elif ev.type == pygame.JOYBUTTONDOWN:
self.pushQ.put(ButtonEvent(buttons[ev.button], True))
elif ev.type == pygame.JOYAXISMOTION:
joy = pygame.joystick.Joystick(ev.joy)
for stick in [False, True]:
# relay movement if different
newStickState = self.getStickState(stick, joy)
if not newStickState == oldStickState[joy.get_id()][stick]:
self.pushQ.put(AxisEvent(stick, newStickState[0], newStickState[1]))
oldStickState[joy.get_id()][stick] = newStickState
# technically the trigger buttons are axes, but we just care if they're pressed
# for now for simplicity
triggerNames = { 4 : "RT", 5 : "LT" }
for triggerAxis in [4, 5]:
if joy.get_axis(triggerAxis) < self.TRIGGER_ACTIVATION and oldTriggerState[triggerAxis]:
self.pushQ.put(ButtonEvent(triggerNames[triggerAxis], False))
oldTriggerState[triggerAxis] = False
elif joy.get_axis(triggerAxis) >= self.TRIGGER_ACTIVATION and not oldTriggerState[triggerAxis]:
self.pushQ.put(ButtonEvent(triggerNames[triggerAxis], True))
oldTriggerState[triggerAxis] = True
elif ev.type == pygame.JOYHATMOTION:
self.pushQ.put(DPadEvent(*ev.value))
else:
print "Unknown xbox controller event: %s" % (ev,)
try:
clock.tick(20)
except KeyboardInterrupt:
break
pygame.quit()
if __name__ == "__main__":
q = Queue.Queue()
sub = XboxPadSubscription(q)
try:
while True:
# without a timeout, ctrl-c doesn't work because.. python
ONEYEAR = 365 * 24 * 60 * 60
ev = q.get(True, ONEYEAR)
print str(ev)
except KeyboardInterrupt:
sub.stop()
sys.exit()