This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
api:event [2016/02/29 17:59] payonel [Overview] |
api:event [2016/06/16 08:14] payonel |
||
---|---|---|---|
Line 13: | Line 13: | ||
//Note:// While it is technically possible to do both at the same time it is not recommended to do so. To make sure that events are received by all registered functions, they are consumed only after all functions have been called. So if you register your handler and pull at the same time, you would receive events twice. | //Note:// While it is technically possible to do both at the same time it is not recommended to do so. To make sure that events are received by all registered functions, they are consumed only after all functions have been called. So if you register your handler and pull at the same time, you would receive events twice. | ||
- | |||
- | ===== Interrupts ===== | ||
- | Interrupts are working during `event.pull*()` methods. They are mean to forcibly return form the function. They are especially useful when `event.pull*()` is called without time limit and filter. In some cases this means that `event.pull*()` could be waiting indefinitely. | ||
- | |||
- | There are two types of interrupts: | ||
- | |||
- | - Soft interrupt is called on `Ctrl+C` keys combination and is only effective if `event.pull*()` allows for returning this type of event (`"interrupted"`). It also returns one additional result which is time spent in `event.pull*()`. | ||
- | - Hard interrupt is run on `Ctrl-Alt-C` keys combination. It forcibly exits the `event.pull*()` method by throwing a `"interrupted"` error. | ||
- | |||
- | ===== Basic event handling ===== | ||
- | The primary functionality uses the function `event.pull()` to get the top event currently in the queue, or - if there is currently no event - puts the program on hold until one is available. | ||
- | |||
- | A simple example primary event handler: | ||
- | ```lua | ||
- | local event = require "event" -- load event table and store the pointer to it in event | ||
- | |||
- | local char_space = string.byte(" ") -- numerical representation of the space char | ||
- | local running = true -- state variable so the loop can terminate | ||
- | |||
- | function unknownEvent() | ||
- | -- do nothing if the event wasn't relevant | ||
- | end | ||
- | |||
- | -- table that holds all event handlers, and in case no match can be found returns the dummy function unknownEvent | ||
- | local myEventHandlers = setmetatable({}, { __index = function() return unknownEvent end }) | ||
- | |||
- | -- Example key-handler that simply sets running to false if the user hits space | ||
- | function myEventHandlers.key_up(adress, char, code, playerName) | ||
- | if (char == char_space) then | ||
- | running = false | ||
- | end | ||
- | end | ||
- | |||
- | -- The main event handler as function to separate eventID from the remaining arguments | ||
- | function handleEvent(eventID, ...) | ||
- | if (eventID) then -- can be nil if no event was pulled for some time | ||
- | myEventHandlers[eventID](...) -- call the appropriate event handler with all remaining arguments | ||
- | end | ||
- | end | ||
- | |||
- | -- main event loop which processes all events, or sleeps if there is nothing to do | ||
- | while running do | ||
- | handleEvent(event.pull()) -- sleeps until an event is available, then process it | ||
- | end | ||
- | ``` | ||
- | |||
- | If you work in driver mode, you need to register the events instead, by either registering a global event handler like the one in the example above, or by registering each individual handler on its own. If you would write the example above to work in the background, the `while running do` loop would be replaced like this: | ||
- | ```lua | ||
- | event.listen("key_up", handleEvent) -- register handleEvent to be called on key_up then end the program | ||
- | ``` | ||
- | It would also be possible to register `myEventHandlers.key_up` directly, in which case it would receive an additional parameter (the event name) as the first parameter. | ||
- | |||
- | **Important:** If you use event handling in driver mode, then event functions will be called from the environment of the OS event handler and variables local to your program will **not** be visible! | ||
===== Functions ===== | ===== Functions ===== | ||
Line 144: | Line 91: | ||
Global event callback error handler. If an event listener throws an error, we handle it in this function to avoid it bubbling into unrelated code (that only triggered the execution by calling `event.pull`). Per default, this logs errors into a file on the temporary file system. | Global event callback error handler. If an event listener throws an error, we handle it in this function to avoid it bubbling into unrelated code (that only triggered the execution by calling `event.pull`). Per default, this logs errors into a file on the temporary file system. | ||
You can replace this function with your own if you want to handle event errors in a different way. | You can replace this function with your own if you want to handle event errors in a different way. | ||
+ | |||
+ | ===== Interrupts ===== | ||
+ | Interrupts are a type of messaging intended to close or stop a process. In OpenOS the `event.pull*()` methods generate the two types of interrupts. | ||
+ | |||
+ | They are especially useful when `event.pull*()` is called without time limit and without filter. In some cases this means that `event.pull*()` could be waiting indefinitely. | ||
+ | |||
+ | - Soft interrupts are generated by pressing `Ctrl+C` and is only effective if `event.pull*()` allows for returning this type of event (`"interrupted"`). It also returns one additional result which is time spent in `event.pull*()`. | ||
+ | - Hard interrupts are generated by pressing `Ctrl-Alt-C`. It forcibly exits the `event.pull*()` method by throwing a `"interrupted"` error. | ||
+ | |||
+ | ===== Basic event example ===== | ||
+ | Typically user scripts care about one or two events, and don't care to handle the rest. It is good to handle "interrupted" for soft interrupts. | ||
+ | |||
+ | ```lua | ||
+ | while true do | ||
+ | local id, _, x, y = event.pullMultiple("touch", "interrupted") | ||
+ | if id == "interrupted" then | ||
+ | print("soft interrupt, closing") | ||
+ | break | ||
+ | elseif id == "touch" then | ||
+ | print("user clicked", x, y) | ||
+ | end | ||
+ | end | ||
+ | ``` | ||
+ | |||
+ | ===== General purpose event handler ===== | ||
+ | Here is a clever solution for providing a general purpose event handler. In this example the primary functionality uses the event id returned by `event.pull()` as a key for a table of callbacks, using metamethods to handle undefined events. Note that `event.pull` puts the program on hold until there is an event available. | ||
+ | |||
+ | ```lua | ||
+ | local event = require "event" -- load event table and store the pointer to it in event | ||
+ | |||
+ | local char_space = string.byte(" ") -- numerical representation of the space char | ||
+ | local running = true -- state variable so the loop can terminate | ||
+ | |||
+ | function unknownEvent() | ||
+ | -- do nothing if the event wasn't relevant | ||
+ | end | ||
+ | |||
+ | -- table that holds all event handlers | ||
+ | -- in case no match can be found returns the dummy function unknownEvent | ||
+ | local myEventHandlers = setmetatable({}, { __index = function() return unknownEvent end }) | ||
+ | |||
+ | -- Example key-handler that simply sets running to false if the user hits space | ||
+ | function myEventHandlers.key_up(adress, char, code, playerName) | ||
+ | if (char == char_space) then | ||
+ | running = false | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- The main event handler as function to separate eventID from the remaining arguments | ||
+ | function handleEvent(eventID, ...) | ||
+ | if (eventID) then -- can be nil if no event was pulled for some time | ||
+ | myEventHandlers[eventID](...) -- call the appropriate event handler with all remaining arguments | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- main event loop which processes all events, or sleeps if there is nothing to do | ||
+ | while running do | ||
+ | handleEvent(event.pull()) -- sleeps until an event is available, then process it | ||
+ | end | ||
+ | ``` | ||
+ | |||
+ | |||
+ | If you work in driver mode, you need to register the events instead, by either registering a global event handler like the one in the example above, or by registering each individual handler on its own. If you would write the example above to work in the background, the `while running do` loop would be replaced like this: | ||
+ | |||
+ | ```lua | ||
+ | event.listen("key_up", handleEvent) -- register handleEvent to be called on key_up then end the program | ||
+ | ``` | ||
+ | It would also be possible to register `myEventHandlers.key_up` directly, in which case it would receive an additional parameter (the event name) as the first parameter. | ||
Contents | Contents | ||
----------- | ----------- | ||
{{page>api:contents&noheader&noeditbutton&nouser&nofooter}} | {{page>api:contents&noheader&noeditbutton&nouser&nofooter}} |