Input Handling

Cross-platform key reader with full escape sequence support.

2 min read 365 words

Milo's input system reads raw terminal input and translates escape sequences into structuredKeyobjects. It handles arrows, function keys, modifiers, and platform differences.

KeyReader

KeyReader is a context manager that puts the terminal in raw mode and yields Keyobjects:

from milo.input import KeyReader

with KeyReader() as keys:
    for key in keys:
        print(f"Got: {key.name or key.char}")
        if key.ctrl and key.char == "c":
            break

Key objects

Each keypress produces a frozenKeydataclass:

Key(
    char="a",       # The character (or empty for special keys)
    name=None,      # SpecialKey enum value for non-character keys
    ctrl=False,     # Ctrl modifier
    alt=False,      # Alt/Option modifier
    shift=False,    # Shift modifier
)

Special keys

TheSpecialKeyenum covers all standard terminal keys:

Category Keys
Arrows UP, DOWN, LEFT, RIGHT
Navigation HOME, END, PAGE_UP, PAGE_DOWN
Editing INSERT, DELETE, BACKSPACE
Control TAB, ENTER, ESCAPE
Function F1 through F12

Escape sequences

Milo includes a frozen lookup table mapping ANSI VT100/xterm escape sequences toKeyobjects. This covers:

  • Plain keys (arrows, F-keys, Home, End, etc.)
  • Shift+key variants
  • Alt+key variants
  • Ctrl+key variants

Platform support

Usestermios + tty for raw mode, selectfor non-blocking reads.

from milo.input._platform import raw_mode, read_char, is_tty

if is_tty():
    with raw_mode():
        ch = read_char()

Usesmsvcrtfor raw character reads.

# Automatically selected on Windows — same KeyReader API
with KeyReader() as keys:
    for key in keys:
        ...

Tip

Useis_tty()to check if stdin is an interactive terminal before entering raw mode. This lets your app degrade gracefully when input is piped.