···11+/* input.h — VT/ANSI escape sequence parser for terminal input
22+ *
33+ * Decodes raw terminal bytes into structured InputEvent records. Handles
44+ * escape sequences (arrow keys, function keys, etc.), mouse protocols
55+ * (VT200, SGR, urxvt), UTF-8 multibyte characters, and control keys.
66+ *
77+ *
88+ * Usage:
99+ * 1. input does not allocate any memory itself, so start by allocating
1010+ * input_size() bytes of memory.
1111+ * 2. Call input_init(mem, esc_latency_ms) to get an InputState.
1212+ * 3. When bytes arrive from stdin, call input_scan(st, buf, len, now).
1313+ * 4. Read events with input_count(st) and input_event(st, i).
1414+ * 5. Check input_delay(st): if non-zero, re-call input_scan() with
1515+ * an empty buffer (len=0) after that many milliseconds to resolve
1616+ * a pending lone ESC.
1717+ *
1818+ * Example:
1919+ *
2020+ * void *mem = malloc(input_size());
2121+ * struct InputState *st = input_init(mem, 50);
2222+ *
2323+ * // in your event loop:
2424+ * int accepted = input_scan(st, buf, nread, now_ms);
2525+ * for (int i = 0; i < input_count(st); i++) {
2626+ * struct InputEvent *ev = input_event(st, i);
2727+ * // handle ev->type, ev->key, ev->ch, ev->mod ...
2828+ * }
2929+ * int delay = input_delay(st);
3030+ * if (delay > 0) {
3131+ * // schedule another input_scan(st, NULL, 0, now_ms) after delay ms
3232+ * }
3333+ *
3434+ * Gotchas:
3535+ *
3636+ * - input_scan() may accept fewer bytes than provided if the internal
3737+ * buffer (SCAN_BUFFER_SIZE) is full. The caller must re-feed the remainder.
3838+ * - Event pointers from input_event() are invalidated by the next
3939+ * input_scan() call. Copy any data you need before scanning again.
4040+ * - At most 128 events are produced per scan. If saturated, the last
4141+ * slot is overwritten. In practice this is unreachable.
4242+ * - A lone ESC byte is ambiguous: it could be the Escape key or the
4343+ * start of a sequence. The parser holds it until either more bytes
4444+ * arrive or the ESC latency expires. You must honour input_delay() and
4545+ * re-call input_scan() with len=0 to flush it.
4646+ * - The `now` parameter must be monotonically increasing milliseconds
4747+ * (e.g. Date.now()). The parser uses it solely for ESC latency
4848+ * disambiguation.
4949+ */
5050+5151+#ifndef INPUT_H
5252+#define INPUT_H
5353+5454+#include <stdint.h>
5555+5656+/* ── Event types ──────────────────────────────────────────────────── */
5757+5858+#define EVENT_KEY 1
5959+#define EVENT_MOUSE 2
6060+#define EVENT_RESIZE 3
6161+6262+/* ── Modifier flags (bitwise) ─────────────────────────────────────── */
6363+6464+#define MOD_ALT 1
6565+#define MOD_CTRL 2
6666+#define MOD_SHIFT 4
6767+#define MOD_MOTION 8
6868+#define MOD_RELEASE 16
6969+7070+/* ── Key codes ────────────────────────────────────────────────────── */
7171+7272+/* Function keys */
7373+#define KEY_F1 0xFFFF
7474+#define KEY_F2 0xFFFE
7575+#define KEY_F3 0xFFFD
7676+#define KEY_F4 0xFFFC
7777+#define KEY_F5 0xFFFB
7878+#define KEY_F6 0xFFFA
7979+#define KEY_F7 0xFFF9
8080+#define KEY_F8 0xFFF8
8181+#define KEY_F9 0xFFF7
8282+#define KEY_F10 0xFFF6
8383+#define KEY_F11 0xFFF5
8484+#define KEY_F12 0xFFF4
8585+8686+/* Navigation */
8787+#define KEY_ARROW_UP 0xFFF3
8888+#define KEY_ARROW_DOWN 0xFFF2
8989+#define KEY_ARROW_LEFT 0xFFF1
9090+#define KEY_ARROW_RIGHT 0xFFF0
9191+#define KEY_HOME 0xFFEF
9292+#define KEY_END 0xFFEE
9393+#define KEY_INSERT 0xFFED
9494+#define KEY_DELETE 0xFFEC
9595+#define KEY_PGUP 0xFFEB
9696+#define KEY_PGDN 0xFFEA
9797+#define KEY_BACKTAB 0xFFE9
9898+9999+/* Mouse */
100100+#define KEY_MOUSE_LEFT 0xFFE8
101101+#define KEY_MOUSE_RIGHT 0xFFE7
102102+#define KEY_MOUSE_MIDDLE 0xFFE6
103103+#define KEY_MOUSE_RELEASE 0xFFE5
104104+#define KEY_MOUSE_WHEEL_UP 0xFFE4
105105+#define KEY_MOUSE_WHEEL_DOWN 0xFFE3
106106+107107+/* Special keys (ASCII range) */
108108+#define KEY_ESC 0x1B
109109+#define KEY_ENTER 0x0D
110110+#define KEY_TAB 0x09
111111+#define KEY_BACKSPACE 0x7F
112112+#define KEY_SPACE 0x20
113113+114114+/**
115115+ * Parsed terminal input event. All fields are represented as numbers for
116116+ * efficient transport via linear memory. A semantic layer is added on top in
117117+ * input.ts
118118+ *
119119+ * @field type Event kind: EVENT_KEY, EVENT_MOUSE, or EVENT_RESIZE.
120120+ * @field mod Bitwise combination of MOD_ALT, MOD_CTRL, MOD_SHIFT, MOD_MOTION.
121121+ * @field key KEY_* constant for special keys, raw byte for control chars,
122122+ * or 0 when the event is a printable character (see ch).
123123+ * @field ch Unicode codepoint for printable characters, 0 otherwise.
124124+ * @field x Mouse column (0-based). Only valid for EVENT_MOUSE.
125125+ * @field y Mouse row (0-based). Only valid for EVENT_MOUSE.
126126+ * @field w Terminal width. Only valid for EVENT_RESIZE.
127127+ * @field h Terminal height. Only valid for EVENT_RESIZE.
128128+ */
129129+struct InputEvent {
130130+ uint8_t type;
131131+ uint8_t mod;
132132+ uint16_t key;
133133+ uint32_t ch;
134134+ int32_t x;
135135+ int32_t y;
136136+ int32_t w;
137137+ int32_t h;
138138+};
139139+140140+/**
141141+ * A struct in which the entire input state can be stored. It is deliberately
142142+ * opaque since it comprises the private state of the input scanner.
143143+ */
144144+struct InputState;
145145+146146+/**
147147+ * Return the number of bytes needed to allocate an InputState.
148148+ *
149149+ * @return Required arena size in bytes (8-byte aligned).
150150+ */
151151+int input_size(void);
152152+153153+/**
154154+ * Initialize an input parser in the provided memory.
155155+ *
156156+ * @param mem Pointer to at least input_size() bytes.
157157+ * @param esc_latency_ms ESC disambiguation latency in milliseconds.
158158+ * @return Initialized parser state.
159159+ */
160160+struct InputState *input_init(void *mem, int esc_latency_ms);
161161+162162+/**
163163+ * Feed raw bytes into the parser and produce events.
164164+ *
165165+ * @param st Parser state from input_init().
166166+ * @param buf Input bytes to parse.
167167+ * @param len Number of bytes in buf.
168168+ * @param now Current timestamp in milliseconds (e.g. Date.now()).
169169+ * Used for ESC latency disambiguation.
170170+ * @return Number of bytes accepted. May be less than len if the
171171+ * internal buffer is full (caller should re-feed the rest).
172172+ */
173173+int input_scan(struct InputState *st, const char *buf, int len, double now);
174174+175175+/**
176176+ * Return the number of events produced by the last input_scan() call.
177177+ *
178178+ * @param st Parser state.
179179+ * @return Event count (0 to 128).
180180+ */
181181+int input_count(struct InputState *st);
182182+183183+/**
184184+ * Return a pointer to the event at the given index.
185185+ *
186186+ * @param st Parser state.
187187+ * @param index Event index (0-based).
188188+ * @return Pointer to the event, or NULL if index is out of range.
189189+ */
190190+struct InputEvent *input_event(struct InputState *st, int index);
191191+192192+/**
193193+ * Return the ESC latency delay if an ambiguous ESC is pending.
194194+ *
195195+ * @param st Parser state.
196196+ * @return esc_latency_ms if a lone ESC is buffered, 0 otherwise.
197197+ * When non-zero, the caller should re-call input_scan()
198198+ * with an empty buffer after this many milliseconds.
199199+ */
200200+int input_delay(struct InputState *st);
201201+202202+#endif
···5566#include <stdint.h>
7788+/**
99+ * Return the byte length of a UTF-8 sequence given its leading byte.
1010+ *
1111+ * @param c Leading byte of a UTF-8 sequence.
1212+ * @return Number of bytes in the sequence (1–6).
1313+ */
1414+int utf8_len(char c);
1515+1616+/**
1717+ * Decode a UTF-8 sequence into a Unicode codepoint.
1818+ *
1919+ * @param out Output codepoint.
2020+ * @param c Pointer to the start of a UTF-8 sequence.
2121+ * @return Number of bytes consumed (1–6), or negative on error.
2222+ * Returns 0 if c points to a null terminator.
2323+ */
824int utf8_decode(uint32_t *out, const char *c);
2525+2626+/**
2727+ * Encode a Unicode codepoint as UTF-8.
2828+ *
2929+ * @param out Output buffer (must hold at least 7 bytes including null).
3030+ * @param c Unicode codepoint.
3131+ * @return Number of bytes written (1–6), excluding null terminator.
3232+ */
933int utf8_encode(char *out, uint32_t c);
10341135#endif