Log inGet started

input

Updated 6 September 2026

The input namespace — 34 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/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. 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). No frame event, no UI forwarding. Internal — backs the map-driven emulation floor.

Parameters

  • code string — Key code

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/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/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/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/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. 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. 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)

Queue a simulated key-down event. 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 name

input/simulateKeyUp

input.simulateKeyUp(key)

Queue a simulated key-up event. Internal — backs Zin.test.releaseKey().

Parameters

  • key string — Key name

input/simulateMouseDown

input.simulateMouseDown(button?)

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)

input/simulateMouseMove

input.simulateMouseMove(x, y)

Set mouse position, in PHYSICAL pixels — the space input.mousePosition, the camera viewport rect and worldToScreen speak. A logical layout coordinate (getLayoutInfo / ui.screenSize) converts with ui.pixelRatio(). Internal — backs Zin.test.moveMouse().

Parameters

  • x number — Screen X (physical pixels)
  • y number — Screen Y (physical pixels)

input/simulateMouseMoveBy

input.simulateMouseMoveBy(dx, dy)

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

input/simulateMouseUp

input.simulateMouseUp(button?)

Queue a simulated mouse-button-up event. Internal — backs Zin.test.releaseMouse().

Parameters

  • button number — Button index (default: 0)

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)

Queue a simulated mouse-wheel event. Internal — backs Zin.test.scroll().

Parameters

  • dy number — Scroll delta (positive = up)

input/simulateTouchCancel

input.simulateTouchCancel(id)

Queue a simulated platform touch-cancel for an active finger id.

Parameters

  • id number — Stable finger id

input/simulateTouchDown

input.simulateTouchDown(id, x, y, pressure?)

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)

input/simulateTouchMove

input.simulateTouchMove(id, x, y, pressure?)

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)

input/simulateTouchUp

input.simulateTouchUp(id)

Queue a simulated touch-lift event for an active finger id.

Parameters

  • id number — Stable finger id

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. 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; touches — array of { id, slot, x, y, dx, dy, pressure, phase } per active finger contact (slot 0 = primary; phase: began|moved|stationary|ended|cancelled); 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