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 import time
34 import ctypes
35
36 from .__tcod import _lib, _Mouse, _Key
37 from . import __tcod as _tcod
38 import tdl as _tdl
39
40 _eventQueue = []
41 _pushedEvents = []
42
43 _mousel = 0
44 _mousem = 0
45 _mouser = 0
46
47
49 """
50 returns a dictionary mapping of human readable key names to their keycodes
51 this parses constants with the names of K_* and makes code=name pairs
52 this is for KeyEvent.keyname variable and that enables things like:
53 if (event.keyname == 'PAGEUP'):
54 """
55 _keyNames = {}
56 for attr in dir(module):
57 if attr[:2] == 'K_':
58 _keyNames[getattr(_tcod, attr)] = attr[2:]
59 return _keyNames
60
61 _keyNames = _parseKeyNames(_tcod)
62
64 __slots__ = ()
65 type = None
66 """String constant representing the type of event.
67
68 Can be: 'QUIT', 'KEYDOWN', 'KEYUP', 'MOUSEDOWN', 'MOUSEUP', or 'MOUSEMOTION.'
69 """
70
72 """List an events public attributes in print calls.
73 """
74 attrdict = {}
75 for varname in dir(self):
76 if '_' == varname[0]:
77 continue
78 attrdict[varname] = self.__getattribute__(varname)
79 return '%s Event %s' % (self.__class__.__name__, repr(attrdict))
80
82 """Fired when the window is closed by the user.
83 """
84 __slots__ = ()
85 type = 'QUIT'
86
88 __slots__ = ('key', 'char', 'shift', 'alt', 'control',
89 'leftAlt', 'leftCtrl', 'rightAlt', 'rightCtrl')
90
91 - def __init__(self, key, char, lalt, lctrl, ralt, rctrl, shift):
92 self.key = _keyNames[key]
93 """Human readable name of the key pressed.
94
95 Can be one of
96 'NONE', 'ESCAPE', 'BACKSPACE', 'TAB', 'ENTER', 'SHIFT', 'CONTROL',
97 'ALT', 'PAUSE', 'CAPSLOCK', 'PAGEUP', 'PAGEDOWN', 'END', 'HOME', 'UP',
98 'LEFT', 'RIGHT', 'DOWN', 'PRINTSCREEN', 'INSERT', 'DELETE', 'LWIN',
99 'RWIN', 'APPS', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
100 'KP0', 'KP1', 'KP2', 'KP3', 'KP4', 'KP5', 'KP6', 'KP7', 'KP8', 'KP9',
101 'KPADD', 'KPSUB', 'KPDIV', 'KPMUL', 'KPDEC', 'KPENTER', 'F1', 'F2',
102 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12',
103 'NUMLOCK', 'SCROLLLOCK', 'SPACE', 'CHAR'
104 @type: string"""
105 char = char if isinstance(char, str) else char.decode()
106 self.char = char.replace('\x00', '')
107 """A single character string of the letter or symbol pressed.
108
109 Special characters like delete and return are not cross-platform.
110 L{key} should be used instead for special keys.
111 @type: string"""
112 self.leftAlt = bool(lalt)
113 """@type: boolean"""
114 self.rightAlt = bool(ralt)
115 """@type: boolean"""
116 self.leftCtrl = bool(lctrl)
117 """@type: boolean"""
118 self.rightCtrl = bool(rctrl)
119 """@type: boolean"""
120 self.shift = bool(shift)
121 """True if shift was held down during this event.
122 @type: boolean"""
123 self.alt = bool(lalt or ralt)
124 """True if alt was held down during this event.
125 @type: boolean"""
126 self.control = bool(lctrl or rctrl)
127 """True if control was held down during this event.
128 @type: boolean"""
129
131 """Fired when the user presses a key on the keyboard or a key repeats.
132 """
133 __slots__ = ()
134 type = 'KEYDOWN'
135
137 """Fired when the user releases a key on the keyboard.
138 """
139 __slots__ = ()
140 type = 'KEYUP'
141
142 _mouseNames = {1: 'LEFT', 2: 'MIDDLE', 3: 'RIGHT', 4: 'SCROLLUP', 5: 'SCROLLDOWN'}
157
159 """Fired when a mouse button is pressed."""
160 __slots__ = ()
161 type = 'MOUSEDOWN'
162
164 """Fired when a mouse button is released."""
165 __slots__ = ()
166 type = 'MOUSEUP'
167
169 """Fired when the mouse is moved."""
170 __slots__ = ('pos', 'motion', 'cell', 'cellmotion')
171 type = 'MOUSEMOTION'
172
173 - def __init__(self, pos, cell, motion, cellmotion):
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 self.motion = motion
181 """(x, y) motion of the mouse on the screen.
182 type: (int, int)"""
183 self.cellmotion = cellmotion
184 """(x, y) mostion of the mouse moving over cells on the root console.
185 type: (int, int)"""
186
188 """
189 Application framework.
190
191 - ev_*: Events are passed to methods based on their L{Event.type} attribute.
192 If an event type is 'KEYDOWN' the ev_KEYDOWN method will be called
193 with the event instance as a parameter.
194
195 - key_*: When a key is pressed another method will be called based on the
196 keyname attribute. For example the 'ENTER' keyname will call key_ENTER
197 with the associated L{KeyDown} event as its parameter.
198
199 - L{update}: This method is called every loop before making a call to
200 L{tdl.flush}. It is passed a single parameter detailing the time in
201 seconds since the last update (often known as deltaTime.)
202 """
203 __slots__ = ('__running')
204 __running = False
205
207 """Unless overridden this method raises a SystemExit exception closing
208 the program."""
209 raise SystemExit()
210
212 "Override this method to handle this event."
213
215 "Override this method to handle this event."
216
218 "Override this method to handle this event."
219
221 "Override this method to handle this event."
222
224 "Override this method to handle this event."
225
227 """Override this method to handle per frame logic and drawing.
228
229 @type deltaTime: float
230 @param deltaTime: This parameter tells the amount of time passed since
231 the last call measured in seconds as a floating point
232 number.
233
234 You can use this variable to make your program
235 frame rate independent.
236 """
237 pass
238
240 """When called the App will begin to return control to where
241 L{App.run} was called.
242
243 No further events are processed and the L{App.update} method will be
244 called one last time before exiting
245 (unless suspended during a call to L{App.update}.)
246 """
247 self.__running = False
248
250 """Delegate control over to this App instance. This function will
251 process all events and send them to the special methods ev_* and key_*.
252
253 A call to L{App.suspend} will return the control flow back to where
254 this function is called. And then the App can be run again.
255 But a single App instance can not be run multiple times simultaneously.
256 """
257 if self.__running:
258 raise _tdl.TDLError('An App can not be run multiple times simultaneously')
259 self.__running = True
260 prevTime = time.clock()
261 while self.__running:
262 for event in get():
263 if event.type:
264
265 method = 'ev_%s' % event.type
266 getattr(self, method)(event)
267 if event.type == 'KEYDOWN':
268
269 method = 'key_%s' % event.key
270 if hasattr(self, method):
271 getattr(self, method)(event)
272 if not self.__running:
273 break
274 newTime = time.clock()
275 self.update(newTime - prevTime)
276 prevTime = newTime
277 _tdl.flush()
278
280 """Flushes the event queue from libtcod into the global list _eventQueue"""
281 global _mousel, _mousem, _mouser, _eventsflushed, _pushedEvents
282 _eventsflushed = True
283 events = _pushedEvents
284 _pushedEvents = []
285
286 mouse = _Mouse()
287 libkey = _Key()
288 while 1:
289 libevent = _lib.TCOD_sys_check_for_event(_tcod.TCOD_EVENT_ANY, libkey, mouse)
290 if not libevent:
291 break
292
293
294 if libevent & _tcod.TCOD_EVENT_MOUSE_MOVE:
295 events.append(MouseMotion(*mouse.motion))
296
297 mousepos = ((mouse.x, mouse.y), (mouse.cx, mouse.cy))
298
299 for oldstate, newstate, released, button in zip((_mousel, _mousem, _mouser),
300 mouse.button, mouse.button_pressed, (1, 2, 3)):
301 if released:
302 if not oldstate:
303 events.append(MouseDown(button, *mousepos))
304 events.append(MouseUp(button, *mousepos))
305 if newstate:
306 events.append(MouseDown(button, *mousepos))
307 elif newstate and not oldstate:
308 events.append(MouseDown(button, *mousepos))
309
310 if mouse.wheel_up:
311 events.append(MouseDown(4, *mousepos))
312 if mouse.wheel_down:
313 events.append(MouseDown(5, *mousepos))
314
315 _mousel = mouse.lbutton
316 _mousem = mouse.mbutton
317 _mouser = mouse.rbutton
318
319 if libkey.vk == _tcod.K_NONE:
320 break
321 if libkey.pressed:
322 keyevent = KeyDown
323 else:
324 keyevent = KeyUp
325 events.append(keyevent(*tuple(libkey)))
326
327 if _lib.TCOD_console_is_window_closed():
328 events.append(Quit())
329
330 _eventQueue.extend(events)
331
333 """Flushes the event queue and returns the list of events.
334
335 This function returns L{Event} objects that can be indentified by their
336 type attribute or their class.
337
338 @rtype: iterator
339 """
340 _processEvents()
341 while _eventQueue:
342
343
344
345 yield(_eventQueue.pop(0))
346 raise StopIteration()
347
349 """Push an event into the event buffer.
350
351 @type event: L{Event}-like object
352 @param event: The event will be available on the next call to L{event.get}. An event
353 pushed in the middle of a get will not show until the next time it's called.
354 This prevents infinite loops.
355 """
356 _pushedEvents.append(event)
357
359 """Waits until the user presses a key. Then returns a L{KeyDown} event.
360
361 @rtype: L{KeyDown}
362 """
363 global _eventsflushed
364 _eventsflushed = True
365 flush = False
366 libkey = _Key()
367 _lib.TCOD_console_wait_for_keypress_wrapper(libkey, flush)
368 return KeyDown(*libkey)
369
371 """Returns True if the exit button on the window has been clicked and
372 stays True afterwards.
373
374 @rtype: boolean
375 """
376 return _lib.TCOD_console_is_window_closed()
377
378 __all__ = [_var for _var in locals().keys() if _var[0] != '_' and _var not in ['time', 'ctypes']]
379