▶ YouTube Summaries

← All summaries

Immediate-mode keybindings with auto-generated help page in Jai

2026-11-05 Thu ⏱ 1 hr 50 min tsodingdaily

Tsoding adds a centralized but still immediate-mode keybinding system to Sowon2, his Jai + raylib music player/timer that is driven almost entirely by shortcuts. Each shortcut check also logs itself with a description and source location, so the app can show an F1 help page listing exactly the shortcuts available in the current context, and later flag collisions - without refactoring every existing IsKeyPressed call site.

The problem

  • Keyboard-only UI keeps the GUI trivial (no buttons), but there are now too many shortcuts to remember.
  • A README would rot. A classic centralized keymap is not "immediate modable": every IsKeyPressed check scattered through the frame would have to be rewritten.

Design

  • Global Key_Bindings state persisting across frames, bracketed per frame by key_bindings_begin(*kb) / key_bindings_end(*kb).
  • =key_bindings_pressed(*kb, modifiers, key, description, loc=#caller_location)= behaves like IsKeyPressed but appends a Key_Stroke (modifiers, key, description, source location) to a per-frame log.
  • begin clears the log; by the end of the frame the log holds every shortcut the current context checked.
  • Modifiers are a Jai enum_flags (Ctrl, Shift, Alt) - a bitmask; chat compares it to Pascal sets. Modifiers not in the mask must be up, so Ctrl+Z and Ctrl+Shift+Z are distinct flat bindings instead of nested ifs.
  • Collisions: initially logged on detection, then moved to the help page (duplicates shown in red, ideally clickable to jump to source via emacsclient) to avoid a log line per frame. A compile-time check via Jai metaprogramming - BFS over the function's control flow graph, the same algorithm used to type-check Porth - is floated as a future idea.
  • Both APIs coexist: unmigrated raw key checks keep working, they just don't appear in help.

Help page

  • F1 sets "switch to help mode on next frame": the log is only complete at frame end, and the help page has its own keys, so key_bindings_snapshot freezes the previous frame's log before switching.
  • F1 has to be bound per mode, otherwise opening help from help recursively snapshots the help page's own keys.
  • Rendering: modifiers joined with + via a temp-allocated string builder, key names formatted, rounded background and frame around each key stroke, aligned description column; Escape returns to the previous mode.

Ideas parked for later

  • Grouping bindings, hidden (debug) bindings, search in help, popup instead of a full page, region-scoped uniqueness, modifier-only chords (Shift+Alt).