Table of Contents

Event(事件) API

Event(事件) API为用户提供了一套基本的事件处理系统,可利用其编写代码以响应操作系统或其他程序/运行库传递的信号

例如,你可以利用此API捕获按下的按键、在外接显示器连接到电脑或断开连接时进行响应,或是处理传入的网络信息。

概述

event API主要有两种用法:

在驱动模式下,你的程序需要先为事件注册回调函数(用 event.listen()函数),然后退出,以继续执行主程序(通常是shell)。
在优先模式下,你无需在程序中注册事件,可以直接使用events.pull()函数拉取并处理信号。

注意:虽然从技术层面上讲可以同时使用两种工作模式,但不推荐这样做。为了保证所有已注册的函数都能接收到事件,事件只有在所有函数均被调用后才会被消耗掉。因此如果你注册了处理函数,同时又进行了拉取,那么同一个事件会被响应两次。

函数

样例:

snippet.lua
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表中的玩家触发的事件。

中断

在OpenOS 1.6.4及更高版本,中断功能已经被删除。下列两个函数现在已经过时。

中断是一类用于关闭或停止进程的消息。在OpenOS中computer.pullSignal()函数及其封装会产生两种类型的事件。

event.pull*()函数在指定了过滤器但不指定超时时间的情况下执行,一定情况下意味着无限期执行。这两种事件非常有用。

简易事件处理样例

通常用户编写的脚本只会涉及一两个事件,不涉及其他事件的处理。建议将“interrupted”事件作为软件中断处理。

snippet.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

通用事件处理函数

此处提供了一个较好的通用事件处理函数。此样例的主要功能是以event.pull()函数返回的事件名称作为回调函数列表的键,用元方法来处理未定义事件。请注意event.pull函数会让程序进入等待状态,直到出现可用事件。

snippet.lua
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循环需要替换为类似下面的代码:

snippet.lua
event.listen("key_up", handleEvent) --注册handleEvent函数,使其在key_up事件发生时被调用,然后结束程序

也可以直接注册myEventHandlers.key_up,这样的话处理函数会额外收到一个参数(事件名称)作为第一个参数。

目录