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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
|
# PyEPL: hardware/eventpoll.pyx
#
# Copyright (C) 2003-2005 Michael J. Kahana
# Authors: Ian Schleifer, Per Sederberg, Aaron Geller, Josh Jacobs
# URL: http://memory.psych.upenn.edu/programming/pyepl
#
# Distributed under the terms of the GNU Lesser General Public License
# (LGPL). See the license.txt that came with this file.
"""
This module is responsible for continual event polling for input
devices.
"""
# import the pygame package
import pygame
# have certain pygame event constants in this namespace
from pygame.locals import KEYDOWN, KEYUP, MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN, JOYAXISMOTION, JOYBALLMOTION, JOYHATMOTION, JOYBUTTONUP, JOYBUTTONDOWN, USEREVENT
# import the pyepl timing module
import timing
# declare python variables to hold callbacks for particular kinds of events...
cdef object keyboard_callback
cdef object mouse_movement_callback
cdef object mouse_buttons_callback
cdef object joystick_axis_callback
cdef object joystick_balls_callback
cdef object joystick_buttons_callback
cdef object joystick_hats_callback
cdef object poll_callbacks # this one is called at every iteration of the event loop
# declare a variable for a python list - it will be a queue for events read
# from pygame, but not yet processed
cdef object event_queue
# declare an integer which holds the number of times the pollEvents function is
# currently in the call stack
cdef int recurse_level
# declare a python object for store the time of the last event polling
cdef object last_poll
# declare a floating point variable to store the threshold below which the
# absolute value of a joystick axis is considered to be zero
cdef float js_zero_threshold
def setJSZeroThreshold(float x):
"""
Set the joystick zero threshold to x.
"""
global js_zero_threshold
js_zero_threshold = x
def setJoystickCallbacks(axis, balls, buttons, hats):
"""
Set the four callbacks for joystick-related events...
axis - Called when a joystick axis changes position
balls - Called when a joystick ball is moved
buttons - Called when a joystick button is pressed or released
hats - Called when a joystick hat is moved from one position to another
"""
# set variables as global in this function...
global joystick_axis_callback
global joystick_balls_callback
global joystick_buttons_callback
global joystick_hats_callback
# assign variables...
joystick_axis_callback = axis
joystick_balls_callback = balls
joystick_buttons_callback = buttons
joystick_hats_callback = hats
def setKeyboardCallback(c):
"""
After this call, any keyboard event will result in the call
"c(key, pressed, timestamp)", where key is a key identifier and pressed
is True or False for depressed and released, respectively.
"""
global keyboard_callback
keyboard_callback = c
def setMouseCallbacks(movement, buttons):
"""
After this call, any mouse movement event will result in the call
"movement(absolute_position, position_change, timestamp)" and any
mouse button event will result in the call "buttons(button,
pressed, timestamp)".
"""
# set variables as global in this function...
global mouse_movement_callback
global mouse_buttons_callback
# assign variables...
mouse_movement_callback = movement
mouse_buttons_callback = buttons
def addPollCallback(c, *targs, **dargs):
"""
Call function c at every polling of events. All remaining parameters, both
positional and keyword, will be passed to c when it is called.
"""
global poll_callbacks
poll_callbacks.append((c, targs, dargs))
def removePollCallback(c):
"""
Stop calling function c at each polling of events.
"""
global poll_callbacks
# for every registered poll callback...
for n, (cb, targs, dargs) in enumerate(poll_callbacks):
# if the associated function is c...
if cb==c:
# remove the callback
del poll_callbacks[n]
# and exit this function
return
def initialize(**options):
"""
Do any preparation necessary for event polling.
"""
# set variables as global in this function...
global recurse_level
global last_poll
global event_queue
global poll_callbacks
# initialize recursion level to zero
recurse_level = 0
# set the time of the last polling to now
last_poll = timing.universal_time()
# create an empty list to store queued events
event_queue = []
# create an empty list to store poll callbacks
poll_callbacks = []
def finalize():
"""
Shut down event polling.
"""
# presently, nothing needs to be done to finalize this module
pass
# global variables to implemets periodic sleeps to make Macs happy in realtime mode
isRealtime = 0
sleepTime = 500 # in uSec
def pollEvents():
# set the realtime mode related variables as global...
global isRealtime
global sleepTime
# set remaining variables as global in this function...
global keyboard_callback
global mouse_movement_callback
global mouse_buttons_callback
global joystick_axis_callback
global joystick_balls_callback
global joystick_buttons_callback
global joystick_hats_callback
global poll_callbacks
global event_queue
global recurse_level
global last_poll
global js_zero_threshold
# declare variable to store current time
cdef object now
# declare variable for timestamp with maximum latency
cdef object t
# declare variable to store events read from pygame
cdef object evs
# temporary float variable (used for joystick axis events)
cdef float v
# get the current time
now = timing.universal_time()
# calculate maximum latency based on current time and last polling time
t = (last_poll, now - last_poll)
# update last polling time
last_poll = now
# get all waiting events from pygame
evs = pygame.event.get()
# for all the events we just read...
for ev in evs:
# ...put them into the event queue along with the timestamp
event_queue.append((t, ev))
# see if we should add sleep to lower CPU use
if isRealtime:
if len(event_queue)==0:
#and timing.universal_time()-lastSleep >= sleepDelay:
# Do the sleep
timing.uSleep(sleepTime)
#lastSleep = timing.universal_time()
# don't allow the rest of this to be called recursively...
if not recurse_level:
# set the recurse level so that we do not get loops
recurse_level = 1
# for all registered polling callbacks...
for c, targs, dargs in poll_callbacks:
# ...call them with the registered parameters
c(*targs, **dargs)
# process events until the queue is empty (even if more are added)...
while len(event_queue):
# read an event and timestamp from the queue [is it a stack now?]
t, e = event_queue.pop(0)
# recurse_level = 1 # was here, but we moved it up
# SEE IF WE HAVE AN EVENT TYPE WE CARE ABOUT...
if e.type == KEYDOWN:
# if it's a keydown event...
if keyboard_callback:
# call the keyboard callback with relevent info
keyboard_callback(e.key, True, t)
elif e.type == KEYUP:
# if it's a key up event...
if keyboard_callback:
# call the keyboard callback with relevent info
keyboard_callback(e.key, False, t)
elif e.type == MOUSEMOTION:
# if it's a mouse motion event...
if mouse_movement_callback:
# call the mouse movement callback with relevent info
mouse_movement_callback(e.pos, e.rel, t)
elif e.type == MOUSEBUTTONUP:
# if it's a mouse button up event...
if mouse_buttons_callback:
# ...mouse buttons callback
mouse_buttons_callback(e.button, False, t)
elif e.type == MOUSEBUTTONDOWN:
# mouse down event?...
if mouse_buttons_callback:
# ...mouse buttons callback
mouse_buttons_callback(e.button, True, t)
elif e.type == JOYAXISMOTION:
# mouse axis motion?...
if joystick_axis_callback:
# put the axis value into a local variable
v = e.value
# if it's absolute value is less than the threshold...
if v < js_zero_threshold and v > -js_zero_threshold:
# ...use zero instead
v = 0.0
# joystick axis callback
joystick_axis_callback(e.joy, e.axis, v, t)
elif e.type == JOYBALLMOTION:
# joystick ball motion?...
if joystick_balls_callback:
# ...joystick balls callback
joystick_balls_callback(e.joy, e.ball, e.rel, t)
elif e.type == JOYHATMOTION:
# joystick hat motion?...
if joystick_hats_callback:
# ...joystick hats callback
joystick_hats_callback(e.joy, e.hat, e.value, t)
elif e.type == JOYBUTTONUP:
# joystick button up?...
if joystick_buttons_callback:
# ...joystick buttons callback
joystick_buttons_callback(e.joy, e.button, False, t)
elif e.type == JOYBUTTONDOWN:
# joystick button down?...
if joystick_buttons_callback:
# ...joystick buttons callback
joystick_buttons_callback(e.joy, e.button, True, t)
# all done, set recursion level back to zero
recurse_level = 0
|