1 # -*- coding: utf-8 -*-
3 wiimote -> mouse interface
9 from threading
import Thread
10 from Queue
import Queue
, Empty
13 # events to use. Is there a way to get ones known to be unused?
16 wiiuse
= None # import within the thread, why do I have to do this?
18 class wiimote_thread(Thread
):
19 '''Manage the wiiuse interface'''
21 def __init__(self
, nmotes
=1, timeout
=5, screenResolution
=(660, 370), position
='ABOVE'):
22 Thread
.__init
__(self
, name
='wiimote')
24 self
.startup
= Queue()
26 self
.timeout
= timeout
27 self
.screenResolution
= screenResolution
28 self
.position
= position
29 self
.selectedWiimoteIndex
= 0
33 self
.startup
.get(True) # wait for the thread to get started and acquire the motes
34 self
.eventCallBack
= _default_event_cb
36 def setEventCallBack(self
, func
) :
37 self
.eventCallBack
= func
40 '''This runs in a separate thread'''
42 import PyWiiUse
as wiiuse
# import here to avoid thread problems on windows
43 self
.wiimotes
= wiiuse
.init(self
.nmotes
)
44 found
= wiiuse
.find(self
.wiimotes
, self
.nmotes
, self
.timeout
)
45 self
.actual_nmotes
= wiiuse
.connect(self
.wiimotes
, self
.nmotes
)
49 for i
in range(self
.nmotes
):
50 wiiuse
.set_leds(self
.wiimotes
[i
], wiiuse
.LED
[i
])
53 wiiuse
.set_leds(self
.wiimotes
[i
], wiiuse
.LED
[i
])
56 wiiuse
.set_leds(self
.wiimotes
[4], wiiuse
.LED_1 | wiiuse
.LED_4
)
58 wiiuse
.set_leds(self
.wiimotes
[4], wiiuse
.LED_1 | wiiuse
.LED_4
)
59 wiiuse
.set_leds(self
.wiimotes
[5], wiiuse
.LED_1 | wiiuse
.LED_2 | wiiuse
.LED_3 | wiiuse
.LED_4
)
61 self
.go
= self
.actual_nmotes
!= 0
63 self
.startup
.put(self
.go
)
66 if self
._paused
: continue
68 if wiiuse
.poll(self
.wiimotes
, self
.nmotes
) :
69 for i
in range(self
.nmotes
) :
71 if m
[0].event
== wiiuse
.EVENT
:
72 self
.eventCallBack(self
, i
, m
)
78 func
, args
= self
.queue
.get_nowait()
89 def selectWiimote(self
, wiimoteIndex
) :
90 self
.selectedWiimoteIndex
= wiimoteIndex
91 # for i in range(self.actual_nmotes) :
92 # wm = self.wiimotes[i]
93 # if i == wiimoteIndex :
94 # self.do(wiiuse.set_ir, wm, 1)
95 # self.do(wiiuse.set_ir_vres, wm, *self.screenResolution)
96 # if self.position == 'ABOVE' :
97 # position = wiiuse.IR_ABOVE
98 # elif self.position == 'BELOW' :
99 # position = wiiuse.IR_BELOW
101 # position = wiiuse.IR_ABOVE
102 # self.do(wiiuse.set_ir_position, wm, position)
103 # # TODO aspect ratio
104 # #self.do(wiiuse.set_aspect_ratio, wm, aspect)
107 # self.do(wiiuse.set_ir, wm, 0)
109 def do(self
, func
, *args
):
110 '''Run the function in the thread handling the wiimote'''
111 self
.queue
.put((func
, args
))
113 def control_cb(self
, wmp
, attachment
, speaker
, ir
, led
, battery
):
114 '''Could check the battery level and such here'''
115 pygame
.event
.post(pygame
.event
.Event(WIIMOTE_STATUS
,
116 attachment
=attachment
,
119 led
=[led
[i
] for i
in range(4)],
123 def disconnect_cb(self
, wmp
):
124 '''What should we do here?'''
125 pygame
.event
.post(pygame
.event
.Event(WIIMOTE_DISCONNECT
,
130 for i
in range(self
.nmotes
):
131 wiiuse
.set_leds(self
.wiimotes
[i
], 0)
132 wiiuse
.disconnect(self
.wiimotes
[i
])
136 return self
.actual_nmotes
139 def _default_event_cb(self
, id, wmp
):
140 ''' default callback that emulate a one button mouse '''
141 if id != self
.selectedWiimoteIndex
: return
143 pos
= (wm
.ir
.x
, wm
.ir
.y
)
144 pygame
.mouse
.set_pos(pos
)
149 wiiuse
.is_just_pressed(wm
, wiiuse
.button
['B']) :
150 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONDOWN
,
153 pygame
.event
.post(event
)
155 if wm
.btns_released
and \
156 wiiuse
.is_released(wm
, wiiuse
.button
['B']):
157 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONUP
,
160 pygame
.event
.post(event
)
162 def _full_mouse_event_cb(self
, id, wmp
):
163 ''' callback that emulate a 2 buttons mouse with wheel '''
164 if id != self
.selectedWiimoteIndex
: return
166 pos
= (wm
.ir
.x
, wm
.ir
.y
)
167 pygame
.mouse
.set_pos(pos
)
173 if wiiuse
.is_just_pressed(wm
, wiiuse
.button
['B']) :
175 elif wiiuse
.is_just_pressed(wm
, wiiuse
.button
['A']) :
177 elif wiiuse
.is_just_pressed(wm
, wiiuse
.button
['Up']) :
179 elif wiiuse
.is_just_pressed(wm
, wiiuse
.button
['Down']) :
183 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONDOWN
,
186 pygame
.event
.post(event
)
188 if wm
.btns_released
:
190 if wiiuse
.is_released(wm
, wiiuse
.button
['B']) :
192 elif wiiuse
.is_released(wm
, wiiuse
.button
['A']) :
194 elif wiiuse
.is_released(wm
, wiiuse
.button
['Up']) :
196 elif wiiuse
.is_released(wm
, wiiuse
.button
['Down']) :
200 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONUP
,
203 pygame
.event
.post(event
)
208 def init(nmotes
, timeout
, screenResolution
=(660, 370), position
='ABOVE'):
209 '''Initialize the module.'''
214 WT
= wiimote_thread(nmotes
, timeout
, screenResolution
, position
)
217 for i
in range(nmotes
) :
218 wm
= Wiimote(i
) # access the wiimote object
219 wm
.enable_accels(0) # turn off acceleration reporting
220 wm
.enable_ir(1, vres
= screenResolution
, position
=position
)
224 '''How many Wiimotes were found?'''
225 return WT
.get_count()
228 '''Gracefully shutdown the connection and turn off the wiimote leds'''
232 class wiimote(object):
233 '''Object representing a Wiimote'''
234 def __init__(self
, n
):
235 self
.wm
= WT
.wiimotes
[n
]
237 def enable_leds(self
, m
):
238 '''Control leds. The lower 4 bits map to the 4 leds'''
239 WT
.do(wiiuse
.set_leds
, self
.wm
, sum([wiiuse
.LED
[i
] for i
in range(4) if m
& (1<<i
)]))
241 def enable_rumble(self
, on
):
243 WT
.do(wiiuse
.rumble
, self
.wm
, on
)
245 def enable_accels(self
, on
):
246 '''Control reporting of accelerometer data.'''
247 WT
.do(wiiuse
.motion_sensing
, self
.wm
, on
)
249 def enable_ir(self
, on
, vres
=None, position
=None, aspect
=None):
250 '''Control reporting IR data.'''
251 WT
.do(wiiuse
.set_ir
, self
.wm
, on
)
253 WT
.do(wiiuse
.set_ir_vres
, self
.wm
, *vres
)
254 if position
is not None:
255 WT
.do(wiiuse
.set_ir_position
, self
.wm
, position
)
256 if aspect
is not None:
257 WT
.do(wiiuse
.set_aspect_ratio
, self
.wm
, aspect
)
259 def set_flags(self
, smoothing
=None, continuous
=None, threshold
=None):
260 '''Set flags SMOOTHING, CONTINUOUS, ORIENT_THRESH'''
262 if smoothing
is not None:
264 enable |
= wiiuse
.SMOOTHING
266 disable |
= wiiuse
.SMOOTHING
267 if continuous
is not None:
269 enable |
= wiiuse
.CONTINUOUS
271 disable |
= wiiuse
.CONTINUOUS
272 if threshold
is not None:
274 enable |
= wiiuse
.ORIENT_THRESH
276 disable |
= wiiuse
.ORIENT_THRESH
277 WT
.do(wiiuse
.set_flags
, self
.wm
, enable
, disable
)
279 def set_orient_thresh(self
, thresh
):
280 '''Set orientation threshold'''
281 WT
.do(wiiuse
.set_orient_threshold
, self
.wm
, thresh
)
284 '''Trigger a status callback.'''
285 WT
.do(wiiuse
.status
, self
.wm
)
287 def disconnect(self
):
288 '''Disconnect this Wiimote'''
289 WT
.do(wiiuse
.disconnect(self
.wm
))
292 '''Get the object for the nth Wiimote'''