input
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
onboolean?— 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
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). No frame event, no UI forwarding. Internal — backs the map-driven emulation floor.
Parameters
codestring— 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
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/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
reporttable— 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
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. 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)
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
keystring— Key name
input/simulateKeyUp
input.simulateKeyUp(key)
Queue a simulated key-up event. Internal — backs Zin.test.releaseKey().
Parameters
keystring— 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
buttonnumber— 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
xnumber— Screen X (physical pixels)ynumber— 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
dxnumber— Horizontal motion in screen pixelsdynumber— Vertical motion in screen pixels
input/simulateMouseUp
input.simulateMouseUp(button?)
Queue a simulated mouse-button-up event. Internal — backs Zin.test.releaseMouse().
Parameters
buttonnumber— 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
activeboolean— 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
dynumber— Scroll delta (positive = up)
input/simulateTouchCancel
input.simulateTouchCancel(id)
Queue a simulated platform touch-cancel for an active finger id.
Parameters
idnumber— 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
idnumber— Stable finger idxnumber— Screen Xynumber— Screen Ypressurenumber— 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
idnumber— Stable finger idxnumber— Screen Xynumber— Screen Ypressurenumber— Contact pressure 0..1 (default: 1.0)
input/simulateTouchUp
input.simulateTouchUp(id)
Queue a simulated touch-lift event for an active finger id.
Parameters
idnumber— 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
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. 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