From 32665a4af7fe429f58436e010fb4e74b57bcdcc7 Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 14 Jul 2026 19:26:23 +0000 Subject: [PATCH] fix(tui): kept tmux keyboard input in legacy mode Skipped the xterm modifyOtherKeys fallback inside tmux when Kitty keyboard negotiation is unavailable, preserving legacy key delivery. Added a regression test for DA1-driven negotiation under tmux. Fixes #5378 --- packages/tui/CHANGELOG.md | 4 ++++ packages/tui/src/terminal.ts | 1 + .../test/kitty-keyboard-da1-ordering.test.ts | 21 ++++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 2a6e16a07..4837ee707 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed tmux sessions becoming unresponsive after terminal capability replies by keeping keyboard input in legacy mode when the Kitty protocol is unavailable ([#5378](https://github.com/can1357/oh-my-pi/issues/5378)). + ## [16.5.0] - 2026-07-13 ### Changed diff --git a/packages/tui/src/terminal.ts b/packages/tui/src/terminal.ts index b35dfa1f5..eb33c98e2 100644 --- a/packages/tui/src/terminal.ts +++ b/packages/tui/src/terminal.ts @@ -36,6 +36,7 @@ export function resolveHangulCompatibilityJamoWidthFromTerminalIdentity( } function shouldEnableModifyOtherKeysFallback(env: NodeJS.ProcessEnv = Bun.env): boolean { + if (isInsideTmux(env)) return false; if (!env.SSH_CONNECTION && !env.SSH_TTY && !env.SSH_CLIENT) return true; return TERMINAL.id !== "base" && TERMINAL.id !== "trueColor"; } diff --git a/packages/tui/test/kitty-keyboard-da1-ordering.test.ts b/packages/tui/test/kitty-keyboard-da1-ordering.test.ts index f38a158c5..300e16d1c 100644 --- a/packages/tui/test/kitty-keyboard-da1-ordering.test.ts +++ b/packages/tui/test/kitty-keyboard-da1-ordering.test.ts @@ -22,9 +22,10 @@ class ModalProbe implements Component { const originalSshConnection = Bun.env.SSH_CONNECTION; const originalSshTty = Bun.env.SSH_TTY; const originalSshClient = Bun.env.SSH_CLIENT; +const originalTmux = Bun.env.TMUX; const originalTerminalId = TERMINAL.id; -function restoreEnv(name: "SSH_CONNECTION" | "SSH_TTY" | "SSH_CLIENT", value: string | undefined): void { +function restoreEnv(name: "SSH_CONNECTION" | "SSH_TTY" | "SSH_CLIENT" | "TMUX", value: string | undefined): void { if (value === undefined) { delete Bun.env[name]; return; @@ -41,6 +42,7 @@ describe("ProcessTerminal kitty keyboard progressive-enhancement ordering", () = restoreEnv("SSH_CONNECTION", originalSshConnection); restoreEnv("SSH_TTY", originalSshTty); restoreEnv("SSH_CLIENT", originalSshClient); + restoreEnv("TMUX", originalTmux); Object.defineProperty(TERMINAL, "id", { value: originalTerminalId, configurable: true }); }); @@ -110,6 +112,23 @@ describe("ProcessTerminal kitty keyboard progressive-enhancement ordering", () = expect(harness.terminal.keyboardEnhancementEnterSequence).toBeNull(); }); + it("keeps legacy keyboard input under tmux when kitty is unavailable", async () => { + Bun.env.TMUX = "/tmp/tmux-501/default,1234,0"; + delete Bun.env.SSH_CONNECTION; + delete Bun.env.SSH_TTY; + delete Bun.env.SSH_CLIENT; + harness = createProcessTerminalRenderHarness(100, 30); + await harness.settle(); + harness.writes.length = 0; + + await harness.feed("\x1b[?1;2c"); + + const out = harness.writes.join(""); + expect(harness.terminal.kittyProtocolActive).toBe(false); + expect(out).not.toContain("\x1b[>4;2m"); + expect(harness.terminal.keyboardEnhancementEnterSequence).toBeNull(); + }); + it("reasserts modifyOtherKeys fallback when fullscreen overlays enter the alternate screen", async () => { harness = createProcessTerminalRenderHarness(100, 30); await harness.settle();