Log inGet started

input

Updated October 16, 2026

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

  • on boolean? — 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

  • code string — 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

  • code string — 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

  • button number — Button index (0=left, 1=right, 2=middle)
  • held boolean — 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

  • dx number — Delta X
  • dy number — 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

  • name string — 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

  • report table — 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

  • generation number — The mark to drop, as input.markBaseline returned 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

  • generation number (optional) — The mark to restore to, as input.markBaseline returned 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

  • claimed boolean — 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

  • owner string — Who holds the regions; each owner's list stands on its own
  • regions { { 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

  • slot number — Pad slot
  • axis string — Canonical axis name
  • value number — 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

  • slot number — Pad slot
  • button string — Canonical button name
  • held boolean — 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

  • name string? — 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

  • slot number — 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

  • key string — Key code in KeyboardEvent.code form ("KeyW", "Space", "ShiftLeft"), or a single letter or digit
  • target string (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

  • key string — Key code in KeyboardEvent.code form ("KeyW", "Space", "ShiftLeft"), or a single letter or digit
  • target string (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

  • button number — Button index (default: 0)
  • target string (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

  • x number — Window X (physical pixels)
  • y number — Window Y (physical pixels)
  • target string (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

  • dx number — Horizontal motion in screen pixels
  • dy number — Vertical motion in screen pixels
  • target string (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

  • button number — Button index (default: 0)
  • target string (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

  • active boolean — 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

  • dy number — Scroll delta (positive = up)
  • target string (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

  • id number — Stable finger id
  • target string (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

  • id number — Stable finger id
  • x number — Screen X
  • y number — Screen Y
  • pressure number — Contact pressure 0..1 (default: 1.0)
  • target string (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

  • id number — Stable finger id
  • x number — Screen X
  • y number — Screen Y
  • pressure number — Contact pressure 0..1 (default: 1.0)
  • target string (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

  • id number — Stable finger id
  • target string (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

  • pointer boolean — Whether the UI holds pointer focus
  • keyboard boolean — 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

  • api
  • reference