These libraries are experimental. APIs may change without notice. Generated from source with koruc 0.1.7 on 11/4/2026.
Kbd
@korulang/kbd@0.0.1Raw nonblocking keyboard reads for terminal Koru programs (termios cbreak + poll + CSI arrow decode)
kbd/index.kz · 5 tors
@korulang/kbd — raw nonblocking keyboard reads for terminal Koru programs. · 29 more lines
@korulang/kbd — raw nonblocking keyboard reads for terminal Koru programs.
The lightest path to live keys: termios cbreak+noecho on stdin (VMIN=0,
VTIME=0), then poll()+read() drained through a byte-level decoder for the
two sequences a game client actually wants — WASD single bytes and CSI
arrow escapes (ESC [ A..D, plus the SS3 alternate ESC O A..D). No event
loop, no alternate screen, no library dependency — three host procs and a
64-deep decoded-key queue.
import libs/kbd
import std/io
libs/kbd:raw()
|> for(0..4000)
! each _ |> libs/kbd:keys(max: 8)
! key k |> libs/kbd:key.name(code: k.code): n
|> std/io:print.ln("{{ n:s }}")
| done |> std/time:sleep-ms(ms: 16)
| done |> libs/kbd:restore()
Codes: 1 up, 2 down, 3 left, 4 right, 5 w, 6 a, 7 s, 8 d, 9 q, 10 space,
11 enter, 12 tab, 13 escape — anything else arrives as 1000+byte (a raw
passthrough so unmapped keys stay distinguishable). 0 is the empty queue:
`keys` reports it as | done, `read` returns it.
Named gaps, honestly: terminals send no key-up — held-key state is
repeat-arrival only. ISIG stays on so ^C still kills (and leaves the tty
raw — restore is the caller's job). A lone Escape is reported only after
two consecutive empty polls: it shares a prefix with every CSI sequence.
raw
index.kz:140// Lifecycle — raw cbreak stdin in, the original termios back out.
//
// Put stdin in cbreak no-echo mode: keys arrive per-press and don't print.
// Non-tty stdin (a pipe, a redirect) is tolerated — poll+read is already
// nonblocking on the data-ready edge. ISIG is kept so ^C still kills.
~pub tor raw {} -> i32restore
index.kz:156// Restore the saved termios. A no-op when stdin was never a tty.
~pub tor restore {} -> i32read
index.kz:170// Reading — the scalar pop and the drain combinator.
//
// Pop one decoded key after a drain sweep; 0 when nothing is queued.
~pub tor read {} -> i32keys
index.kz:178// The source combinator (the `! key` sibling of udp's `! packet`): fire once
// per decoded press currently queued, stop at `max` or at the empty queue.
~pub tor keys { max: i32 }
! key Key
| donekey.name
index.kz:197// The code as a name — for echo tests and HUDs, not for keybinds (bind on
// the code; the names are display strings).
~pub tor key.name { code: i32 } -> string