simvx.graphics.input_adapter

Desktop windowing shim: GLFW/SDL3 events to :class:InputRouter.

Backend-agnostic: GLFW and SDL3 deliver the same integer key codes, the same action constants, and the same modifier bit positions, so one shim serves both.

Everything this module does is translation – action ints to pressed/echo booleans, a mods bitfield to four flags. A button goes through as the index the platform reports, and the device’s layout names it: GLFW’s mouse numbering is the engine’s default mouse layout, and a pen’s barrels are numbered from 1 as SDL3 and Qt both report them. What an event means to the engine lives in

mod:

simvx.core.input.router, shared with the browser runtime.

The facts a platform may or may not have – the event’s own time, the character its key prints, which device it came from – arrive as keyword arguments and pass straight through. A backend converted its time onto the monotonic clock before calling (see :mod:.platform._event_facts), and one with nothing to say says nothing, which leaves the router to fill the fact in and Input.capabilities to report that it did.

Module Contents

Functions

set_router

Install the router these callbacks feed (called by FrameLoop.on_setup).

key_callback

Process a key event.

mouse_button_callback

Process a mouse button.

cursor_pos_callback

Process a cursor position event.

scroll_callback

Process a scroll event.

char_callback

Process a character input event (typed characters).

touch_callback

Process one finger: a press, a move, a lift or a cancel.

pen_callback

Process one pen sample, straight through to :meth:InputRouter.pen.

focus_callback

Process a window focus change.

install_controller_rumble

Wire the backend’s rumble to Controller.rumble, or tear the seam down.

poll_controllers

Poll controllers via the window backend and publish one frame of state.

Data

API

simvx.graphics.input_adapter.log

‘getLogger(…)’

simvx.graphics.input_adapter.set_router(router: simvx.core.input.InputRouter | None) → None

Install the router these callbacks feed (called by FrameLoop.on_setup).

simvx.graphics.input_adapter.key_callback(key: int, action: int, mods: int, *, time: float | None = None, label: str | None = None, device_id: int = 0) → None

Process a key event.

Args: key: Platform key code (integer, shared by GLFW/SDL3). action: _PRESS (1), _RELEASE (0), or _REPEAT (2). mods: Modifier bits (shift, ctrl, alt, super). time: The event’s own time on the monotonic clock, where the platform has one. Left unset, the router stamps the event at receipt. label: What this key prints under the player’s layout. Left unset, the engine’s US table answers instead. device_id: Which physical keyboard; 0 is the aggregate device.

simvx.graphics.input_adapter.mouse_button_callback(button: int, action: int, mods: int, *, time: float | None = None, device_id: int = 0) → None

Process a mouse button.

Args: button: The platform’s button index, in GLFW’s numbering (0 left, 1 right, 2 middle, 3 back, 4 forward, then whatever the mouse has). action: _PRESS (1) or _RELEASE (0). mods: Modifier bits. time: The event’s own time on the monotonic clock, where the platform has one. device_id: Which physical mouse; 0 is the aggregate device.

simvx.graphics.input_adapter.cursor_pos_callback(x: float, y: float, *, time: float | None = None) → None

Process a cursor position event.

Coordinates arrive in logical (screen) pixels, not physical framebuffer pixels. On HiDPI displays the framebuffer may be larger, but cursor coordinates and tree.screen_size share logical units, so the input layer needs no DPI scaling.

simvx.graphics.input_adapter.scroll_callback(x_offset: float, y_offset: float, *, time: float | None = None) → None

Process a scroll event.

simvx.graphics.input_adapter.char_callback(codepoint: int, *, time: float | None = None) → None

Process a character input event (typed characters).

simvx.graphics.input_adapter.touch_callback(finger_id: int, phase: simvx.core.input.PointerPhase, x: float, y: float, pressure: float | None, *, contact_size: tuple[float, float] | None = None, time: float | None = None, device_id: int = 0) → None

Process one finger: a press, a move, a lift or a cancel.

Args: finger_id: Unique finger identifier while it is down. phase: DOWN, MOVE, UP or CANCEL. x, y: Position in window pixel coordinates. pressure: Touch pressure 0.0-1.0, or None where the screen cannot measure it. contact_size: The contact’s width and height, where the platform reports it. time: The event’s own time on the monotonic clock, where the platform has one. device_id: Which touchscreen; 0 is the aggregate device.

simvx.graphics.input_adapter.pen_callback(pen_id: int, phase: simvx.core.input.PointerPhase, x: float, y: float, *, button: int = 0, pressure: float | None = None, tilt: tuple[float, float] | None = None, twist: float | None = None, distance: float | None = None, tangential_pressure: float | None = None, tool: simvx.core.input.PointerTool = PointerTool.TIP, tool_id: int = 0, time: float | None = None, device_id: int = 0) → None

Process one pen sample, straight through to :meth:InputRouter.pen.

The backend has already said everything in the engine’s own terms, tilt and twist in radians and the eraser as a tool, so this only forwards it. button is the pen’s own index: 0 the tip, barrels from 1.

simvx.graphics.input_adapter.focus_callback(focused: bool) → None

Process a window focus change.

The loss releases what the window was holding: the release of a key or button held as focus moves away is delivered to whatever took the focus, so the engine has to let go of it here. Both are recorded on the router, because only a focused window moves focus by hover.

simvx.graphics.input_adapter.install_controller_rumble(window_backend: Any) → None

Wire the backend’s rumble to Controller.rumble, or tear the seam down.

A backend that cannot drive the motors, and None at teardown, both install nothing, which also clears a callback left by a previous run: the window it belonged to is gone and calling into it would reach a destroyed handle. Input.capabilities.rumble does not come back down with it, because a capability is what the machine can do rather than what is wired up this instant.

The motors belong to the machine, so the seam lands on the process-wide device store whichever tree’s state it is reached through.

simvx.graphics.input_adapter.poll_controllers(window_backend: Any) → None

Poll controllers via the window backend and publish one frame of state.

The poll is a transaction, not an add-only write: a pad the backend stops reporting is dropped, so unplugging a controller releases its held buttons instead of leaving them pressed for the rest of the run. A backend that declares no controller support opens no transaction at all, because “I cannot see pads” must not be published as “every pad has gone”.

Each pad carries what the backend knows about the device beside what it is doing: its name, its stable id and whether the engine’s standard button names apply. A backend states only what its library told it, so a fact it leaves out is one it could not answer rather than an empty answer.

The pads are process-wide, so one poll serves every tree: a game running under the editor reads the controller the editor’s poll found. What the router decides is only where the pad events the poll produced are published, which is the tree whose handlers should hear them.

simvx.graphics.input_adapter.__all__

[‘install_controller_rumble’, ‘set_router’, ‘key_callback’, ‘mouse_button_callback’, ‘cursor_pos_cal…