Files
ddidderr 3afe938b95 feat(input): port keyboard, keybinding and mouse input handling
Ports ZIG/src/input (except macOS keymaps) into ghostty-input:
- key, key_mods (incl. RemapSet), the physical keycode table
- key_encode: legacy, modifyOtherKeys and kitty keyboard protocol
  encoders, function key tables
- Binding: all keybinding actions with their user-visible docs (for
  +list-actions), triggers, sets with sequences, chains, leader keys and
  key tables, and formatting back to config strings
- command palette defaults, mouse, paste safety checks, kitty helpers,
  links, helpgen action docs

Deviations (docs/rewrite/notes/ghostty-input.md): Mods.super is named
super_; case folding uses char::to_lowercase plus Ghostty's special
cases instead of uucode tables; chain parents are trigger paths instead
of pointers; a Zig bug where chained leaves inside sequences corrupted the
shared prefix when formatting is fixed (covered by a test).

Integration left: building encode/paste Options from terminal modes,
and implementing the EntryFormatter trait in ghostty-config.

Test Plan:
- cargo test -p ghostty-input (220 tests; 8 macOS-only skipped)
- cargo clippy -p ghostty-input --all-targets -- -D warnings
2026-10-11 21:56:07 +02:00

2.6 KiB

ghostty-input port notes

File mapping (ZIG/src/input -> crates/ghostty-input/src)

  • input.zig -> lib.rs (re-exports); config.zig -> config.rs; keyboard.zig -> keyboard.rs
  • key.zig -> key.rs (Key generated by macro with name()/from_name(); KeyEvent<'a> borrows utf8)
  • key_mods.zig -> key_mods.rs (Mods is a plain bool struct + int()/from_int() u16 layout; RemapSet is an insertion-ordered Vec)
  • keycodes.zig -> keycodes.rs (data table RAW_ENTRIES, entries() built lazily, Linux = xkb column)
  • function_keys.zig -> function_keys.rs; key_encode.zig -> key_encode.rs (legacy + kitty)
  • Binding.zig -> binding/{mod,action,set,tests}.rs; command.zig -> command.rs
  • helpgen_actions.zig -> helpgen_actions.rs (generate/generate_string)
  • mouse.zig, kitty.zig, paste.zig, Link.zig -> same-named modules
  • Skipped: KeymapDarwin.zig, KeymapNoop.zig (macOS only / no-op).

Naming deviations

  • Mods.super -> super_ (Rust keyword). Zig final -> final_ in kitty::Entry.
  • Binding Action doc comments are kept as // comments (indented lists would be doctests); text is exposed via ActionKey::docs() / Action::docs().
  • Action::scoped(Scope) returns Option<&Action>.
  • paste: encode(&[u8]) (const, may return MutableRequired) and encode_mut(&mut [u8]) replace the comptime-typed Zig function.
  • Set.chain_parent is a trigger path instead of raw pointers.
  • Case folding: char::to_lowercase plus 3 special cases rather than uucode tables.
  • Value::format_entries fixes a Zig bug (shared-buffer rewind corrupting sibling prefixes for chained leaves in sequences); test set_format_entries_sequence_shares_prefix.
  • macOS-only branches (option-as-alt translation, ctrlOrSuper on Darwin) are compiled out; Linux behaviour only.

Skipped tests

  • 7 macOS-only key_encode tests (kitty/legacy with macos option/super text, alt+x macos, etc.) and Mods translation macos-option-as-alt (ported as a Linux identity test).
  • RemapSet formatEntry tests use format_entries() (list of values) since the config formatter lives in ghostty-config.
  • Zig imguiKey (cimgui) not ported; inspector deferred.
  • Link.oniRegex not ported (regex engine chosen by consumer).

TODO(integration)

  • paste::Options::fromTerminal, key_encode::Options fromTerminal: build from terminal modes in ghostty-terminal.
  • binding::set::EntryFormatter trait stands in for config/formatter.zig; config crate should implement it.
  • Command::C / defaultsC are plain structs, not C ABI.
  • function_keys test uses a hardcoded 38-byte limit (Zig reads from termio).

Status

220 tests pass; clippy -D warnings and fmt clean.