MineOS/Libraries/Event.lua
2022-05-06 19:52:53 +03:00

141 lines
3.5 KiB
Lua
Executable File

local event, handlers, interruptingKeysDown, lastInterrupt = {
interruptingEnabled = true,
interruptingDelay = 1,
defaultInterruptingFunction = function()
error("interrupted", 0)
end,
interruptingKeyCodes = {
[29] = true,
[46] = true,
[56] = true
},
push = computer.pushSignal
}, {}, {}, 0
event.interruptingFunction = event.defaultInterruptingDFunction
local computerPullSignal, computerUptime, mathHuge, mathMin, skipSignalType = computer.pullSignal, computer.uptime, math.huge, math.min
--------------------------------------------------------------------------------------------------------
function event.addHandler(callback, interval, times)
checkArg(1, callback, "function")
checkArg(2, interval, "number", "nil")
checkArg(3, times, "number", "nil")
local handler = {
callback = callback,
times = times or mathHuge,
interval = interval,
nextTriggerTime = interval and computerUptime() + interval or 0
}
handlers[handler] = true
return handler
end
function event.removeHandler(handler)
checkArg(1, handler, "table")
if handlers[handler] then
handlers[handler] = nil
return true
else
return false, "Handler with given table is not registered"
end
end
function event.getHandlers()
return handlers
end
function event.skip(signalType)
skipSignalType = signalType
end
function event.pull(preferredTimeout)
local uptime, signalData = computerUptime()
local deadline = uptime + (preferredTimeout or mathHuge)
repeat
-- Determining pullSignal timeout
timeout = deadline
for handler in pairs(handlers) do
if handler.nextTriggerTime > 0 then
timeout = mathMin(timeout, handler.nextTriggerTime)
end
end
-- Pulling signal data
signalData = { computerPullSignal(timeout - computerUptime()) }
-- Handlers processing
for handler in pairs(handlers) do
if handler.times > 0 then
uptime = computerUptime()
if
handler.nextTriggerTime <= uptime
then
handler.times = handler.times - 1
if handler.nextTriggerTime > 0 then
handler.nextTriggerTime = uptime + handler.interval
end
-- Callback running
handler.callback(table.unpack(signalData))
end
else
handlers[handler] = nil
end
end
-- Program interruption support. It's faster to do it here instead of registering handlers
if (signalData[1] == "key_down" or signalData[1] == "key_up") and event.interruptingEnabled then
-- Analysing for which interrupting key is pressed - we don't need keyboard API for this
if event.interruptingKeyCodes[signalData[4]] then
interruptingKeysDown[signalData[4]] = signalData[1] == "key_down" and true or nil
end
local shouldInterrupt = true
for keyCode in pairs(event.interruptingKeyCodes) do
if not interruptingKeysDown[keyCode] then
shouldInterrupt = false
end
end
if shouldInterrupt and uptime - lastInterrupt > event.interruptingDelay then
lastInterrupt = uptime
event.interruptingFunction()
end
end
-- Loop-breaking condition
if signalData[1] then
if signalData[1] == skipSignalType then
skipSignalType = nil
else
return table.unpack(signalData)
end
end
until uptime >= deadline
end
-- Sleeps "time" of seconds via "busy-wait" concept
function event.sleep(time)
checkArg(1, time, "number", "nil")
local deadline = computerUptime() + (time or 0)
repeat
event.pull(deadline - computerUptime())
until computerUptime() >= deadline
end
--------------------------------------------------------------------------------------------------------
return event