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'''
20 def __init__(self
, nmotes
=1, timeout
=5):
21 Thread
.__init
__(self
, name
='wiimote')
23 self
.startup
= Queue()
25 self
.selectedWiimoteIndex
= 0
26 self
.timeout
= timeout
30 self
.startup
.get(True) # wait for the thread to get started and acquire the motes
31 self
.eventCallBack
= _default_event_cb
33 def setEventCallBack(self
, func
) :
34 self
.eventCallBack
= func
37 '''This runs in a separate thread'''
39 import PyWiiUse
as wiiuse
# import here to avoid thread problems on windows
40 self
.wiimotes
= wiiuse
.init(self
.nmotes
)
41 found
= wiiuse
.find(self
.wiimotes
, self
.nmotes
, self
.timeout
)
42 self
.actual_nmotes
= wiiuse
.connect(self
.wiimotes
, self
.nmotes
)
45 for i
in range(self
.nmotes
):
46 wiiuse
.set_leds(self
.wiimotes
[i
], wiiuse
.LED
[i
])
48 self
.go
= self
.actual_nmotes
!= 0
50 self
.startup
.put(self
.go
)
53 if self
._paused
: continue
55 if wiiuse
.poll(self
.wiimotes
, self
.nmotes
) :
56 for i
in range(self
.nmotes
) :
58 if m
[0].event
== wiiuse
.EVENT
:
59 self
.eventCallBack(self
, i
, m
)
65 func
, args
= self
.queue
.get_nowait()
76 def selectWiimote(self
, wiimoteIndex
) :
77 self
.selectedWiimoteIndex
= wiimoteIndex
79 def do(self
, func
, *args
):
80 '''Run the function in the thread handling the wiimote'''
81 self
.queue
.put((func
, args
))
83 def control_cb(self
, wmp
, attachment
, speaker
, ir
, led
, battery
):
84 '''Could check the battery level and such here'''
85 pygame
.event
.post(pygame
.event
.Event(WIIMOTE_STATUS
,
86 attachment
=attachment
,
89 led
=[led
[i
] for i
in range(4)],
93 def disconnect_cb(self
, wmp
):
94 '''What should we do here?'''
95 pygame
.event
.post(pygame
.event
.Event(WIIMOTE_DISCONNECT
,
100 for i
in range(self
.nmotes
):
101 wiiuse
.set_leds(self
.wiimotes
[i
], 0)
102 wiiuse
.disconnect(self
.wiimotes
[i
])
106 return self
.actual_nmotes
109 def _default_event_cb(self
, id, wmp
):
110 ''' default callback that emulate a one button mouse '''
111 if id != self
.selectedWiimoteIndex
: return
113 pos
= (wm
.ir
.x
, wm
.ir
.y
)
114 pygame
.mouse
.set_pos(pos
)
119 wiiuse
.is_just_pressed(wm
, wiiuse
.button
['B']) :
120 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONDOWN
,
123 pygame
.event
.post(event
)
125 if wm
.btns_released
and \
126 wiiuse
.is_released(wm
, wiiuse
.button
['B']):
127 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONUP
,
130 pygame
.event
.post(event
)
132 def _full_mouse_event_cb(self
, id, wmp
):
133 ''' callback that emulate a 2 buttons mouse with wheel '''
134 if id != self
.selectedWiimoteIndex
: return
136 pos
= (wm
.ir
.x
, wm
.ir
.y
)
137 pygame
.mouse
.set_pos(pos
)
143 if wiiuse
.is_just_pressed(wm
, wiiuse
.button
['B']) :
145 elif wiiuse
.is_just_pressed(wm
, wiiuse
.button
['A']) :
147 elif wiiuse
.is_just_pressed(wm
, wiiuse
.button
['Up']) :
149 elif wiiuse
.is_just_pressed(wm
, wiiuse
.button
['Down']) :
153 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONDOWN
,
156 pygame
.event
.post(event
)
158 if wm
.btns_released
:
160 if wiiuse
.is_released(wm
, wiiuse
.button
['B']) :
162 elif wiiuse
.is_released(wm
, wiiuse
.button
['A']) :
164 elif wiiuse
.is_released(wm
, wiiuse
.button
['Up']) :
166 elif wiiuse
.is_released(wm
, wiiuse
.button
['Down']) :
170 event
= pygame
.event
.Event(pygame
.MOUSEBUTTONUP
,
173 pygame
.event
.post(event
)
178 def init(nmotes
, timeout
, screenResolution
=(660, 370), position
='ABOVE'):
179 '''Initialize the module.'''
183 WT
= wiimote_thread(nmotes
, timeout
)
185 if position
== 'ABOVE' :
186 position
= wiiuse
.IR_ABOVE
187 elif position
== 'BELOW' :
188 position
= wiiuse
.IR_BELOW
190 position
= wiiuse
.IR_ABOVE
194 for i
in range(nmotes
) :
195 wm
= Wiimote(i
) # access the wiimote object
196 wm
.enable_accels(0) # turn off acceleration reporting
197 wm
.enable_ir(1, vres
= screenResolution
, position
=position
)
201 '''How many Wiimotes were found?'''
202 return WT
.get_count()
205 '''Gracefully shutdown the connection and turn off the wiimote leds'''
209 class wiimote(object):
210 '''Object representing a Wiimote'''
211 def __init__(self
, n
):
212 self
.wm
= WT
.wiimotes
[n
]
214 def enable_leds(self
, m
):
215 '''Control leds. The lower 4 bits map to the 4 leds'''
216 WT
.do(wiiuse
.set_leds
, self
.wm
, sum([wiiuse
.LED
[i
] for i
in range(4) if m
& (1<<i
)]))
218 def enable_rumble(self
, on
):
220 WT
.do(wiiuse
.rumble
, self
.wm
, on
)
222 def enable_accels(self
, on
):
223 '''Control reporting of accelerometer data.'''
224 WT
.do(wiiuse
.motion_sensing
, self
.wm
, on
)
226 def enable_ir(self
, on
, vres
=None, position
=None, aspect
=None):
227 '''Control reporting IR data.'''
228 WT
.do(wiiuse
.set_ir
, self
.wm
, on
)
230 WT
.do(wiiuse
.set_ir_vres
, self
.wm
, *vres
)
231 if position
is not None:
232 WT
.do(wiiuse
.set_ir_position
, self
.wm
, position
)
233 if aspect
is not None:
234 WT
.do(wiiuse
.set_aspect_ratio
, self
.wm
, aspect
)
236 def set_flags(self
, smoothing
=None, continuous
=None, threshold
=None):
237 '''Set flags SMOOTHING, CONTINUOUS, ORIENT_THRESH'''
239 if smoothing
is not None:
241 enable |
= wiiuse
.SMOOTHING
243 disable |
= wiiuse
.SMOOTHING
244 if continuous
is not None:
246 enable |
= wiiuse
.CONTINUOUS
248 disable |
= wiiuse
.CONTINUOUS
249 if threshold
is not None:
251 enable |
= wiiuse
.ORIENT_THRESH
253 disable |
= wiiuse
.ORIENT_THRESH
254 WT
.do(wiiuse
.set_flags
, self
.wm
, enable
, disable
)
256 def set_orient_thresh(self
, thresh
):
257 '''Set orientation threshold'''
258 WT
.do(wiiuse
.set_orient_threshold
, self
.wm
, thresh
)
261 '''Trigger a status callback.'''
262 WT
.do(wiiuse
.status
, self
.wm
)
264 def disconnect(self
):
265 '''Disconnect this Wiimote'''
266 WT
.do(wiiuse
.disconnect(self
.wm
))
269 '''Get the object for the nth Wiimote'''