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