simvx.core.testing.input_sim¶
InputSimulator – simulate keyboard/mouse/touch input for headless testing.
Each public method does three things in one call:
State injection – writes into the
Inputsingleton’s typed state sets, matching the bytes the platform adapter would write (soInput.is_mouse_button_pressed()and friends see the press).Scene-tree event propagation – posts a
TreeInputEventto the activeSceneTreeso@on_inputdecorators fire.UI-tree event propagation – posts a
UIInputEventviatree.ui_input(...)soControl._on_gui_inputhandlers fire.
If no SceneTree is active (pure logic tests with no tree), steps 2 and 3
are silently skipped.
Module Contents¶
Classes¶
Simulate input events for headless testing. |
Data¶
API¶
- simvx.core.testing.input_sim.__all__¶
[‘InputSimulator’]
- class simvx.core.testing.input_sim.InputSimulator(tree: simvx.core.scene_tree.SceneTree | None = None)[source]¶
Simulate input events for headless testing.
Drives the engine the same way real platform adapters do: state writes, scene-tree event propagation, and UI-tree event propagation, so a single
sim.click(pos)call fires polling state,@on_inputdecorators, andControl._on_gui_inputin lockstep.The target SceneTree is either bound at construction time (when a test explicitly knows which tree to drive, as
UITestHarnessdoes) or resolved lazily viaSceneTree.current()on each call (so simple one-tree scenarios work without plumbing).Usage: from simvx.core.input import Key sim = InputSimulator() sim.press_key(Key.SPACE) runner.advance_frames(1) sim.release_key(Key.SPACE)
Initialization
- press_key(key: simvx.core.input.Key | int) None[source]¶
Simulate a key press. Accepts Key enum or int.
- tap_key(key: simvx.core.input.Key | int) None[source]¶
Press now, schedule release for the next frame boundary.
Pressing AND releasing in the same Python tick lights up both
is_action_just_pressedANDis_action_just_releasedon the same frame, which breaks edge-triggered game logic (PyDew Valley and the Tier-1 Balatro port both hit this). Instead, press immediately so the current frame’stree.tick()seesis_action_just_pressed, then queue the release for the next frame boundary.SceneRunner.advance_framesdrains the queue at the end of every iteration (afterInput._new_frame), so the typical flowsim.tap_key(); runner.advance_frames(2)observesis_action_just_pressedon the first iteration andis_action_just_releasedon the second. Callers driving frames outside SceneRunner can flush manually via- Meth:
flush_pending_releases.
- classmethod flush_pending_releases() None[source]¶
Release every key queued by :meth:
tap_keysince the last flush.Writes the release into the typed
Inputstate AND propagates a- Class:
TreeInputEventto the activeSceneTreeso polling (is_action_just_released) and@on_inputdecorators both observe the release edge.
Snapshots the queue before iterating so a release handler that re-queues a release does not extend the current drain.
- press_mouse(button: simvx.core.input.MouseButton | int = MouseButton.LEFT, position: tuple[float, float] | None = None) None[source]¶
Simulate mouse button press, optionally at a position.
- release_mouse(button: simvx.core.input.MouseButton | int = MouseButton.LEFT) None[source]¶
Simulate mouse button release.
- click(position: tuple[float, float], button: simvx.core.input.MouseButton | int = MouseButton.LEFT) None[source]¶
Click at a screen position (press + release).
- scroll(dx: float = 0.0, dy: float = -1.0) None[source]¶
Simulate scroll wheel. dy < 0 = scroll down, dy > 0 = scroll up.
- touch_down(finger_id: int = 0, position: tuple[float, float] = (0, 0), pressure: float = 1.0) None[source]¶
Simulate a touch press (finger down).
- touch_move(finger_id: int = 0, position: tuple[float, float] = (0, 0), pressure: float = 1.0) None[source]¶
Simulate a touch move (finger drag).