Input Handling
TUIX captures keyboard and mouse input on a dedicated background thread and delivers events to widgets via snapshots.
Architecture
The input system runs as a background thread started by input.listen(). It reads raw platform events and enqueues them into two circular buffers: one for keyboard events and one for mouse events. Each buffer holds up to 128 events. The main thread consumes events by calling input.get_snapshot(), which pops one event from each queue and returns them in a TuixInputSnapshot structure.
Input Snapshots
A snapshot is a point-in-time capture of the input state. It contains the current terminal dimensions and pointers to keyboard and mouse event data.
snap = input.get_snapshot()
# Feed to interactive widgets
objects.tuix_choice_feed_input(obj, snap)
# or
objects.tuix_input_feed_input(obj, snap)Snapshots are the bridge between the input thread and widget logic. You call get_snapshot() once per frame and pass the result to each widget that needs input.
Keyboard Events
Keyboard events contain key code, scan code, modifier flags, press/repeat state, timestamp, and up to 8 bytes of UTF-8 text.
| Field | Type | Description |
|---|---|---|
| btn | int | Key button identifier |
| code | int | Key code |
| scancode | int | Hardware scan code |
| modifiers | int | Modifier flags (Shift, Ctrl, Alt) |
| pressed | int | 1 if key is down, 0 if up |
| repeat | int | 1 if this is a key repeat event |
| timestamp | double | Event timestamp |
| has_event | int | 1 if an event is present |
| text | char[8] | UTF-8 text generated by the key |
Mouse Events
Mouse events capture position, button, and event type. The event system supports press, release, hover, drag, scrolling, and double-click.
| Event Type | Value | Description |
|---|---|---|
| TUIX_MOUSE_NONE | 0 | No event |
| TUIX_MOUSE_PRESS | 1 | Button pressed |
| TUIX_MOUSE_RELEASE | 2 | Button released |
| TUIX_MOUSE_HOVER | 3 | Mouse moved (no button) |
| TUIX_MOUSE_DRAG | 4 | Mouse moved with button held |
| TUIX_MOUSE_SCROLL_UP | 5 | Scroll wheel up |
| TUIX_MOUSE_SCROLL_DOWN | 6 | Scroll wheel down |
| TUIX_MOUSE_DOUBLE_CLICK | 7 | Double-click detected |
| TUIX_MOUSE_HSCROLL_LEFT | 8 | Horizontal scroll left |
| TUIX_MOUSE_HSCROLL_RIGHT | 9 | Horizontal scroll right |
| Button | Value |
|---|---|
| TUIX_BTN_LEFT | 0 |
| TUIX_BTN_MIDDLE | 1 |
| TUIX_BTN_RIGHT | 2 |
| TUIX_BTN_X1 | 3 |
| TUIX_BTN_X2 | 4 |
Platform Implementation
On Windows, the input thread uses ReadConsoleInputW to receive native KEY_EVENT_RECORD and MOUSE_EVENT_RECORD structures. A button state machine tracks press/release edges for accurate click detection. ENABLE_VIRTUAL_TERMINAL_INPUT is intentionally not used to avoid a Windows bug where SGR-encoded mouse events are misinterpreted as keyboard input.
On POSIX systems (Linux, macOS), the terminal is set to raw mode and a single pthread reads from stdin. Mouse events are parsed from SGR escape sequences. The terminal mode is restored when input.stop() is called.
Usage Pattern
from tuix.core import input, objects
# Start listening
input.listen()
# In your render loop
while running:
snap = input.get_snapshot()
objects.tuix_choice_feed_input(choice_obj, snap)
objects.tuix_input_feed_input(input_obj, snap)
# ... render ...
# Stop listening
input.stop()