Builtin Library
README.md
events
Frame-event readers and edge-event subscriptions. Wraps the internal
__zero_input.events() FFI with per-kind filters and a push-style
on/off API that fires from Zin.tick. Backs Zin.events.
__zero_input.events() returns the current frame's events in
dispatch order; reading does not consume them. Subscription dispatch
happens during Zin.tick (or Zin.autoTick.start()'s worker), so
without a tick host on() callbacks never fire.
Exports
M.frame() -> { InputEvent }— this frame's events in dispatch order.M.iter() -> iterator—ipairsoverframe(); reads better at call sites.M.keysDown / keysUp / mouseDowns / mouseUps / mouseMoves / mouseWheels / texts() -> { InputEvent }— per-kind filters.M.on(filter: EventFilter, callback, opts: SubOpts?) -> SubHandle— register an edge subscriber, returns handle.M.off(handle: SubHandle | number)— cancel a subscriber.M.clearSubscribers()— drop all subscribers (test isolation).M.subscriberCount() -> number— current subscriber count.M._dispatch(events)— internal; called byZin.tick.
Types:
InputEvent = { [string]: any }— one entry of the frame event log.EventFilter = string | { [string]: any } | (any) -> booleanSubOpts = { context: string?, once: boolean?, priority: number? }SubHandle = { id: number, off: () -> () }
Usage
local Zin = require("@builtin::modules.zinput")
for _, ev in ipairs(Zin.events.frame()) do
if ev.kind == "key.down" and ev.code == "Space" then
-- jump on the press edge, not on every frame the key is held
end
end
local h = Zin.events.on({ kind = "key.down", code = "Escape" }, function(ev, gpe)
if not gpe then closeMenu() end
end, { context = "ui" })
-- later: h.off()
Notes
- Reading
frame()is non-destructive — multiple consumers can iterate the same frame's events. The log clears at end-of-frame and is rebuilt next frame. - Subscribers dispatch in priority-desc order; equal priorities preserve
insertion order. Returning
"sink"from a callback halts further dispatch for that single event (lower-priority subscribers skipped). once = truesubscribers auto-unsubscribe after their first matching dispatch.- A subscription ends with the context that made it as well as with
off: one a component makes ends when that component instance goes (removed, hot-reloaded, or its entity despawned), one a module body makes at the module's next run.scopes.list()names each as aluaurow under the context it follows. - Subscriber errors are caught and logged via
log.warn; one bad handler doesn't break dispatch.