fix(runtime): kitty key-release delivers input like Ink, not '' (parity) (#91)

useInput had an undocumented guard that blanked `input` to '' on any kitty key-RELEASE
event, so a printable release (and a ctrl+letter release) delivered nothing. Ink has no
release special-case -- it classifies a kitty event purely by isPrintable/ctrl+letter, so
a printable release delivers `text ?? name` and a ctrl+letter release delivers the letter
name (use-input.ts:204-217). Removes the guard to match.

The kept "Ctrl+C exits under kitty" divergence is unaffected: the exit check in emitInput
is already scoped to `eventType !== "release"`, so a Ctrl+C release flows through as
input='c' without spuriously exiting (press still exits).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-31 16:26:13 +08:00
committed by GitHub
parent 860980de8a
commit f2397bfa00
4 changed files with 83 additions and 11 deletions
+8 -3
View File
@@ -70,9 +70,14 @@ export function useInput(
let input: string;
if (keypress.isKittyProtocol) {
if (keypress.eventType === "release") {
input = "";
} else if (keypress.isPrintable) {
// No release special-case: Ink (use-input.ts:204-217) classifies a kitty
// event purely by isPrintable / ctrl+letter, regardless of
// press/repeat/release. A printable release delivers `text ?? name` (e.g.
// 'a'); a ctrl+letter release delivers the letter name. Suppressing input
// on release here was an undocumented divergence — removed for byte-parity
// with Ink. (Ctrl+C exit is scoped to non-release in emitInput, so a
// Ctrl+C release flowing through here does not trigger a spurious exit.)
if (keypress.isPrintable) {
input = keypress.text ?? keypress.name;
} else if (keypress.ctrl && keypress.name.length === 1) {
input = keypress.name;