input
The input namespace: 41 functions.
input/armObservation
input.armObservation(on: boolean?)
Hold the input observation's mapping half open (true, the default) or close it now (false). A read arms it for a window of frames on its own, so this is for a test or a tool that wants the mapping half building continuously, or wants to stop paying for it the moment it is done.
Parameters
onboolean?— Arm (default) or disarm.
input/backUnanswered
input.backUnanswered()
Hand a Back press the script holding Back took back to the platform's own default, because no claim was held when it arrived. Internal: backs Zin.back.
input/emulateKeyDown
input.emulateKeyDown(code)
The input-emulation floor's write surface: mark code held by the floor. Merged into the default polling views (isDown, snapshot().keys) so Zin.state.keyDown cannot tell an emulated hold from a real one; tracked separately in snapshot().keys_emulated, and readable real-only via Zin.state.keyDownReal. Drained before the next frame's controller scripts run, like simulate* — but pushes no frame event and is never forwarded to the UI layer: emulated input exists for polling surfaces, and event-driven consumers already receive the real touch events the floor was driven from. code is resolved against the KeyboardEvent.code vocabulary, so an emulated hold is held under the code content reads; a name outside it raises. Internal — backs the map-driven emulation floor.
Parameters
codestring— Key code
input/emulateKeyUp
input.emulateKeyUp(code)
Release code from the input-emulation floor. Only lifts the held state if a real key-press hasn't since claimed the code (real press owns the key). code is resolved against the KeyboardEvent.code vocabulary, and a name outside it raises. No frame event, no UI forwarding. Internal — backs the map-driven emulation floor.
Parameters
codestring— Key code in KeyboardEvent.code form ("KeyW", "Space", "ShiftLeft"), or a single letter or digit
input/emulateMouseButton
input.emulateMouseButton(button, held)
Set emulated mouse button button (0=left, 1=right, 2=middle) held/released from the input-emulation floor. Mirrors emulateKeyDown/emulateKeyUp: a real mouse press owns the button thereafter. No frame event, no UI forwarding. Internal — backs the map-driven emulation floor.
Parameters
buttonnumber— Button index (0=left, 1=right, 2=middle)heldboolean— True to hold, false to release
input/emulateMouseDelta
input.emulateMouseDelta(dx, dy)
Accumulate an emulated mouse-delta contribution from the input-emulation floor into this frame's mouse_delta. No frame event, no UI forwarding. Internal — backs the map-driven emulation floor.
Parameters
dxnumber— Delta Xdynumber— Delta Y
input/events
input.events() -> {table}
Get the current frame's input events as an array of { kind = '...', ... } records in dispatch order. Internal — Zin wraps this as Zin.events.frame(). Variants produced today: key.down { code, repeat }, key.up { code }, mouse.down { button, x, y }, mouse.up { button, x, y }, mouse.move { x, y, dx, dy }, mouse.wheel { dx, dy }, text { text }, touch.down { id, x, y, pressure }, touch.move { id, x, y, dx, dy, pressure }, touch.up { id, x, y }, touch.cancel { id }, gamepad.connected { slot, name }, gamepad.disconnected { slot }, gamepad.down { slot, button }, gamepad.up { slot, button }, gamepad.axis { slot, axis, value }. Returns an empty array if no events have been published yet. Cleared at end of frame (PostRender). Reading does not consume.
Returns {table} — Frame events in dispatch order
input/frameId
input.frameId() -> integer
Get the engine's monotonic frame counter. Bumped once per frame at PostRender. Internal — used by Zin.tick to dedup cross-coroutine double-ticks within the same engine frame. Stable across multiple reads inside the same frame, strictly greater after a task.wait(0) yield. Returns 0 only before the very first frame has elapsed.
Returns integer — Monotonic frame counter
input/isAnyDown
input.isAnyDown({name, ...}) -> boolean, string?
Are any of the given keys currently held? Returns held, which: when any key in the array is held, held=true and which is the first matched code (in iteration order); otherwise false, nil. Internal — used by Zin.
Parameters
names{string}— Array of key codes to check
Returns boolean, string? — (held, first matched code or nil)
input/isDown
input.isDown(name) -> boolean
Is the given key currently held this frame? Internal — Zin wraps this as Zin.state.keyDown(name). Direct lookup on the published snapshot's keys array.
Parameters
namestring— Key code (e.g. "KeyD", "Space", "ShiftLeft")
Returns boolean — True if the key is held this frame
input/markBaseline
input.markBaseline() -> number
Read every device as it stands — the keys and buttons held, the contacts down, the pads connected and what they hold, the pointer's position and lock, the UI focus pin, the scene context and the touch and pad capabilities — and make that reading the state input.resetToBaseline puts the devices back to. The reading is taken where the call lands in the queue of simulated input, so input queued before it is inside the reading and input queued after it is not. A caller that runs in someone else's engine — a sweep of test suites sharing one — marks before it begins, so what it leaves held is let go for the next.
Returns number — The mark's generation, counting from 1 — what input.resetToBaseline takes to restore to this mark.
local mark = input.markBaseline()
input/observationArmedFrames
input.observationArmedFrames() -> integer
How many more frames the arming window has left before a mapping layer stops building its half of the input observation. A read of input.observe() or of /runtime/input sets it back to the full window; every frame that passes takes one off it, and 0 means nothing is observing.
Returns integer — Frames left in the arming window.
input/observationWanted
input.observationWanted() -> boolean
Whether something has read the input observation recently enough that a mapping layer should spend a frame building its half of it. A read of input.observe() or of /runtime/input arms this for a window of frames; a world nobody is observing reads false and pays nothing. Internal — the mapping layer's per-frame tick consults it.
Returns boolean — Whether a mapping report is wanted this frame.
input/observe
input.observe() -> table
Report what the input layer did with the last completed frame: every device event that arrived with the surface it came from and whether the UI took it (consumed_by_ui), the pointer-lock quartet, which focus the UI holds, what device classes the session has, and — while the mapping layer is publishing — its account of which controls those events became and why a live control stayed silent. The observation covers ONE engine frame, the frame that has just been drawn; a read taken from a script during frame N answers for frame N-1. Reading consumes nothing and clears nothing, so any number of observers see the same frame. mappingStatus says whether the mapping half is current, stale, arming (this read armed it — read again), or unarmed. Serialised from the same document /runtime/input serves.
Returns table — The engine's current input observation.
input/pressBack
input.pressBack()
Press Back, routed the way the platform's own Back is: the topmost overlay that states how it is dismissed is dismissed, else the script holding Back takes it, else the platform's own default answers it (an Android app moves to the background). The press is a back event naming its taker. Internal: backs Zin.back.press.
input/publishMapping
input.publishMapping(report: table)
Publish the mapping layer's account of this frame into the engine's input observation, where input.observe() and the /runtime/input node serve it beside the device half. Internal — called once per frame by the mapping layer's tick while input.observationWanted() holds.
Parameters
reporttable— The mapping layer's report for this frame.
input/releaseBaseline
input.releaseBaseline(generation)
Drop the reading input.markBaseline took under generation, and every reading taken after it, once the caller that took it is done resetting to it. The devices stay as they stand. It lands in the queue of simulated input after everything queued before it, so a reset queued first still reads the mark it names.
Parameters
generationnumber— The mark to drop, asinput.markBaselinereturned it.
input.releaseBaseline(mark)
input/releasePointerLock
input.releasePointerLock()
Release pointer lock (cursor ungrab + show). Internal — backs Zin.pointer.unlock().
input/releaseUiFocus
input.releaseUiFocus()
Give the UI's focus pair back to the UI pass, which writes its own opinion on its next run. Internal — backs Zin.test.releaseUiFocus().
input/requestPointerLock
input.requestPointerLock()
Request pointer lock (cursor grab + hide). Internal — backs Zin.pointer.lock().
input/resetToBaseline
input.resetToBaseline(generation?) -> number
Put every device back to the reading input.markBaseline took: a key or button held since is released and one held then is pressed again, a contact begun since is lifted, a pad this surface connected since is unplugged and what a pad holds is put back, the pointer returns to its position and its lock to what it was, and the UI focus pin, the scene context and the touch and pad capabilities read as they did. Each change travels the path the device's own event takes, so the UI learns of a release the way it learned of the press. The restore lands with the next drain of simulated input, one frame on.
Parameters
generationnumber(optional) — The mark to restore to, asinput.markBaselinereturned it; the newest mark when omitted. The marks taken after it go with the reset.
Returns number — How many frames stand between the call and the devices reading restored: 1.
input.resetToBaseline(mark)
input/setBackClaimed
input.setBackClaimed(claimed)
State whether a script holds Back. While it does, a Back press no overlay takes is recorded as a back event taken by claim, and the platform is told the app takes Back. Internal: backs Zin.back.claim, which holds the claims themselves.
Parameters
claimedboolean— Whether any claim on Back is held
input/setTouchClaims
input.setTouchClaims(owner, regions)
State the regions of the window an owner's on-screen controls hold, replacing the ones it stated before; an empty list lets go of them. A touch contact that begins inside any owner's region belongs to the control there: it reaches the game as a touch, and drives no pointer, so no UI widget beneath the control receives it and no mouse button reads held. A contact beginning anywhere else drives the pointer the way it always does. Regions are in the window pixels touch contacts arrive in. Backs the on-screen touch controls.
Parameters
ownerstring— Who holds the regions; each owner's list stands on its ownregions{ { x: number, y: number, radius: number?, w: number?, h: number? } }— Each a disc{ x, y, radius }around its centre, or a box{ x, y, w, h }from its top-left corner
input/simulateGamepadAxis
input.simulateGamepadAxis(slot, axis, value)
Queue a simulated pad-axis move. axis is a canonical name: left_stick_x, left_stick_y, right_stick_x, right_stick_y, left_trigger, right_trigger, with case and word separators folded away and a name outside the vocabulary raising. Stick axes clamp to -1..1 with y screen-down positive; trigger axes clamp to 0..1 and latch their digital button at 0.5. Internal — backs the inputSim toolbox's padStick / padTrigger.
Parameters
slotnumber— Pad slotaxisstring— Canonical axis namevaluenumber— Axis value
input/simulateGamepadButton
input.simulateGamepadButton(slot, button, held)
Queue a simulated pad-button state change. button is a canonical name: south, east, west, north, left_shoulder, right_shoulder, left_trigger, right_trigger, left_stick, right_stick, select, start, guide, dpad_up, dpad_down, dpad_left, dpad_right. Case and word separators fold away, so "South" and "LeftShoulder" reach the same buttons the canonical spellings name; a name outside the vocabulary raises, naming every canonical button. Internal — backs the inputSim toolbox's padDown / padUp.
Parameters
slotnumber— Pad slotbuttonstring— Canonical button nameheldboolean— True for down, false for up
input/simulateGamepadConnect
input.simulateGamepadConnect(name?) -> ()
Queue a simulated pad connection. The pad takes the lowest free slot and reports name (default "Simulated Gamepad") as its device name. Internal — backs the inputSim toolbox's connect. Read the slot it took from the next frame's snapshot gamepads array.
Parameters
namestring?— Device name the pad reports
input/simulateGamepadDisconnect
input.simulateGamepadDisconnect(slot)
Queue a simulated pad disconnection. Anything the pad still held publishes its button-up first. Internal — backs the inputSim toolbox's disconnect.
Parameters
slotnumber— Pad slot to disconnect
input/simulateKeyDown
input.simulateKeyDown(key, target?)
Queue a simulated key-down event. key is resolved against the KeyboardEvent.code vocabulary: a code reaches itself, a differently-cased spelling reaches the canonical one, and a single letter or digit reaches its Key<L> / Digit<N> code, so the snapshot holds what a real keyboard reports. A name outside the vocabulary raises, naming the nearest code. Drained before the next frame's controller scripts run. Internal — backs Zin.test.pressKey(); production code should not call this directly.
Parameters
keystring— Key code in KeyboardEvent.code form ("KeyW", "Space", "ShiftLeft"), or a single letter or digittargetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateKeyUp
input.simulateKeyUp(key, target?)
Queue a simulated key-up event. key is resolved against the KeyboardEvent.code vocabulary exactly as simulateKeyDown resolves it, and a name outside it raises. Internal — backs Zin.test.releaseKey().
Parameters
keystring— Key code in KeyboardEvent.code form ("KeyW", "Space", "ShiftLeft"), or a single letter or digittargetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateMouseDown
input.simulateMouseDown(button?, target?)
Queue a simulated mouse-button-down event. 0=left (default), 1=right, 2=middle. Internal — backs Zin.test.pressMouse().
Parameters
buttonnumber— Button index (default: 0)targetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateMouseMove
input.simulateMouseMove(x, y, target?)
Place the pointer on the WINDOW, in physical pixels. input.snapshot().mouse_position reads it back in the scene viewport's space, which worldToScreen answers in too: the window point less the origin camera.viewData().viewport carries. A point taken from either of those reaches the place it names by adding that origin, and the two spaces are one wherever the scene is drawn across the whole window. A logical layout coordinate (getLayoutInfo / ui.screenSize) converts to window pixels with ui.pixelRatio(). Internal — backs Zin.test.moveMouse().
Parameters
xnumber— Window X (physical pixels)ynumber— Window Y (physical pixels)targetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateMouseMoveBy
input.simulateMouseMoveBy(dx, dy, target?)
Move the pointer by a relative motion, the way a mouse device reports it: the contribution accumulates into this frame's mouse_delta and advances the position by the same amount. Repeating the same (dx, dy) keeps delivering it. Internal — backs Zin.test.moveMouseBy().
Parameters
dxnumber— Horizontal motion in screen pixelsdynumber— Vertical motion in screen pixelstargetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateMouseUp
input.simulateMouseUp(button?, target?)
Queue a simulated mouse-button-up event. Internal — backs Zin.test.releaseMouse().
Parameters
buttonnumber— Button index (default: 0)targetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateSceneContext
input.simulateSceneContext(active?: boolean)
Hand the active input context to the scene (true, the default)
or to the UI (false). While a viewport widget is on screen the
scene owns continuous pointer input — buttons, motion, scroll —
only while it is the active context, which a pointer gesture
decides by where it begins; this decides it without one. The next
gesture decides it again. Internal — backs Zin.test.focusScene().
Parameters
activeboolean— true hands the context to the scene, false to the UI (default: true)
input/simulateScroll
input.simulateScroll(dy, target?)
Queue a simulated mouse-wheel event. Internal — backs Zin.test.scroll().
Parameters
dynumber— Scroll delta (positive = up)targetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateTouchCancel
input.simulateTouchCancel(id, target?)
Queue a simulated platform touch-cancel for an active finger id.
Parameters
idnumber— Stable finger idtargetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateTouchDown
input.simulateTouchDown(id, x, y, pressure?, target?)
Queue a simulated touch-contact-begin event. id is any stable number identifying the finger until its matching simulateTouchUp/Cancel. Drained before the next frame's controller scripts run. The primary touch (slot 0) also drives the mouse path. Internal — backs Zin test touch helpers.
Parameters
idnumber— Stable finger idxnumber— Screen Xynumber— Screen Ypressurenumber— Contact pressure 0..1 (default: 1.0)targetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateTouchMove
input.simulateTouchMove(id, x, y, pressure?, target?)
Queue a simulated touch-move event for an active finger id.
Parameters
idnumber— Stable finger idxnumber— Screen Xynumber— Screen Ypressurenumber— Contact pressure 0..1 (default: 1.0)targetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateTouchUp
input.simulateTouchUp(id, target?)
Queue a simulated touch-lift event for an active finger id.
Parameters
idnumber— Stable finger idtargetstring(optional) —"game"(the default): the game's input alone — the scene reads it whatever surface a person at the window holds, and no UI widget receives it."ui": the UI, the way a person's device reaches it — delivered to the focused or hovered widget, a press deciding the active input context by where it lands.
input/simulateUiFocus
input.simulateUiFocus(pointer: boolean, keyboard: boolean)
Hold the UI layer's two focus opinions at pointer and keyboard until input.releaseUiFocus() gives them back to the UI pass. The pair decides, per event surface, whether the UI took an event: a pointer event is judged on pointer focus and a key on keyboard focus, so a run with no UI on screen can still put a handler on either side of consumed_by_ui. Queued like every other simulated input, so the events queued behind it are stamped against it. Internal — backs Zin.test.uiFocus().
Parameters
pointerboolean— Whether the UI holds pointer focuskeyboardboolean— Whether the UI holds keyboard focus
input/snapshot
input.snapshot() -> table
Get the current frame's input state as a table. Internal — Zin wraps this as Zin.state.get(). Fields: keys, keys_pressed, keys_released — ARRAYS of pressed key code strings (e.g. {"KeyD", "Space"}). NOT a {KeyD=true} dict; t.keys["KeyD"] is always nil. They are the scene's keys: the ones pressed while the scene was the active input context (see scene_context). editor_keys, editor_keys_pressed, editor_keys_released — the same arrays for the editor, which answers to every key no focused widget took, including keys pressed after a click on a panel. keys_emulated — array of key codes held by the input-emulation floor, a subset of keys (merged there for polling); Zin.state.keyDownReal reads keys minus keys_emulated. mouse_position, mouse_delta — [x, y]; mouse_buttons, mouse_pressed, mouse_released — [L, R, M] bool arrays (InputResource convention); scroll_delta — number; pointer_locked, ui_focused: booleans; ui_took_press: boolean, true while a UI widget sensing a click or a drag holds the press in progress, nil until a UI pass has decided a press that arrived; touches: array of { id, slot, x, y, dx, dy, pressure, phase, pointer } per active finger contact (slot 0 = primary; phase: began|moved|stationary|ended|cancelled; pointer: whether it drives the UI's pointer); touch_capable — boolean, true once the session has (or declares) a touch input source; gamepads — array of { slot, name, buttons, buttons_pressed, buttons_released, axes, simulated } per connected pad, ordered by slot (button fields are ARRAYS of canonical names, axes is a map of canonical axis name to number); gamepad_capable — boolean, true once the session has seen a pad.
Returns table — Input state snapshot for this frame