Event(事件) API为用户提供了一套基本的事件处理系统,可利用其编写代码以响应操作系统或其他程序/运行库传递的信号。
例如,你可以利用此API捕获按下的按键、在外接显示器连接到电脑或断开连接时进行响应,或是处理传入的网络信息。
event API主要有两种用法:
在驱动模式下,你的程序需要先为事件注册回调函数(用 event.listen()
函数),然后退出,以继续执行主程序(通常是shell)。
在优先模式下,你无需在程序中注册事件,可以直接使用events.pull()
函数拉取并处理信号。
注意:虽然从技术层面上讲可以同时使用两种工作模式,但不推荐这样做。为了保证所有已注册的函数都能接收到事件,事件只有在所有函数均被调用后才会被消耗掉。因此如果你注册了处理函数,同时又进行了拉取,那么同一个事件会被响应两次。
event.listen(event: string, callback: function): boolean
number
,代表了事件id,可用于传递给event.cancel
函数取消事件。若函数已经注册过此类事件,将会返回false
。event.ignore(event: string, callback: function): boolean
true
。若指定的函数并未注册到此类事件则返回false
。false
后将会注销自身。等价于调用 event.ignore
,并向其传递侦听器函数与所注册的事件名称。event.timer(interval: number, callback: function[, times: number]): number
interval
指定的时长后将会被触发。math.huge
可以无限次重复调用。event.cancel(timerId: number): boolean
event.timer
函数创建的定时器。event.timer
函数返回的定时器id。true
。若不存在指定id对应的定时器则返回false
。event.pull([timeout: number], [name: string], ...): string, ...
nil
。nil
,此时事件名称不会被过滤。模式字符串的使用可参考string.match
函数。nil
,这样将不会过滤此参数。touch
信号(在玩家点击2级或3级显示器时触发)带有如下参数: screenX: number, screenY: number, playerName: string
(点击处的X、Y坐标,进行点击的玩家ID)local _, x, y = event.pull("touch", nil, nil, "Steve")
event.pullFiltered([timeout: number], [filter: function]): string, ...
(自1.5.9起添加)nil
。样例:
local allowedPlayers = {"Kubuxu", "Sangar", "Magik6k", "Vexatos"} local function filter(name, ...) if name ~= "key_up" and name ~= "key_down" and name ~= "touch" then return false end local nick if name == "touch" then nick = select(3, ...) else nick = select(4, ...) end for _, allowed in ipairs(allowedPlayers) do if nick == allowed then return true end end return false end local e = {event.pullFiltered(filter)} --程序将会不限时等待拉取key_up、key_down和click事件。过滤器会确保只拉取allowedPlayers表中的玩家触发的事件。
event.pullMultiple(...): ...
(自1.5.9起添加)pullMultiple
函数可接收多个要拉取的事件名称作为参数,同时支持基本的过滤功能。event.onError(message: any)
events.pull
函数触发函数执行的代码)。默认情况下,此函数会将报错信息记录到临时文件系统中的文件。event.push(name: string[, ...])
event.pull
,添加此别名会更符合逻辑。在OpenOS 1.6.4及更高版本,中断功能已经被删除。下列两个函数现在已经过时。
event.shouldSoftInterrupt(): boolean
(自1.5.9起添加,在1.6.4被移除)event.shouldInterrupt(): boolean
(自1.5.9起添加,在1.6.4被移除)
中断是一类用于关闭或停止进程的消息。在OpenOS中computer.pullSignal()
函数及其封装会产生两种类型的事件。
若event.pull*()
函数在指定了过滤器但不指定超时时间的情况下执行,一定情况下意味着无限期执行。这两种事件非常有用。
Ctrl+C
时产生的事件信号。信号包含两个参数,事件名称"interrupted"
和电脑运行时间。
Ctrl-Alt-C
时产生。它会通过抛出"interrupted"
异常以强制退出event.pull*()
函数。通常用户编写的脚本只会涉及一两个事件,不涉及其他事件的处理。建议将“interrupted”事件作为软件中断处理。
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
此处提供了一个较好的通用事件处理函数。此样例的主要功能是以event.pull()
函数返回的事件名称作为回调函数列表的键,用元方法来处理未定义事件。请注意event.pull
函数会让程序进入等待状态,直到出现可用事件。
local event = require "event" --加载事件列表,将指向它们的指针存储到event变量中 local char_space = string.byte(" ") --用数字代替空格字符 local running = true --存储状态的变量,便于循环停止执行 function unknownEvent() --如果事件为无关事件,则不进行处理 end --存储所有事件处理函数的列表 --会返回占位伪函数unknownEvent,以防无法匹配 local myEventHandlers = setmetatable({}, { __index = function() return unknownEvent end }) --简易按键处理函数样例,当用户按下空格键时将running变量设为false function myEventHandlers.key_up(adress, char, code, playerName) if (char == char_space) then running = false end end --主事件处理函数,将事件ID(eventID)从其他参数中分离出来 function handleEvent(eventID, ...) if (eventID) then --如果一段时间内没有事件被拉取,值可能为nil myEventHandlers[eventID](...) --调用对应的事件处理函数,并传递剩下的所有参数 end end --主事件拉取循环,处理所有事件。在没有任务时会等待。 while running do handleEvent(event.pull()) --等待可用事件出现,然后进行处理 end
如果程序以驱动模式运作,你需要注册事件而不是拉取事件。你可以将所有事件注册到像上面样例一样的全局事件处理函数,也可以将每个事件注册到对应的处理函数。如果你希望上面的样例在后台运行,while running do
循环需要替换为类似下面的代码:
event.listen("key_up", handleEvent) --注册handleEvent函数,使其在key_up事件发生时被调用,然后结束程序
也可以直接注册myEventHandlers.key_up
,这样的话处理函数会额外收到一个参数(事件名称)作为第一个参数。