1
|
|
|
""" |
2
|
|
|
This module handles user input. |
3
|
|
|
|
4
|
|
|
To handle user input you will likely want to use the L{event.get} function |
5
|
|
|
or create a subclass of L{event.App}. |
6
|
|
|
- L{event.get} iterates over recent events. |
7
|
|
|
- L{event.App} passes events to the overridable methods: ev_* and key_*. |
8
|
|
|
|
9
|
|
|
But there are other options such as L{event.keyWait} and L{event.isWindowClosed}. |
|
|
|
|
10
|
|
|
|
11
|
|
|
A few event attributes are actually string constants. |
12
|
|
|
Here's a reference for those: |
13
|
|
|
- L{Event.type} |
14
|
|
|
|
15
|
|
|
'QUIT', 'KEYDOWN', 'KEYUP', 'MOUSEDOWN', 'MOUSEUP', or 'MOUSEMOTION.' |
16
|
|
|
|
17
|
|
|
- L{MouseButtonEvent.button} (found in L{MouseDown} and L{MouseUp} events) |
18
|
|
|
|
19
|
|
|
'LEFT', 'MIDDLE', 'RIGHT', 'SCROLLUP', 'SCROLLDOWN' |
20
|
|
|
|
21
|
|
|
- L{KeyEvent.key} (found in L{KeyDown} and L{KeyUp} events) |
22
|
|
|
|
23
|
|
|
'NONE', 'ESCAPE', 'BACKSPACE', 'TAB', 'ENTER', 'SHIFT', 'CONTROL', |
24
|
|
|
'ALT', 'PAUSE', 'CAPSLOCK', 'PAGEUP', 'PAGEDOWN', 'END', 'HOME', 'UP', |
25
|
|
|
'LEFT', 'RIGHT', 'DOWN', 'PRINTSCREEN', 'INSERT', 'DELETE', 'LWIN', |
26
|
|
|
'RWIN', 'APPS', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
27
|
|
|
'KP0', 'KP1', 'KP2', 'KP3', 'KP4', 'KP5', 'KP6', 'KP7', 'KP8', 'KP9', |
28
|
|
|
'KPADD', 'KPSUB', 'KPDIV', 'KPMUL', 'KPDEC', 'KPENTER', 'F1', 'F2', |
29
|
|
|
'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', |
30
|
|
|
'NUMLOCK', 'SCROLLLOCK', 'SPACE', 'CHAR' |
31
|
|
|
|
32
|
|
|
""" |
33
|
|
|
|
34
|
|
|
import time as _time |
35
|
|
|
|
36
|
|
|
from tcod import ffi as _ffi |
|
|
|
|
37
|
|
|
from tcod import lib as _lib |
|
|
|
|
38
|
|
|
|
39
|
|
|
import tdl as _tdl |
40
|
|
|
from . import style as _style |
41
|
|
|
|
42
|
|
|
_eventQueue = [] |
|
|
|
|
43
|
|
|
_pushedEvents = [] |
|
|
|
|
44
|
|
|
|
45
|
|
|
_mousel = 0 |
|
|
|
|
46
|
|
|
_mousem = 0 |
|
|
|
|
47
|
|
|
_mouser = 0 |
|
|
|
|
48
|
|
|
|
49
|
|
|
# this interprets the constants from libtcod and makes a key -> keyname dictionary |
|
|
|
|
50
|
|
|
def _parseKeyNames(lib): |
|
|
|
|
51
|
|
|
""" |
52
|
|
|
returns a dictionary mapping of human readable key names to their keycodes |
53
|
|
|
this parses constants with the names of K_* and makes code=name pairs |
54
|
|
|
this is for KeyEvent.key variable and that enables things like: |
55
|
|
|
if (event.key == 'PAGEUP'): |
56
|
|
|
""" |
57
|
|
|
_keyNames = {} |
|
|
|
|
58
|
|
|
for attr in dir(lib): # from the modules variables |
59
|
|
|
if attr[:6] == 'TCODK_': # get the K_* constants |
60
|
|
|
_keyNames[getattr(lib, attr)] = attr[6:] # and make CODE=NAME pairs |
61
|
|
|
return _keyNames |
62
|
|
|
|
63
|
|
|
_keyNames = _parseKeyNames(_lib) |
|
|
|
|
64
|
|
|
|
65
|
|
|
class Event(object): |
66
|
|
|
"""Base Event class. |
67
|
|
|
|
68
|
|
|
You can easily subclass this to make your own events. Be sure to set |
69
|
|
|
the class attribute L{Event.type} for it to be passed to a custom L{App} |
70
|
|
|
ev_* method.""" |
71
|
|
|
type = None |
72
|
|
|
"""String constant representing the type of event. |
73
|
|
|
|
74
|
|
|
The L{App} ev_* methods depend on this attribute. |
75
|
|
|
|
76
|
|
|
Can be: 'QUIT', 'KEYDOWN', 'KEYUP', 'MOUSEDOWN', 'MOUSEUP', or 'MOUSEMOTION.' |
|
|
|
|
77
|
|
|
""" |
78
|
|
|
|
79
|
|
|
def __repr__(self): |
80
|
|
|
"""List an events public attributes when printed. |
81
|
|
|
""" |
82
|
|
|
attrdict = {} |
83
|
|
|
for varname in dir(self): |
84
|
|
|
if '_' == varname[0]: |
85
|
|
|
continue |
86
|
|
|
attrdict[varname] = self.__getattribute__(varname) |
87
|
|
|
return '%s Event %s' % (self.__class__.__name__, repr(attrdict)) |
88
|
|
|
|
89
|
|
|
class Quit(Event): |
90
|
|
|
"""Fired when the window is closed by the user. |
91
|
|
|
""" |
92
|
|
|
__slots__ = () |
93
|
|
|
type = 'QUIT' |
94
|
|
|
|
95
|
|
|
class KeyEvent(Event): |
|
|
|
|
96
|
|
|
|
97
|
|
|
def __init__(self, key='', char='', text='', shift=False, |
98
|
|
|
left_alt=False, right_alt=False, |
99
|
|
|
left_control=False, right_control=False, |
100
|
|
|
left_meta=False, right_meta=False): |
101
|
|
|
# Convert keycodes into string, but use string if passed |
102
|
|
|
self.key = key if isinstance(key, str) else _keyNames[key] |
103
|
|
|
"""Human readable names of the key pressed. |
104
|
|
|
Non special characters will show up as 'CHAR'. |
105
|
|
|
|
106
|
|
|
Can be one of |
107
|
|
|
'NONE', 'ESCAPE', 'BACKSPACE', 'TAB', 'ENTER', 'SHIFT', 'CONTROL', |
108
|
|
|
'ALT', 'PAUSE', 'CAPSLOCK', 'PAGEUP', 'PAGEDOWN', 'END', 'HOME', 'UP', |
109
|
|
|
'LEFT', 'RIGHT', 'DOWN', 'PRINTSCREEN', 'INSERT', 'DELETE', 'LWIN', |
110
|
|
|
'RWIN', 'APPS', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
111
|
|
|
'KP0', 'KP1', 'KP2', 'KP3', 'KP4', 'KP5', 'KP6', 'KP7', 'KP8', 'KP9', |
112
|
|
|
'KPADD', 'KPSUB', 'KPDIV', 'KPMUL', 'KPDEC', 'KPENTER', 'F1', 'F2', |
113
|
|
|
'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', |
114
|
|
|
'NUMLOCK', 'SCROLLLOCK', 'SPACE', 'CHAR' |
115
|
|
|
|
116
|
|
|
For the actual character instead of 'CHAR' use L{keychar}. |
117
|
|
|
@type: string""" |
118
|
|
|
self.char = char.replace('\x00', '') # change null to empty string |
119
|
|
|
"""A single character string of the letter or symbol pressed. |
120
|
|
|
|
121
|
|
|
Special characters like delete and return are not cross-platform. |
122
|
|
|
L{key} or L{keychar} should be used instead for special keys. |
123
|
|
|
Characters are also case sensitive. |
124
|
|
|
@type: string""" |
125
|
|
|
# get the best out of self.key and self.char |
126
|
|
|
self.keychar = self.char if self.key == 'CHAR' else self.key |
127
|
|
|
"""Similar to L{key} but returns a case sensitive letter or symbol |
128
|
|
|
instead of 'CHAR'. |
129
|
|
|
|
130
|
|
|
This variable makes available the widest variety of symbols and should |
131
|
|
|
be used for key-mappings or anywhere where a narrower sample of keys |
132
|
|
|
isn't needed. |
133
|
|
|
""" |
134
|
|
|
self.text = text |
135
|
|
|
|
136
|
|
|
self.left_alt = self.leftAlt = bool(left_alt) |
|
|
|
|
137
|
|
|
"""@type: boolean""" |
138
|
|
|
self.right_alt = self.rightAlt = bool(right_alt) |
|
|
|
|
139
|
|
|
"""@type: boolean""" |
140
|
|
|
self.left_control = self.leftCtrl = bool(left_control) |
|
|
|
|
141
|
|
|
"""@type: boolean""" |
142
|
|
|
self.right_control = self.rightCtrl = bool(right_control) |
|
|
|
|
143
|
|
|
"""@type: boolean""" |
144
|
|
|
self.shift = bool(shift) |
145
|
|
|
"""True if shift was held down during this event. |
146
|
|
|
@type: boolean""" |
147
|
|
|
self.alt = self.left_alt or self.right_alt |
148
|
|
|
"""True if alt was held down during this event. |
149
|
|
|
@type: boolean""" |
150
|
|
|
self.control = self.left_control or self.right_control |
151
|
|
|
"""True if control was held down during this event. |
152
|
|
|
@type: boolean""" |
153
|
|
|
self.left_meta = bool(left_meta) |
154
|
|
|
self.right_meta = bool(right_meta) |
155
|
|
|
self.meta = self.left_meta or self.right_meta |
156
|
|
|
|
157
|
|
|
def __repr__(self): |
158
|
|
|
parameters = [] |
159
|
|
|
for attr in ('key', 'char', 'text', 'shift', |
160
|
|
|
'left_alt', 'right_alt', |
161
|
|
|
'left_control', 'right_control', |
162
|
|
|
'left_meta', 'right_meta'): |
163
|
|
|
value = getattr(self, attr) |
164
|
|
|
if value: |
165
|
|
|
parameters.append('%s=%r' % (attr, value)) |
166
|
|
|
return '%s(%s)' % (self.__class__.__name__, ', '.join(parameters)) |
167
|
|
|
|
168
|
|
|
class KeyDown(KeyEvent): |
169
|
|
|
"""Fired when the user presses a key on the keyboard or a key repeats. |
170
|
|
|
""" |
171
|
|
|
type = 'KEYDOWN' |
172
|
|
|
|
173
|
|
|
class KeyUp(KeyEvent): |
174
|
|
|
"""Fired when the user releases a key on the keyboard. |
175
|
|
|
""" |
176
|
|
|
type = 'KEYUP' |
177
|
|
|
|
178
|
|
|
_mouseNames = {1: 'LEFT', 2: 'MIDDLE', 3: 'RIGHT', 4: 'SCROLLUP', 5: 'SCROLLDOWN'} |
|
|
|
|
179
|
|
|
class MouseButtonEvent(Event): |
|
|
|
|
180
|
|
|
|
181
|
|
|
def __init__(self, button, pos, cell): |
182
|
|
|
self.button = _mouseNames[button] |
183
|
|
|
"""Can be one of |
184
|
|
|
'LEFT', 'MIDDLE', 'RIGHT', 'SCROLLUP', 'SCROLLDOWN' |
185
|
|
|
@type: string""" |
186
|
|
|
self.pos = pos |
187
|
|
|
"""(x, y) position of the mouse on the screen |
188
|
|
|
@type: (int, int)""" |
189
|
|
|
self.cell = cell |
190
|
|
|
"""(x, y) position of the mouse snapped to a cell on the root console |
191
|
|
|
@type: (int, int)""" |
192
|
|
|
|
193
|
|
|
class MouseDown(MouseButtonEvent): |
194
|
|
|
"""Fired when a mouse button is pressed.""" |
195
|
|
|
__slots__ = () |
196
|
|
|
type = 'MOUSEDOWN' |
197
|
|
|
|
198
|
|
|
class MouseUp(MouseButtonEvent): |
199
|
|
|
"""Fired when a mouse button is released.""" |
200
|
|
|
__slots__ = () |
201
|
|
|
type = 'MOUSEUP' |
202
|
|
|
|
203
|
|
|
class MouseMotion(Event): |
204
|
|
|
"""Fired when the mouse is moved.""" |
205
|
|
|
type = 'MOUSEMOTION' |
206
|
|
|
|
207
|
|
|
def __init__(self, pos, cell, motion, cellmotion): |
208
|
|
|
self.pos = pos |
209
|
|
|
"""(x, y) position of the mouse on the screen. |
210
|
|
|
type: (int, int)""" |
211
|
|
|
self.cell = cell |
212
|
|
|
"""(x, y) position of the mouse snapped to a cell on the root console. |
213
|
|
|
type: (int, int)""" |
214
|
|
|
self.motion = motion |
215
|
|
|
"""(x, y) motion of the mouse on the screen. |
216
|
|
|
type: (int, int)""" |
217
|
|
|
self.cellmotion = cellmotion |
218
|
|
|
"""(x, y) mostion of the mouse moving over cells on the root console. |
219
|
|
|
type: (int, int)""" |
220
|
|
|
|
221
|
|
|
class App(object): |
222
|
|
|
""" |
223
|
|
|
Application framework. |
224
|
|
|
|
225
|
|
|
- ev_*: Events are passed to methods based on their L{Event.type} attribute. |
|
|
|
|
226
|
|
|
If an event type is 'KEYDOWN' the ev_KEYDOWN method will be called |
227
|
|
|
with the event instance as a parameter. |
228
|
|
|
|
229
|
|
|
- key_*: When a key is pressed another method will be called based on the |
230
|
|
|
L{KeyEvent.key} attribute. For example the 'ENTER' key will call key_ENTER |
|
|
|
|
231
|
|
|
with the associated L{KeyDown} event as its parameter. |
232
|
|
|
|
233
|
|
|
- L{update}: This method is called every loop. It is passed a single |
234
|
|
|
parameter detailing the time in seconds since the last update |
235
|
|
|
(often known as deltaTime.) |
236
|
|
|
|
237
|
|
|
You may want to call drawing routines in this method followed by |
238
|
|
|
L{tdl.flush}. |
239
|
|
|
|
240
|
|
|
""" |
241
|
|
|
__slots__ = ('__running', '__prevTime') |
242
|
|
|
|
243
|
|
|
def ev_QUIT(self, event): |
|
|
|
|
244
|
|
|
"""Unless overridden this method raises a SystemExit exception closing |
245
|
|
|
the program.""" |
246
|
|
|
raise SystemExit() |
247
|
|
|
|
248
|
|
|
def ev_KEYDOWN(self, event): |
|
|
|
|
249
|
|
|
"""Override this method to handle a L{KeyDown} event.""" |
250
|
|
|
|
251
|
|
|
def ev_KEYUP(self, event): |
|
|
|
|
252
|
|
|
"""Override this method to handle a L{KeyUp} event.""" |
253
|
|
|
|
254
|
|
|
def ev_MOUSEDOWN(self, event): |
|
|
|
|
255
|
|
|
"""Override this method to handle a L{MouseDown} event.""" |
256
|
|
|
|
257
|
|
|
def ev_MOUSEUP(self, event): |
|
|
|
|
258
|
|
|
"""Override this method to handle a L{MouseUp} event.""" |
259
|
|
|
|
260
|
|
|
def ev_MOUSEMOTION(self, event): |
|
|
|
|
261
|
|
|
"""Override this method to handle a L{MouseMotion} event.""" |
262
|
|
|
|
263
|
|
|
def update(self, deltaTime): |
|
|
|
|
264
|
|
|
"""Override this method to handle per frame logic and drawing. |
265
|
|
|
|
266
|
|
|
@type deltaTime: float |
267
|
|
|
@param deltaTime: This parameter tells the amount of time passed since |
268
|
|
|
the last call measured in seconds as a floating point |
269
|
|
|
number. |
270
|
|
|
|
271
|
|
|
You can use this variable to make your program |
272
|
|
|
frame rate independent. |
273
|
|
|
Use this parameter to adjust the speed of motion, |
274
|
|
|
timers, and other game logic. |
275
|
|
|
""" |
276
|
|
|
pass |
277
|
|
|
|
278
|
|
|
def suspend(self): |
279
|
|
|
"""When called the App will begin to return control to where |
280
|
|
|
L{App.run} was called. |
281
|
|
|
|
282
|
|
|
Some further events are processed and the L{App.update} method will be |
283
|
|
|
called one last time before exiting |
284
|
|
|
(unless suspended during a call to L{App.update}.) |
285
|
|
|
""" |
286
|
|
|
self.__running = False |
|
|
|
|
287
|
|
|
|
288
|
|
|
def run(self): |
289
|
|
|
"""Delegate control over to this App instance. This function will |
290
|
|
|
process all events and send them to the special methods ev_* and key_*. |
291
|
|
|
|
292
|
|
|
A call to L{App.suspend} will return the control flow back to where |
293
|
|
|
this function is called. And then the App can be run again. |
294
|
|
|
But a single App instance can not be run multiple times simultaneously. |
295
|
|
|
""" |
296
|
|
|
if getattr(self, '_App__running', False): |
297
|
|
|
raise _tdl.TDLError('An App can not be run multiple times simultaneously') |
|
|
|
|
298
|
|
|
self.__running = True |
|
|
|
|
299
|
|
|
while self.__running: |
300
|
|
|
self.runOnce() |
301
|
|
|
|
302
|
|
|
def run_once(self): |
303
|
|
|
"""Pump events to this App instance and then return. |
304
|
|
|
|
305
|
|
|
This works in the way described in L{App.run} except it immediately |
306
|
|
|
returns after the first L{update} call. |
307
|
|
|
|
308
|
|
|
Having multiple L{App} instances and selectively calling runOnce on |
309
|
|
|
them is a decent way to create a state machine. |
310
|
|
|
""" |
311
|
|
|
if not hasattr(self, '_App__prevTime'): |
312
|
|
|
self.__prevTime = _time.clock() # initiate __prevTime |
|
|
|
|
313
|
|
|
for event in get(): |
314
|
|
|
if event.type: # exclude custom events with a blank type variable |
315
|
|
|
# call the ev_* methods |
316
|
|
|
method = 'ev_%s' % event.type # ev_TYPE |
317
|
|
|
getattr(self, method)(event) |
318
|
|
|
if event.type == 'KEYDOWN': |
319
|
|
|
# call the key_* methods |
320
|
|
|
method = 'key_%s' % event.key # key_KEYNAME |
321
|
|
|
if hasattr(self, method): # silently exclude undefined methods |
322
|
|
|
getattr(self, method)(event) |
323
|
|
|
newTime = _time.clock() |
|
|
|
|
324
|
|
|
self.update(newTime - self.__prevTime) |
325
|
|
|
self.__prevTime = newTime |
|
|
|
|
326
|
|
|
#_tdl.flush() |
327
|
|
|
|
328
|
|
|
def _processEvents(): |
|
|
|
|
329
|
|
|
"""Flushes the event queue from libtcod into the global list _eventQueue""" |
330
|
|
|
global _mousel, _mousem, _mouser, _eventsflushed, _pushedEvents |
|
|
|
|
331
|
|
|
_eventsflushed = True |
332
|
|
|
events = _pushedEvents # get events from event.push |
333
|
|
|
_pushedEvents = [] # then clear the pushed events queue |
334
|
|
|
|
335
|
|
|
mouse = _ffi.new('TCOD_mouse_t *') |
336
|
|
|
libkey = _ffi.new('TCOD_key_t *') |
337
|
|
|
while 1: |
338
|
|
|
libevent = _lib.TCOD_sys_check_for_event(_lib.TCOD_EVENT_ANY, libkey, mouse) |
|
|
|
|
339
|
|
|
if not libevent: # no more events from libtcod |
340
|
|
|
break |
341
|
|
|
|
342
|
|
|
#if mouse.dx or mouse.dy: |
343
|
|
|
if libevent & _lib.TCOD_EVENT_MOUSE_MOVE: |
344
|
|
|
events.append(MouseMotion((mouse.x, mouse.y), |
345
|
|
|
(mouse.cx, mouse.cy), |
346
|
|
|
(mouse.dx, mouse.dy), |
347
|
|
|
(mouse.dcx, mouse.dcy))) |
348
|
|
|
|
349
|
|
|
mousepos = ((mouse.x, mouse.y), (mouse.cx, mouse.cy)) |
350
|
|
|
|
351
|
|
|
for oldstate, newstate, released, button in \ |
352
|
|
|
zip((_mousel, _mousem, _mouser), |
353
|
|
|
(mouse.lbutton, mouse.mbutton, mouse.rbutton), |
354
|
|
|
(mouse.lbutton_pressed, mouse.mbutton_pressed, |
355
|
|
|
mouse.rbutton_pressed), |
356
|
|
|
(1, 2, 3)): |
357
|
|
|
if released: |
358
|
|
|
if not oldstate: |
359
|
|
|
events.append(MouseDown(button, *mousepos)) |
360
|
|
|
events.append(MouseUp(button, *mousepos)) |
361
|
|
|
if newstate: |
362
|
|
|
events.append(MouseDown(button, *mousepos)) |
363
|
|
|
elif newstate and not oldstate: |
364
|
|
|
events.append(MouseDown(button, *mousepos)) |
365
|
|
|
|
366
|
|
|
if mouse.wheel_up: |
367
|
|
|
events.append(MouseDown(4, *mousepos)) |
368
|
|
|
if mouse.wheel_down: |
369
|
|
|
events.append(MouseDown(5, *mousepos)) |
370
|
|
|
|
371
|
|
|
_mousel = mouse.lbutton |
372
|
|
|
_mousem = mouse.mbutton |
373
|
|
|
_mouser = mouse.rbutton |
374
|
|
|
|
375
|
|
|
if libkey.vk == _lib.TCODK_NONE: |
376
|
|
|
break |
377
|
|
|
if libkey.pressed: |
378
|
|
|
keyevent = KeyDown |
379
|
|
|
else: |
380
|
|
|
keyevent = KeyUp |
381
|
|
|
events.append( |
382
|
|
|
keyevent( |
383
|
|
|
libkey.vk, |
384
|
|
|
libkey.c.decode('ascii', errors='ignore'), |
385
|
|
|
_ffi.string(libkey.text).decode('utf-8'), |
386
|
|
|
libkey.shift, |
387
|
|
|
libkey.lalt, |
388
|
|
|
libkey.ralt, |
389
|
|
|
libkey.lctrl, |
390
|
|
|
libkey.rctrl, |
391
|
|
|
libkey.lmeta, |
392
|
|
|
libkey.rmeta, |
393
|
|
|
) |
394
|
|
|
) |
395
|
|
|
|
396
|
|
|
if _lib.TCOD_console_is_window_closed(): |
397
|
|
|
events.append(Quit()) |
398
|
|
|
|
399
|
|
|
_eventQueue.extend(events) |
400
|
|
|
|
401
|
|
|
def get(): |
402
|
|
|
"""Flushes the event queue and returns the list of events. |
403
|
|
|
|
404
|
|
|
This function returns L{Event} objects that can be identified by their |
405
|
|
|
type attribute or their class. |
406
|
|
|
|
407
|
|
|
@rtype: iterator |
408
|
|
|
@return: Returns an iterable of objects derived from L{Event} or anything |
409
|
|
|
put in a L{push} call. If the iterator is deleted or otherwise |
410
|
|
|
interrupted before finishing the excess items are preserved for the |
411
|
|
|
next call. |
412
|
|
|
""" |
413
|
|
|
_processEvents() |
414
|
|
|
return _event_generator() |
415
|
|
|
|
416
|
|
|
def _event_generator(): |
|
|
|
|
417
|
|
|
while _eventQueue: |
418
|
|
|
# if there is an interruption the rest of the events stay untouched |
419
|
|
|
# this means you can break out of a event.get loop without losing |
420
|
|
|
# the leftover events |
421
|
|
|
yield(_eventQueue.pop(0)) |
|
|
|
|
422
|
|
|
raise StopIteration() |
423
|
|
|
|
424
|
|
|
|
425
|
|
|
def wait(timeout=None, flush=True): |
426
|
|
|
"""Wait for an event. |
427
|
|
|
|
428
|
|
|
@type timeout: int or None |
429
|
|
|
@param timeout: The time in seconds that this function will wait before |
430
|
|
|
giving up and returning None. |
431
|
|
|
|
432
|
|
|
With the default value of None, this will block forever. |
433
|
|
|
@type flush: boolean |
434
|
|
|
@param flush: If True a call to L{tdl.flush} will be made before listening |
435
|
|
|
for events. |
436
|
|
|
@rtype: L{Event} or None |
437
|
|
|
@return: Returns an instance derived from L{Event}, or None if the function |
438
|
|
|
has timed out. |
439
|
|
|
Anything added via L{push} will also be returned. |
440
|
|
|
|
441
|
|
|
@since: 1.4.0 |
442
|
|
|
""" |
443
|
|
|
if timeout is not None: |
444
|
|
|
timeout = timeout + _time.clock() # timeout at this time |
445
|
|
|
while True: |
446
|
|
|
if _eventQueue: |
447
|
|
|
return _eventQueue.pop(0) |
448
|
|
|
if flush: |
449
|
|
|
# a full 'round' of events need to be processed before flushing |
450
|
|
|
_tdl.flush() |
451
|
|
|
if timeout and _time.clock() >= timeout: |
452
|
|
|
return None # return None on timeout |
453
|
|
|
_time.sleep(0.001) # sleep 1ms |
454
|
|
|
_processEvents() |
455
|
|
|
|
456
|
|
|
|
457
|
|
|
def push(event): |
458
|
|
|
"""Push an event into the event buffer. |
459
|
|
|
|
460
|
|
|
@type event: L{Event}-like object |
461
|
|
|
@param event: The event will be available on the next call to L{event.get}. |
462
|
|
|
An event pushed in the middle of a L{get} will not show until |
463
|
|
|
the next time L{get} called preventing push related |
464
|
|
|
infinite loops. |
465
|
|
|
|
466
|
|
|
This object should at least have a 'type' attribute. |
467
|
|
|
""" |
468
|
|
|
_pushedEvents.append(event) |
469
|
|
|
|
470
|
|
|
def key_wait(): |
471
|
|
|
"""Waits until the user presses a key. |
472
|
|
|
Then returns a L{KeyDown} event. |
473
|
|
|
|
474
|
|
|
Key events will repeat if held down. |
475
|
|
|
|
476
|
|
|
A click to close the window will be converted into an Alt+F4 KeyDown event. |
477
|
|
|
|
478
|
|
|
@rtype: L{KeyDown} |
479
|
|
|
""" |
480
|
|
|
while 1: |
481
|
|
|
for event in get(): |
482
|
|
|
if event.type == 'KEYDOWN': |
483
|
|
|
return event |
484
|
|
|
if event.type == 'QUIT': |
485
|
|
|
# convert QUIT into alt+F4 |
486
|
|
|
return KeyDown('F4', '', True, False, True, False, False) |
487
|
|
|
_time.sleep(.001) |
488
|
|
|
|
489
|
|
|
def set_key_repeat(delay=500, interval=0): |
|
|
|
|
490
|
|
|
"""Does nothing. |
491
|
|
|
""" |
492
|
|
|
pass |
493
|
|
|
|
494
|
|
|
def is_window_closed(): |
495
|
|
|
"""Returns True if the exit button on the window has been clicked and |
496
|
|
|
stays True afterwards. |
497
|
|
|
|
498
|
|
|
@rtype: boolean |
499
|
|
|
""" |
500
|
|
|
return _lib.TCOD_console_is_window_closed() |
501
|
|
|
|
502
|
|
|
__all__ = [_var for _var in locals().keys() if _var[0] != '_'] |
503
|
|
|
|
504
|
|
|
App.runOnce = _style.backport(App.run_once) |
505
|
|
|
keyWait = _style.backport(key_wait) |
|
|
|
|
506
|
|
|
setKeyRepeat = _style.backport(set_key_repeat) |
|
|
|
|
507
|
|
|
isWindowClosed = _style.backport(is_window_closed) |
|
|
|
|
508
|
|
|
|
509
|
|
|
|
This check looks for lines that are too long. You can specify the maximum line length.