fix(input): carry key and preedit text as bytes like Zig

Zig's KeyEvent.utf8 and the embedded API's key/preedit text are byte
slices passed through to key encoding and the pty; the port converted
them lossily to UTF-8.
- KeyEvent.utf8 is &[u8] end to end (ghostty-input encoder, core,
  ghostty-lib C API, libghostty-vt key events, GTK callers). Where Zig
  validates with Utf8View (alternates, modify-other-keys, ctrl CSI-u,
  associated text, binding unicode lookup) invalid text takes the same
  "no UTF-8" fallback.
- Invalid preedit UTF-8 behaves like Zig's `try Utf8View.init`: the
  prior preedit is cleared and marked dirty, the callback returns an
  error (logged by the C API) and no preedit is set.
- The inspector key widget shows invalid key text lossily, display only.

Test Plan:
- cargo test --workspace --no-fail-fast (3407 passed)
- cargo test -p ghostty-lib --features test-platform (C-API key text
  0xff 0xfe reaches the pty unchanged)
- just check-macos (both), just check-windows, just check-wasm
This commit is contained in:
ddidderr committed 2026-10-12 11:01:17 +02:00
1 parent 1327e63811
commit c8113345a5
19 files changed
+277 -144

No files matched your search

+1 -1
View File
@@ -170,7 +170,7 @@ mod tests {
insp.record_key_event(crate::KeyEvent::new(&KeyEvent {
action: Action::Press,
key: Key::KeyA,
utf8: "a",
utf8: "a".as_bytes(),
..KeyEvent::default()
}));
+3 -2
View File
@@ -30,7 +30,8 @@ impl InputEvent {
mods: ev.mods,
consumed_mods: ev.consumed_mods,
composing: ev.composing,
utf8: ev.utf8.to_owned(),
// Display only: invalid UTF-8 is shown as U+FFFD.
utf8: String::from_utf8_lossy(ev.utf8).into_owned(),
unshifted_codepoint: ev.unshifted_codepoint,
}
}
@@ -494,7 +495,7 @@ mod tests {
Event::new(&KeyEvent {
action: Action::Press,
key,
utf8,
utf8: utf8.as_bytes(),
..KeyEvent::default()
})
}