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