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
This commit is contained in:
ddidderr committed 2026-10-11 21:56:07 +02:00
1 parent 5b8c92b98c
commit e03432241b
21 files changed
+13413 -1

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
# 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.