API Reference

Public package

TachyPy public API with lazy imports to avoid unnecessary backend loading.

Core modules

Display and timing utilities for TachyPy with pluggable backends.

class tachypy.screen.Screen(screen_number: int = 0, width: int | None = None, height: int | None = None, fullscreen: bool = True, vsync: bool = True, desired_refresh_rate: int = 60, grab_input: bool = True, backend: str = 'glfw', warmup_frames: int = 60, warmup_color: Sequence[float] = (128, 128, 128))

Create and manage a GLFW/OpenGL display.

close() None

Close the display backend.

fill(color: Sequence[float] = (128, 128, 128)) None

Clear the screen with the provided RGB color in [0, 255].

flip() int

Swap buffers and return the immediate post-swap timestamp in nanoseconds.

The returned value is captured immediately after the backend swap call returns, before event polling, viewport synchronization, input updates, or frame-rate housekeeping. It approximates the display swap completion time, not photon onset at a specific screen location.

get_flip_interval() float | None

Return the interval between the last two flips in seconds.

hide_mouse() None

Hide cursor in the active backend window.

poll_events() None

Pump pending GLFW window events without interpreting participant input.

set_mouse_visible(visible: bool) None

Set mouse visibility explicitly.

should_close() bool

Return whether the GLFW window has received a close request.

show_mouse() None

Show cursor in the active backend window.

test_flip_intervals(num_frames: int = 50) float

Measure and return the mean frame interval in seconds.

tick() None

Limit frame updates to the desired refresh rate.

wait(duration_secs: float) None

Wait for a duration in seconds using high precision timing.

class tachypy.responses.ResponseHandler(keys_to_listen=None, screen=None)

Poll a GLFW-backed Screen and track participant keyboard/mouse responses.

clear_events()

Clear tracked transition events while preserving held-state snapshots.

get_events()

Poll the screen event pump and update response state snapshots.

get_key_presses()

Return recorded key transition events.

get_mouse_clicks()

Return recorded mouse button transition events.

get_mouse_position()

Return the latest mouse position or None if unavailable.

is_key_down(key_name)

Return True when the given key is currently held.

is_mouse_button_pressed(button)

Return True when the given mouse button index is pressed.

reset_timer()

Reset the event timestamp origin.

set_position(x, y)

Set the cursor position in the GLFW window and local state.

should_quit()

Return whether a quit signal has been received.

wait_for_keypress(keys=None, timeout=None, time_reference_ns=None, callback=None, callback_delay=None)

Block until one of the listed keys is pressed, keeping the display alive.

Parameters:
  • keys (sequence of str, optional) – Keys to wait for (e.g. ["z", "c"]). If omitted, returns on any tracked keydown event instead of a specific key.

  • timeout (float, optional) – Maximum time to wait, in seconds.

  • time_reference_ns (int, optional) – Timestamp in the time.monotonic_ns() domain – e.g. the return value of Screen.flip() – to measure elapsed from, instead of the moment this call starts.

  • callback (callable, optional) – Zero-argument callable executed once, callback_delay seconds after this call started (or after time_reference_ns, if given) – unless a key is pressed before then, in which case it never fires. Does not end the wait: after firing, polling continues normally until a key is pressed, timeout elapses, or a quit is requested.

  • callback_delay (float, optional) – Delay in seconds after which callback fires.

Returns:

(key, elapsed) – the normalized name of the key that was pressed, or None on timeout or quit; and seconds elapsed since the timing origin (time_reference_ns, or when this call started if not given).

Return type:

tuple[str | None, float]

Raises:
  • ValueError – If callback is given without a positive callback_delay.

  • RuntimeError – If callback raises an exception.

Examples

Show a stimulus, then clear the screen to gray after a fixed 500 ms viewing duration if no response has arrived yet. If the participant responds within the first 500 ms, hide_stimulus never runs and the stimulus simply stays on screen until the key is detected:

>>> ... # draw the stimulus
>>> screen.flip()
>>> def hide_stimulus():
...     screen.fill([128, 128, 128])  # back to a plain gray screen
...     screen.flip()
>>> key, rt = response_handler.wait_for_keypress(
...     keys=["z", "c"], callback=hide_stimulus, callback_delay=0.5,
... )
was_key_pressed(key_name)

Return True when the given key transitioned to down this frame.

was_mouse_button_pressed(button)

Return True when the mouse button transitioned to down this frame.

was_mouse_button_released(button)

Return True when the mouse button transitioned to up this frame.

TachyPy audio convenience wrapper backed by tachyaudio.

class tachypy.audio.Audio(sample_rate=44100, channels=1, backend=None, *, block_size=None, device_id=None, latency=None, timeout=None)

Schedule playback through tachyaudio while preserving TachyPy’s API.

close()

Close audio resources by stopping playback.

play(data, when=0)

Play a NumPy buffer, optionally scheduled at an absolute monotonic time.

when is expressed in seconds from time.monotonic_ns() / 1e9. The call starts a daemon thread and returns immediately.

stop()

Stop current playback immediately.

Texture-backed text helpers implemented with Pillow and OpenGL.

class tachypy.text.LegacyText(text, font_name='Helvetica', font_size=24, color=(255, 255, 255), dest_rect=None, line_spacing=4, backend='auto')

OpenGL text object that renders text to a Pillow-backed texture.

delete()

Delete the OpenGL texture associated with this text object.

draw()

Draw the text texture centered in dest_rect.

set_dest_rect(dest_rect)

Update destination rectangle and regenerate wrapped lines.

set_text(new_text)

Update text content and regenerate the texture.

Backend-independent OpenGL bitmap text rendering.

class tachypy.gltext.GLText(text: str, dest_rect=None, color: Sequence[float] = (255, 255, 255), pixel_size: float = 3.0, line_spacing: float = 2.0, glyph_spacing: float = 1.0, align: str = 'center', vertical_align: str = 'center')

Draw simple bitmap text directly with OpenGL quads.

draw()

Draw the bitmap text block using immediate-mode OpenGL quads.

set_dest_rect(dest_rect)

Update destination rectangle and recompute line wrapping.

set_text(new_text: str)

Update displayed text and recompute line wrapping.

Signed-distance-field text rendering with OpenGL shaders.

class tachypy.gltext_sdf.GLTextSDF(text: str, dest_rect=None, color: Sequence[float] = (255, 255, 255), pixel_size: float = 4.0, line_spacing: float = 2.0, glyph_spacing: float = 1.0, align: str = 'center', vertical_align: str = 'center', sdf_scale: int = 8, sdf_padding: int = 6, sdf_spread: float = 10.0, smoothing: float = 0.1)

Draw higher-quality scalable text using an SDF texture atlas.

delete()

Release OpenGL resources owned by this SDF text object.

draw()

Draw text using the SDF atlas and shader smoothing.

System-font OpenGL text rendering (FreeType + HarfBuzz) with graceful fallback.

class tachypy.glsystemtext.GLSystemText(text: str, dest_rect=None, font_name: str = 'Helvetica', font_size: float = 32.0, color: Sequence[float] = (255, 255, 255), line_spacing: float = 1.15, align: str = 'center', vertical_align: str = 'center', fallback_renderer: str = 'bitmap', content_scale: float = 1.0)

Render text with system TrueType/OpenType fonts and OpenGL quads.

Falls back to GLText when shaping/rasterization dependencies are missing.

delete()

Release allocated glyph textures and fallback resources.

draw()

Draw text, delegating to fallback renderer when system path is disabled.

classmethod resolve_font_path(font_name: str) Path | None

Resolve a system font from a family/path query.

Supports: - absolute/relative font file paths - comma-separated fallback font families (e.g. “Avenir, Helvetica, Arial”) - partial family/style matching against system font file names

Style words (e.g. “Bold”, “Italic”) in the query are matched against the font file, but unrequested style words present in a candidate’s file name are penalized so a plain query like “Arial” prefers the regular weight over “Arial Narrow Italic”. An exact family match (e.g. “Arial” -> “Arial.ttf”) is also preferred over a candidate with extra qualifiers (e.g. “Arial Unicode”).

set_dest_rect(dest_rect)

Update destination layout rectangle.

set_text(new_text: str)

Update content text.

Scrollbar widget for continuous response (0..100 range by default).

class tachypy.scrollbar.Scrollbar(screen_width: float, screen_height: float, position_y: float = 200, half_bar_length: float = 400, bar_thickness: float = 4, bar_color: Sequence[float] = (0, 0, 0), half_mark_height: float = 5, mark_thickness: float = 3, mark_color: Sequence[float] = (0, 0, 0), num_marks: int = 10, half_end_height: float = 20, end_thickness: float = 4, end_color: Sequence[float] = (0, 0, 0), text_left: str = '0', text_right: str = '100', font_size: int = 24, font_name: str = 'Helvetica', text_color: Sequence[float] = (0, 0, 0), text_offset: float = 24, limit_mouse: bool = False, content_scale: float = 1.0)

Draw a scrollbar with a movable marker and configurable mouse behavior.

Parameters:
  • screen_width (float) – Size of the display area used to place the scrollbar.

  • screen_height (float) – Size of the display area used to place the scrollbar.

  • position_y (float) – Vertical position of the bar and marker in screen coordinates.

  • half_bar_length (float) – Half the horizontal length of the bar.

  • bar_thickness (float) – Thickness of the main bar, tick marks, and end markers.

  • mark_thickness (float) – Thickness of the main bar, tick marks, and end markers.

  • end_thickness (float) – Thickness of the main bar, tick marks, and end markers.

  • bar_color (sequence of float) – Colors used for the bar, marks, and ends.

  • mark_color (sequence of float) – Colors used for the bar, marks, and ends.

  • end_color (sequence of float) – Colors used for the bar, marks, and ends.

  • half_mark_height (float) – Half the height of each tick mark.

  • num_marks (int) – Number of tick marks drawn along the bar.

  • half_end_height (float) – Half the height of the left and right end markers.

  • text_left (str) – Labels displayed at each end of the scrollbar.

  • text_right (str) – Labels displayed at each end of the scrollbar.

  • font_size (int) – Font size used for the end labels.

  • font_name (str) – Font name used for the labels.

  • text_color (sequence of float) – Color of the labels.

  • text_offset (float) – Vertical offset for the labels above the bar.

  • limit_mouse (bool) – When True, the marker only updates when the mouse stays near the bar’s horizontal line. Set to False to allow interaction even when the cursor is farther away vertically.

  • content_scale (float) – Pass screen.content_scale to get sharp end labels on Retina/HiDPI screens.

Example

>>> scrollbar = Scrollbar(screen_width=screen.width, screen_height=screen.height, content_scale=screen.content_scale)
>>> value = None
>>> response_handler.clear_events()
>>> while value is None:
...     response_handler.get_events()
...     mouse_x, mouse_y = response_handler.get_mouse_position()
...     scrollbar.handle_mouse(mouse_x, mouse_y)
...     screen.fill((127, 127, 127))
...     scrollbar.draw()
...     screen.flip()
...     for click in response_handler.get_mouse_clicks():
...         if click["type"] == "mouseup":
...             value = scrollbar.get_value()
True
False
draw() None

Draw the scrollbar, ticks, labels, and marker.

get_normalized_value() float

Return current position in [0, 1].

get_range() Tuple[float, float]

Return value range represented by this widget.

get_value() float

Return current position in [0, 100].

handle_mouse(mouse_x: float, mouse_y: float) bool

Move the marker to the given mouse x-position and return True when it changes.

property max_x: float

Return maximum marker x-position.

property min_x: float

Return minimum marker x-position.

set_normalized_value(value: float) None

Set position from normalized value in [0, 1] (clamped).

set_value(value: float) None

Set position from value in [0, 100] (clamped).

tachypy.psychophysics.fabriquer_cercles_sin(nx, frequence, phase)

Deprecated alias for make_concentric_sine_circles().

tachypy.psychophysics.fabriquer_enveloppe_gaussienne(nx, ecart_type)

Deprecated alias for make_gaussian_envelope().

tachypy.psychophysics.fabriquer_gabor(nx, frequence, phase, angle, ecart_type)

Deprecated alias for make_gabor().

tachypy.psychophysics.fabriquer_grand_damier(une_case, M, N)

Deprecated alias for make_checkerboard().

tachypy.psychophysics.fabriquer_grille_sin(nx, frequence, phase, angle)

Deprecated alias for make_sine_grating().

tachypy.psychophysics.fabriquer_petit_damier(une_case)

Deprecated alias for make_checkerboard_tile().

tachypy.psychophysics.fabriquer_secteurs_sin(nx, frequence, phase)

Deprecated alias for make_sine_sectors().

tachypy.psychophysics.fabriquer_wiggles_sin(nx, frequence_min, frequence_max, frequence_radiale, phase_radiale, phase)

Deprecated alias for make_wiggles_sine().

tachypy.psychophysics.location_bubbles(nb_bubbles=50, std_bubble=25, an_image=None, x_size=None, y_size=None, random_state=None)

Generate a bubbles mask and optionally apply it to an image.

Parameters:
  • nb_bubbles (int) – Expected number of bubbles.

  • std_bubble (float) – Standard deviation of each bubble in pixels.

  • an_image (ndarray, optional) – Optional image with values in [0, 1].

  • x_size (int, optional) – Image dimensions when an_image is not provided.

  • y_size (int, optional) – Image dimensions when an_image is not provided.

  • random_state (tuple, optional) – Numpy random state as returned by np.random.get_state().

tachypy.psychophysics.make_checkerboard(num_pixels_per_cell, n_rows, n_cols)

Create a checkerboard image made of repeated 2x2 checkerboard tiles.

tachypy.psychophysics.make_checkerboard_tile(num_pixels_per_cell)

Create a 2x2 checkerboard tile.

tachypy.psychophysics.make_concentric_sine_circles(nx, frequency, phase)

Create concentric sine circles with values in [0, 1].

tachypy.psychophysics.make_gabor(nx, frequency, phase, angle, std_dev)

Create a Gabor patch image with values in [0, 1].

tachypy.psychophysics.make_gaussian_envelope(nx, std_dev)

Create a centered square Gaussian envelope image with values in [0, 1].

tachypy.psychophysics.make_sine_grating(nx, frequency, phase, angle)

Create a square sine grating image with values in [0, 1].

tachypy.psychophysics.make_sine_sectors(nx, frequency, phase)

Create angular sine sectors with values in [0, 1].

tachypy.psychophysics.make_wiggles_sine(nx, frequency_min, frequency_max, radial_frequency, radial_phase, phase)

Create a square “wiggles” image with values in [0, 1].

tachypy.psychophysics.noisy_bit_dithering(im, depth=256)

Implement noisy-bit dithering from Allard & Faubert (2008).

Parameters:
  • im (ndarray) – Input image matrix with values expected in [0, 1].

  • depth (int) – Number of display levels (default 256).

tachypy.psychophysics.normalize_to_unit_interval(im)

Normalize an array to [0, 1], returning zeros for constant arrays.

tachypy.psychophysics.stretch(im)

Deprecated alias for normalize_to_unit_interval().

Wooting pressure feedback

Keyboard-agnostic visual feedback toolkit (see Wooting Analog Keyboards). These modules never import a keyboard package; they render feedback for any object satisfying tachypy.feedback.PressureSource.

Visual pressure-feedback toolkit for analog keyboards.

Keyboard-agnostic: it renders feedback for any object satisfying PressureSource and never imports a keyboard package. Most users do not import from here directly — they call wait_light_press_visual on an acquisition class enriched with VisualPressureFeedbackMixin (see tachypy.wooting). The building blocks below are exposed for power users who want custom widgets or to drive the loop manually.

Layout

  • model — pure logic: PressureSource, PressureFeedbackConfig (thresholds, hold, and scaling), and PressureFeedbackState (no OpenGL).

  • widgets — rendering: PressureFeedbackWidget (ABC) and the default InteractiveFixationCross.

  • runner — the agnostic loop (run_light_press_visual) and the user-facing VisualPressureFeedbackMixin.

class tachypy.feedback.InteractiveFixationCross(screen, center=None, half_width: float = 8.0, half_height: float = 8.0, thickness: float = 1.0, initial_color=(100, 100, 100), target_color=(0, 0, 0), vertical_color=None, background_color=(128, 128, 128), fixation_cross=None, acquisition=None, show_goal_markers: bool = False, show_pressure_text: bool = False, left_pressure_label: str = '', right_pressure_label: str = '', pressure_text_color=None, pressure_text_font_size: int | None = None, pressure_text_width: float | None = None, pressure_text_height: float | None = None, pressure_text_gap: float = 10.0, pressure_text_decimals: int = 2, pressure_text_font_name: str | None = None)
draw() None

Draw the interactive fixation cross and optional pressure text.

Notes

The vertical line is always drawn. A horizontal side with scale 0 is hidden, which corresponds to no detected pressure on that side.

update(state: PressureFeedbackState) None

Update the widget from a pressure feedback state.

Parameters:

state (PressureFeedbackState) – Latest pressure feedback state. The widget copies pressure values, statuses, scales, and hold progress from this object.

Returns:

The widget state is updated in place.

Return type:

None

class tachypy.feedback.PressureFeedbackConfig(min_pressure_start: float = 0.01, max_pressure_start: float = 0.35, threshold: float = 0.8, hold_seconds: float = 0.3, min_scale: float = 0.25, normal_scale: float = 1.0, max_scale: float = 2.0)

Settings for pressure-readiness feedback: thresholds, hold, and scaling.

Parameters:
  • min_pressure_start (float, default=0.01) – Lower bound for the accepted light-press interval.

  • max_pressure_start (float, default=0.35) – Upper bound for the accepted light-press interval.

  • threshold (float, default=0.8) – Response threshold used by the acquisition task. Must be greater than max_pressure_start.

  • hold_seconds (float, default=0.30) – Duration both pressures must remain inside the accepted interval before readiness is reached.

  • min_scale (float) – Visual scale factors for the weakest non-zero pressure, the in-range pressure, and strong over-pressure (used by scale_for()).

  • normal_scale (float) – Visual scale factors for the weakest non-zero pressure, the in-range pressure, and strong over-pressure (used by scale_for()).

  • max_scale (float) – Visual scale factors for the weakest non-zero pressure, the in-range pressure, and strong over-pressure (used by scale_for()).

classmethod from_source(source, *, hold_seconds: float | None = None, **overrides)

Build a config from a PressureSource.

Parameters:
  • source (PressureSource) – Object exposing min_pressure_start, max_pressure_start, threshold and hold_seconds (e.g. a keyboard acquisition).

  • hold_seconds (float, optional) – Override the source’s hold_seconds.

  • **overrides – Any other field to override (scale factors, thresholds, …).

Return type:

PressureFeedbackConfig

scale_for(pressure: float) float

Return the visual scale factor for one pressure value.

Returns 0.0 when pressure is exactly zero, normal_scale inside the accepted interval, and a clamped continuous scale outside it.

class tachypy.feedback.PressureFeedbackState(config: PressureFeedbackConfig, left_pressure: float = 0.0, right_pressure: float = 0.0, left_scale: float = 1.0, right_scale: float = 1.0, left_status: Literal['too_weak', 'ideal', 'too_strong'] = 'too_weak', right_status: Literal['too_weak', 'ideal', 'too_strong'] = 'too_weak', hold_progress: float = 0.0, elapsed_hold_time: float = 0.0, is_ready: bool = False, _hold_started_at: float | None = None)

State machine for real-time pressure feedback.

Parameters:

config (PressureFeedbackConfig) – Feedback thresholds, hold duration, and scale factors.

left_pressure, right_pressure

Most recent pressure values.

Type:

float

left_scale, right_scale

Current visual scale values for the left and right horizontal segments.

Type:

float

left_status, right_status

Pressure classification for each side.

Type:

{“too_weak”, “ideal”, “too_strong”}

hold_progress

Fraction of the hold duration completed, clamped to [0, 1].

Type:

float

elapsed_hold_time

Seconds spent continuously inside the accepted interval.

Type:

float

is_ready

True once both pressures have remained ideal for hold_seconds.

Type:

bool

update(left_pressure: float, right_pressure: float, now: float) None

Update pressure status, scale, hold timer, and readiness.

Parameters:
  • left_pressure (float) – Current pressure for the left monitored key.

  • right_pressure (float) – Current pressure for the right monitored key.

  • now (float) – Current monotonic timestamp, usually from time.perf_counter().

Returns:

The object is updated in place.

Return type:

None

class tachypy.feedback.PressureFeedbackWidget

Abstract drawing interface for pressure feedback widgets.

Notes

Widgets consume a PressureFeedbackState and render it using a specific backend. The feedback runner only depends on this interface, so new visual backends can be added without changing the loop logic.

abstractmethod draw() None

Draw the widget using its rendering backend.

abstractmethod update(state: PressureFeedbackState) None

Receive the latest pressure feedback state.

Parameters:

state (PressureFeedbackState) – Current pressure, scale, status, hold progress, and readiness state.

class tachypy.feedback.PressureSource(*args, **kwargs)

Minimal interface a keyboard must expose to drive visual feedback.

The feedback engine is keyboard-agnostic: it only needs a way to read pressures and the light-press thresholds. Any object satisfying this protocol (for example tachywooting.WOOTING_ACQUISITION) can drive the visual feedback, without TachyPy ever importing the keyboard package.

min_pressure_start, max_pressure_start

Bounds of the accepted light-press interval.

Type:

float

threshold

Response threshold of the acquisition task.

Type:

float

hold_seconds

Default continuous-hold duration for readiness checks.

Type:

float

read_pressures(keys)

Return current analog pressures ([0, 1]) for the given keys, as a mapping keyed by str(key) preserving input order.

class tachypy.feedback.VisualPressureFeedbackMixin

Adds wait_light_press_visual() to a PressureSource.

Any acquisition class that satisfies the PressureSource contract becomes able to show visual feedback simply by mixing this in:

class WOOTING_ACQUISITION(BaseWooting, VisualPressureFeedbackMixin):
    ...
wait_light_press_visual(target_keys: Sequence[str | int], screen, response_handler=None, fixation_cross=None, overlay_drawables: Sequence[object] | None = None, hold_seconds: float | None = None, timeout_seconds: float | None = None, background_color: tuple[int, int, int] = (128, 128, 128), initial_color: tuple[int, int, int] | None = None, show_pressure_text: bool | None = None, show_goal_markers: bool | None = None, exit_keys: Sequence[str] = ('escape', 'esc', 'enter', 'return', 'space', 'q'), widget: Any | None = None, verbose: bool = False) bool

Wait for two keys to stay in the light-press range while showing visual feedback.

Parameters:
  • target_keys (sequence of str or int) – Exactly two keys. The first controls the left side of the widget, the second the right side.

  • screen (TachyPy Screen object) – Must expose flip(). If it exposes fill(color), the screen is cleared with background_color each frame.

  • response_handler (TachyPy ResponseHandler, optional) – When provided, quit requests and exit_keys presses return False.

  • fixation_cross (TachyPy FixationCross, optional) – Existing fixation cross whose geometry and color are copied by the auto-created widget. Invalid with widget.

  • overlay_drawables (sequence, optional) – Objects with a .draw() method called each frame after the widget.

  • hold_seconds (float, optional) – Required continuous hold duration. Defaults to self.hold_seconds.

  • timeout_seconds (float, optional) – Maximum wait time. Raises TimeoutError if exceeded.

  • background_color (tuple[int, int, int], default=(128, 128, 128)) – RGB color used to clear the screen each frame.

  • initial_color (tuple[int, int, int], optional) – Starting color of the horizontal bar. Defaults to (100, 100, 100). Invalid with widget.

  • show_pressure_text (bool, optional) – Show real-time pressure values above the cross for out-of-range keys. Defaults to False. Invalid with widget.

  • show_goal_markers (bool, optional) – Show thin ticks at the target positions. Defaults to False. Invalid with widget.

  • exit_keys (sequence of str) – Keys that abort the wait when response_handler is active.

  • widget (PressureFeedbackWidget, optional) – Full custom widget override. When provided, fixation_cross, initial_color, show_pressure_text and show_goal_markers are invalid.

  • verbose (bool, default=False) – Reserved for future logging hooks.

Returns:

True when both keys were held in range for hold_seconds. False when the user exits via response_handler.

Return type:

bool

Raises:
  • ValueError – Invalid arguments or incompatible parameter combinations.

  • TimeoutErrortimeout_seconds exceeded before readiness.

Examples

>>> acq.wait_light_press_visual(target_keys=["c", "z"], screen=screen)
>>> acq.wait_light_press_visual(
...     target_keys=["c", "z"], screen=screen,
...     response_handler=rh, fixation_cross=fixation,
... )
tachypy.feedback.run_light_press_visual(*, read_pair: Callable[[], tuple[float, float]], state: PressureFeedbackState, widget: PressureFeedbackWidget, screen, response_handler=None, exit_keys: Sequence[str] = ('escape', 'esc', 'enter', 'return', 'space', 'q'), overlay_drawables: Sequence[object] | None = None, background_color=(128, 128, 128), timeout_seconds: float | None = None, wait_until: Callable[[float], None] | None = None, verbose: bool = False) bool

Run the visual light-press feedback loop until ready or aborted.

Parameters:
  • read_pair (callable) – Zero-argument callable returning (left_pressure, right_pressure).

  • state (PressureFeedbackState) – Feedback state machine to drive each frame.

  • widget (PressureFeedbackWidget) – Widget updated and drawn each frame.

  • screen (object) – TachyPy Screen-like object. Must expose flip(); if it exposes fill(color), the screen is cleared with background_color.

  • response_handler (object, optional) – ResponseHandler-like object. Exit and quit requests return False.

  • exit_keys (sequence of str) – Keys that abort the wait when response_handler is active.

  • overlay_drawables (sequence, optional) – Objects with .draw() called each frame after the widget.

  • background_color (tuple or callable) – RGB color (or callable returning one) used to clear the screen.

  • timeout_seconds (float, optional) – Maximum wait time. Raises TimeoutError if exceeded.

  • wait_until (callable, optional) – wait_until(next_t) used to pace the loop. Defaults to a portable sleep; pass a keyboard’s precise tick for tighter timing.

  • verbose (bool, default=False) – Reserved for future logging hooks.

Returns:

True when both keys were held in range for the hold duration. False when the user exits via response_handler.

Return type:

bool