simvx.core.input.router

Platform-neutral input routing.

Every backend – desktop windowing (GLFW/SDL3) and the browser runtime – feeds its events through :class:InputRouter. The router is the single place that knows what an input event means to the engine:

  1. update the :class:Input singleton (typed and string-keyed state),

  2. route the event to the UI system (tree.ui_input / tree.touch_input),

  3. propagate a :class:TreeInputEvent for @on_input handler dispatch.

Backends translate their own wire format into the normalised arguments here – engine :class:Key codes, :class:MouseButton values, pressed booleans – and do nothing else. Keeping steps 1-3 in one place is what stops the backends drifting apart: a handler kind that works on the desktop works in the browser because both reach it through this module.

Module Contents

Classes

InputRouter

Routes normalised input events into engine state, UI, and @on_input.

Data

API

simvx.core.input.router.log

‘getLogger(…)’

simvx.core.input.router.TOUCH_DOWN

0

simvx.core.input.router.TOUCH_UP

1

simvx.core.input.router.TOUCH_MOVE

2

class simvx.core.input.router.InputRouter(tree: simvx.core.scene_tree.SceneTree | None = None, *, input_state: simvx.core.input.state._Input | None = None)[source]

Routes normalised input events into engine state, UI, and @on_input.

Args: tree: The :class:SceneTree receiving UI and @on_input dispatch. None routes to input state only, which is what a headless backend or a state-only test wants. input_state: Input state override, for a caller that owns an instance no tree holds.

A router that was given a tree writes that tree’s own :class:_Input, not the ambient proxy. The two are the same object for an ordinary tree, and a different one for a tree built with isolated_input=True: the state write happens before the tree opens its input span, so resolving the ambient proxy here would land every key in the process-wide default and the isolated tree would read False for a key that is genuinely held.

Initialization

__slots__

(‘tree’, ‘_input’, ‘_primary_finger’, ‘_last_motion_pos’)

reset() None[source]

Drop per-session pointer state (call on scene change or app teardown).

is_key_down(code: int) bool[source]

Whether code is currently held, for backends that must infer key repeat.

key(code: int, pressed: bool, *, echo: bool = False, ctrl: bool | None = None, shift: bool | None = None, alt: bool | None = None, meta: bool | None = None) None[source]

Route a key event.

Args: code: Engine :class:Key code. pressed: True on press, False on release. echo: True for an auto-repeat press. Repeats reach the UI, so held keys still repeat in text fields, but they are not propagated as @on_input events: a game action fires once per physical press, so a tree event is never a repeat. ctrl, shift, alt, meta: Modifier state at event time. A backend that does not report them leaves them unset and the held-key state answers instead.

char(text: str) None[source]

Route a typed character (text entry only; never a game action).

mouse_button(button: simvx.core.input.enums.MouseButton, pressed: bool, *, ctrl: bool | None = None, shift: bool | None = None, alt: bool | None = None, meta: bool | None = None) None[source]

Route a mouse button event.

Args: button: Engine :class:MouseButton. Backends whose native ordering differs (the DOM numbers the middle and right buttons the other way round) remap before calling. pressed: True on press, False on release. ctrl, shift, alt, meta: Modifier state at event time, carried to the UI as well as to @on_input, so a widget can implement a Shift-click. A caller that does not report them – the emulated pointer behind a touch, for one – leaves them unset and the held-key state answers instead.

mouse_motion(x: float, y: float) None[source]

Route absolute pointer motion, in logical (screen) pixels.

HiDPI needs no scaling here: cursor coordinates and tree.screen_size are both logical units even when the framebuffer is larger.

mouse_motion_relative(dx: float, dy: float) None[source]

Route relative pointer motion under pointer lock.

A locked pointer has no meaningful screen position, so this contributes delta only: the UI is not notified and the stored position stands.

scroll(dx: float, dy: float) None[source]

Route a scroll event. Positive dy scrolls up.

touch(finger_id: int, action: int, x: float, y: float, pressure: float = 1.0) None[source]

Route a touch event.

Raw multi-touch always reaches Input._touches for game code and gesture recognition. The primary finger (the first one down) is also emulated as mouse input so every UI widget works under touch untouched; when Input.set_mouse_from_touch_emulation is on, it additionally fires

Attr:

MouseButton.LEFT, so actions bound to the left button work on touch devices without the game doing anything.

Args: finger_id: Unique finger identifier. action: :data:TOUCH_DOWN, :data:TOUCH_UP, or :data:TOUCH_MOVE. x, y: Position in logical (screen) pixels. pressure: Touch pressure, 0.0-1.0.

simvx.core.input.router.__all__

[‘InputRouter’, ‘TOUCH_DOWN’, ‘TOUCH_UP’, ‘TOUCH_MOVE’]