.. top: Events ====== Events are generated by the windowing back-end whenever user interaction occurs. The nature of the events will vary a little according to which windowing system is in use, but they generally follow the following pattern. An `Event` instance is created for each event and is passed down a cascade of handlers attached to the `World`. Handlers can be attached either using the `.SetEventHandler()` method:: def handler( self, event ): print( event ) w = Shady.World().SetEventHandler( handler, slot=-1 ) or using the decorator version of the same operation, simply called `.EventHandler()`:: w = Shady.World() @w.EventHandler( slot=-1 ) def handler( self, event ): print( event ) In either case, note the `slot` argument: a given slot number can be associated with only one handler, and handlers are run in increasing numeric order of their slot. The default handler---the `Shady.World.HandleEvent` method that closes the `World` when the user presses either q or the escape key---occupies the default `slot=0` and can be replaced by specifying a different function in that slot. If a handler returns a truthy return value, the cascade is halted ("I handled that event so you don't have to"). The best way to understand how to match events is to install the `print(event)` handler as in the examples above, and observe what is printed to the console. You can also explore the demo script :doc:`examples/events.py `. You will see that every `Event` instance has a `.type` string, a timestamp `.t` in seconds, and an `.abbrev` string. It may also have other attributes that depend on the `.type`. In Shady's default windowing back-end (the GLFW-based binary accelerator library), possible `.type` values include:: ================== ========================= =========== .type other relevant attributes .abbrev ================== ========================= =========== 'window_focus' wf 'window_unfocus' wu 'mouse_enter' me 'mouse_leave' ml 'mouse_motion' .x .y .dx .dy .modifiers mm 'mouse_press' .x .y .button .modifiers mp[button] 'mouse_release' .x .y .button .modifiers mr[button] 'key_press' .key .modifiers kp[key] 'key_auto' .key .modifiers ka[key] 'key_release' .key .modifiers kr[key] 'text' .text t[text] ================== ========================= =========== The `.modifiers` attribute is a space-delimited string containing zero or more of the words `'shift ctrl super alt num'` (in arbitrary order) showing which modifier keys, if any, were held down when the event occurred. If a key-press (or key auto-repeat) would normally result in a character being typed, then an `Event` with `type='text'` is generated separately from, and immediately after, the corresponding `Event` with `type='key_press'` or `type='key_auto'`. The `.text` attribute of the second event will contain the character or characters typed (including case inflection), whereas the prior event will have a `.key` attribute denoting (always in lower case) the label on the cap of the key that produced it. If modifier keys were used, there will also be separate `key_press` and `key_release` events corresponding to each modifier key---these events will not produce `text` events of their own. Note that (in contrast to the `.modifier` substrings, which may simply denote that a logical shift or ctrl modifier applies) key-related events for the modifier keys themselves may tell you which *physical* modifier key was pressed, for example as `key='lshift' or `key='rshift'`. The `.abbrev` attribute is not used directly but it provides a hint for how you can match the event more concisely. Your event-matching code does not need to use this---it can contain code like:: if event.type == 'key_press' and event.key == ' ' and .... but this can get very long-winded. You can often perform the same task more quickly using `.abbrev` codes in conjunction with the `>>` operator:: def handler(world, e): if e >> 'kp[ ]': print('you pressed the space bar!') if e >> 'kp[return]': print('you pressed the return key!') An event-matching string can have modifiers, in any order you like and this time delimited by `+`, prepended to it. So, while `'kp[ ]'` on its own will match any pressing of the space-bar regardless of modifiers, you can be more specific as to the modifier combination you are looking for (including, if desired, the specifier `'none'`):: e >> 'ctrl+kp[c]' # matches only ctrl-c e >> 'ctrl+shift+kp[c]' # matches only ctrl-shift-c e >> 'none+kp[c]' # matches only a `c` key-press WITHOUT mods e >> 'kp[c]' # matches any of the above (and other mods) You can match multiple possibilities at once by delimiting them with whitespace in the matching string:: e >> 'ctrl+kp[c] shift+kp[c]' # matches ctrl-c OR shift-c (only) (This means you should not use whitespace *inside* each matching code, with the exception of a space-inside-square-brackets for matching the space bar, as in `'kp[ ]'`, or space character, as in `'t[ ]'`.) See the demo script :doc:`examples/events.py ` for more.