Input Event
Shippinginput_eventHuman/Hardware-in-the-loop input: keyboard/mouse drives a live scalar into a running simulation
Signature
Outputs
valueScalar— The current input level (a Scalar with optional unit; exact — control input carries no uncertainty).
Parameters
| Key | Type | Default | Notes |
|---|---|---|---|
source | enum | key | one of: key, mouse_button, mouse_x, mouse_y, mouse_wheel |
binding | text | Space | The bound key (e.g. Space, W, ArrowUp) or mouse button (Left / Right / Middle). Shown only for key / mouse_button sources. Capture it in the Sim Input panel while live. |
mode | enum | hold | one of: hold, toggle, impulse, axis |
value_on | float | 1.0(unit) | Output while pressed / toggled-on, or the value the axis maps to at its maximum. |
value_off | float | 0.0(unit) | Resting output (released / toggled-off), or the value the axis maps to at its minimum. The batch/head-less run emits this. |
impulse_ms | float | 50.0ms | How long (in wall-clock ms) an Impulse pulse holds the On value before returning to Off. Active only in Impulse mode. |
value | float | 0.0(unit) | The current output level. Driven by the bound input while live (see the Sim Input panel); editable directly as the rest value. |
unit | text | Physical unit of the emitted value (e.g. N, V, rad). Dimensionless when empty. |
Description
Input Event is a runtime Human/Hardware-in-the-loop (HIL / HumanIL) input source. Drop it inside a execution_mode = Simulation compound, wire its value output into the dynamics, and while the sim runs live (wall-clock-paced "Run Live") the user's keyboard / mouse drives its output in real time — pressing a key fires a thruster, holding a button opens a valve, a mouse axis steers a setpoint. It lets a person (or, later, a piece of hardware) sit inside the control loop and react to the evolving state.
The Rust builtin itself does zero math: it is a runtime-tunable constant scalar source — exactly like constant, it emits the value parameter on its single output. All the input interpretation — which key, hold vs. toggle vs. impulse vs. axis, the high/low levels — lives on the Dart side (SimInputController). When an input event occurs the UI resolves a numeric and writes it straight into the running solver via exec_set_live_param(node, "value", v) — the same zero-recompile slot write a slider drag uses. So the node stays trivial and deterministic: it only ever emits whatever scalar currently sits in value (its rest level in batch / before the first event), exact and unitful.
Because the live retune overwrites value each event, this node is whitelisted alongside constant in the AOT tunable-slot gate, so even a compiled scalar program can be driven live; on the generic evaluator path (a model with events / forcing inputs) the value write is re-read every step for free.
Outside a live simulation — on a batch Run or the acyclic dataflow path — it is a plain constant source emitting value (which defaults to the configured value_off rest level), so a model authored with input events still runs head-less and reproducibly.
Modes: Hold is momentary (on while pressed), Toggle flips on each press, Impulse emits one short impulse_ms pulse per press, and Axis maps a continuous device value between value_off and value_on. The binding and mode params apply only to the button-style sources (key / mouse_button); the axis sources are inherently continuous and hide them.
Mathematics
Examples
Thruster on the space bar
Set source = key, binding = Space, mode = hold, value_on = 1, value_off = 0, unit = N. Wire value into a force input. While the sim runs live, holding Space applies ; releasing returns to . A batch run emits the rest value the whole time.
Steering a setpoint with the mouse
Set source = mouse_x, mode = axis. The continuous mouse-X position maps between value_off (at minimum) and value_on (at maximum), driving a live setpoint into the controller as you move the cursor.
Impulse valve kick
Set mode = impulse, impulse_ms = 50. Each key press holds value_on for of wall-clock time, then falls back to value_off — a one-shot kick regardless of how long the key is held.
Applications
- Human-in-the-loop control: piloting a simulated vehicle, spacecraft, or robot from the keyboard/mouse while the physics runs live.
- Interactive what-if probing — nudging a setpoint or disturbance mid-run to feel how a controller responds.
- Teaching / demo scenarios where a person injects thruster fires, valve openings, or steering inputs into a running model.
- A tunable live constant that a batch run reproducibly pins to its rest level for head-less, deterministic replay.
Neat
The Rust core is deliberately math-free: it is the exact same constant-from-param source as `constant`, with all device interpretation pushed to Dart — so the solver stays deterministic and the node is trivially reproducible head-less.
The live driver reuses the *slider-drag* mechanism: an input event is just `exec_set_live_param(node, "value", v)`, a zero-recompile slot write, so keyboard/mouse control needs no graph recompile per event.
It is whitelisted next to `constant` in the AOT tunable-slot gate, so even an ahead-of-time-compiled scalar program can be driven live without falling back to the generic evaluator.
The same node degrades to a plain constant on a batch run, so a model authored for interactive HIL still executes reproducibly and head-less.
Known issues
Live driving only happens under wall-clock-paced "Run Live" inside a Simulation compound; on a batch run or the dataflow path it is a static constant at its rest level.
A bypassed ("muted") or unwired Input Event drives nothing in the running solver — the HUD dims the input lamp rather than raising an error, so a mis-authored node can silently do nothing.
Modes, bindings, and axis mapping live entirely on the Dart side; the Rust builtin surfaces only the resolved `value`, so the input semantics are not visible from the core alone.