File: eventpoll.pyx

package info (click to toggle)
pyepl 1.1.0-3.1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 2,120 kB
  • sloc: cpp: 7,986; python: 6,026; makefile: 360; ansic: 132
file content (299 lines) | stat: -rw-r--r-- 10,053 bytes parent folder | download | duplicates (5)
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