Merge remote-tracking branch 'origin/farm/9322146b/skip-ssh-modifyotherkeys-fallback'
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the modifyOtherKeys keyboard fallback enabling on unknown SSH terminals, avoiding broken Shift input in iOS SSH clients such as Redock ([#4325](https://github.com/can1357/oh-my-pi/issues/4325)).
|
||||
|
||||
## [16.3.0] - 2026-07-02
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -35,6 +35,11 @@ export function resolveHangulCompatibilityJamoWidthFromTerminalIdentity(
|
||||
return "platform";
|
||||
}
|
||||
|
||||
function shouldEnableModifyOtherKeysFallback(env: NodeJS.ProcessEnv = Bun.env): boolean {
|
||||
if (!env.SSH_CONNECTION && !env.SSH_TTY && !env.SSH_CLIENT) return true;
|
||||
return TERMINAL.id !== "base" && TERMINAL.id !== "trueColor";
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum encoded UTF-8 bytes per `process.stdout.write` call on Windows.
|
||||
*
|
||||
@@ -840,13 +845,13 @@ export class ProcessTerminal implements Terminal {
|
||||
break;
|
||||
}
|
||||
case "keyboard": {
|
||||
// Keyboard probe sentinel: kitty reply never arrived → fall back to modifyOtherKeys.
|
||||
if (!this.#kittyProtocolActive && !this.#modifyOtherKeysActive && this.#modifyOtherKeysTimeout) {
|
||||
// Keyboard probe sentinel: kitty reply never arrived → fall back to modifyOtherKeys
|
||||
// only where the resolved terminal is known enough to tolerate it.
|
||||
if (this.#modifyOtherKeysTimeout) {
|
||||
clearTimeout(this.#modifyOtherKeysTimeout);
|
||||
this.#modifyOtherKeysTimeout = undefined;
|
||||
this.#safeWrite("\x1b[>4;2m");
|
||||
this.#modifyOtherKeysActive = true;
|
||||
}
|
||||
this.#enableModifyOtherKeysFallback();
|
||||
break;
|
||||
}
|
||||
case "osc99Probe": {
|
||||
@@ -1054,6 +1059,13 @@ export class ProcessTerminal implements Terminal {
|
||||
}
|
||||
}
|
||||
|
||||
#enableModifyOtherKeysFallback(): void {
|
||||
if (this.#kittyProtocolActive || this.#modifyOtherKeysActive) return;
|
||||
if (!shouldEnableModifyOtherKeysFallback()) return;
|
||||
this.#safeWrite("\x1b[>4;2m");
|
||||
this.#modifyOtherKeysActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query terminal for Kitty keyboard protocol support and enable if available.
|
||||
*
|
||||
@@ -1073,11 +1085,7 @@ export class ProcessTerminal implements Terminal {
|
||||
this.#safeWrite("\x1b[?u\x1b[c");
|
||||
this.#modifyOtherKeysTimeout = setTimeout(() => {
|
||||
this.#modifyOtherKeysTimeout = undefined;
|
||||
if (this.#kittyProtocolActive || this.#modifyOtherKeysActive) {
|
||||
return;
|
||||
}
|
||||
this.#safeWrite("\x1b[>4;2m");
|
||||
this.#modifyOtherKeysActive = true;
|
||||
this.#enableModifyOtherKeysFallback();
|
||||
}, 150);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { afterEach, describe, expect, it } from "bun:test";
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import { TERMINAL } from "@oh-my-pi/pi-tui/terminal-capabilities";
|
||||
import {
|
||||
createProcessTerminalRenderHarness,
|
||||
type ProcessTerminalRenderHarness,
|
||||
@@ -18,12 +19,29 @@ class ModalProbe implements Component {
|
||||
return ["modal"];
|
||||
}
|
||||
}
|
||||
const originalSshConnection = Bun.env.SSH_CONNECTION;
|
||||
const originalSshTty = Bun.env.SSH_TTY;
|
||||
const originalSshClient = Bun.env.SSH_CLIENT;
|
||||
const originalTerminalId = TERMINAL.id;
|
||||
|
||||
function restoreEnv(name: "SSH_CONNECTION" | "SSH_TTY" | "SSH_CLIENT", value: string | undefined): void {
|
||||
if (value === undefined) {
|
||||
delete Bun.env[name];
|
||||
return;
|
||||
}
|
||||
Bun.env[name] = value;
|
||||
}
|
||||
|
||||
describe("ProcessTerminal kitty keyboard progressive-enhancement ordering", () => {
|
||||
let harness: ProcessTerminalRenderHarness | undefined;
|
||||
|
||||
afterEach(() => {
|
||||
harness?.dispose();
|
||||
harness = undefined;
|
||||
restoreEnv("SSH_CONNECTION", originalSshConnection);
|
||||
restoreEnv("SSH_TTY", originalSshTty);
|
||||
restoreEnv("SSH_CLIENT", originalSshClient);
|
||||
Object.defineProperty(TERMINAL, "id", { value: originalTerminalId, configurable: true });
|
||||
});
|
||||
|
||||
it("enables kitty when the kitty reply arrives before the DA1 sentinel", async () => {
|
||||
@@ -75,6 +93,23 @@ describe("ProcessTerminal kitty keyboard progressive-enhancement ordering", () =
|
||||
expect(out).not.toContain("\x1b[>1u");
|
||||
});
|
||||
|
||||
it("skips modifyOtherKeys fallback for SSH_CONNECTION-only unknown terminals", async () => {
|
||||
Bun.env.SSH_CONNECTION = "192.0.2.10 54321 192.0.2.20 22";
|
||||
delete Bun.env.SSH_TTY;
|
||||
delete Bun.env.SSH_CLIENT;
|
||||
Object.defineProperty(TERMINAL, "id", { value: "base", configurable: true });
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user