Table of Contents

Class TerminalInput

Namespace
Retro.Crt.Input
Assembly
Retro.Crt.dll

Read decoded InputEvents from stdin. Pair with RawMode so the terminal actually delivers bytes instead of cooked, line-buffered input.

public static class TerminalInput
Inheritance
TerminalInput
Inherited Members

Remarks

Maintains a small UTF-8 byte buffer and a parser char buffer between calls so escape sequences split across reads still parse correctly. All state is process-global because stdin is.

On Unix, TryReadEvent(out InputEvent) uses poll(2) with timeout 0 to check for available bytes without blocking. On Windows the underlying WaitForSingleObject is best-effort: a console handle becomes signaled on any input event (including key-up events that produce no VT bytes), so an occasional false positive followed by a short blocking ReadFile is possible. For strict non-blocking semantics on Windows, run ReadEvent() on a background thread and post events to your main loop yourself.

Methods

ReadEvent()

Block until one InputEvent can be parsed, then return it. Throws EndOfStreamException if stdin closes before any further event arrives.

public static InputEvent ReadEvent()

Returns

InputEvent

TryReadEvent(out InputEvent)

Try to return the next event without blocking. Returns false when no complete event is currently buffered AND no new bytes are available (or stdin is at EOF).

public static bool TryReadEvent(out InputEvent ev)

Parameters

ev InputEvent

Returns

bool

WaitForEvent(int, out InputEvent)

Wait up to timeoutMs milliseconds for an event. Returns true when an event was decoded, false when the timeout expires or stdin reaches EOF. Pass 0 for a strictly non-blocking poll, or a negative number to wait indefinitely (equivalent to ReadEvent() minus the EOF exception).

public static bool WaitForEvent(int timeoutMs, out InputEvent ev)

Parameters

timeoutMs int
ev InputEvent

Returns

bool

Remarks

Resolves the classic ESC-vs-CSI ambiguity: a lone 0x1b byte could be the user pressing Escape OR the start of a still- arriving cursor / function key sequence, so the parser stays optimistic and reports Incomplete. After a non-zero timeoutMs wait that delivered no follow-up bytes, this method commits the buffered ESC as a real Escape keypress — otherwise apps that bind Escape (modal close, menu dismiss) would feel stuck until the next keystroke nudged the parser forward.