From e6f611169b83609113ba5f1128436e07ef7a1bd4 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 19 Jun 2026 11:24:16 -0700 Subject: [PATCH] FN-6737: preserve terminal Ctrl shortcuts Keep terminal shortcut focus stable so Ctrl combinations emit control bytes reliably. - Prevent pointer, mouse, and touch activation on terminal shortcut buttons from stealing xterm focus. - Expand terminal shortcut coverage for Ctrl control codes, touch focus preservation, and platform copy modifiers. - Add a patch changeset for the published CLI package. Files changed: .changeset/fn-6737-terminal-ctrl-shortcuts.md | 5 +++ .../dashboard/app/components/TerminalModal.tsx | 31 +++++++++++++-- .../components/__tests__/TerminalModal.test.tsx | 46 +++++++++++++++++++--- 3 files changed, 73 insertions(+), 9 deletions(-) Fusion-Task-Id: FN-6737 Fusion-Task-Lineage: e27439e0-b2c5-44c1-8584-848e61d41e1b --- .changeset/fn-6737-terminal-ctrl-shortcuts.md | 5 ++ .../app/components/TerminalModal.tsx | 31 +++++++++++-- .../__tests__/TerminalModal.test.tsx | 46 ++++++++++++++++--- 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 .changeset/fn-6737-terminal-ctrl-shortcuts.md diff --git a/.changeset/fn-6737-terminal-ctrl-shortcuts.md b/.changeset/fn-6737-terminal-ctrl-shortcuts.md new file mode 100644 index 0000000000..e3d908c951 --- /dev/null +++ b/.changeset/fn-6737-terminal-ctrl-shortcuts.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": patch +--- + +Fix terminal shortcut focus preservation so on-screen Ctrl combinations emit control bytes reliably on touch and pointer devices while keeping physical Ctrl behavior intact. diff --git a/packages/dashboard/app/components/TerminalModal.tsx b/packages/dashboard/app/components/TerminalModal.tsx index 40fd5d5053..a6cf94c775 100644 --- a/packages/dashboard/app/components/TerminalModal.tsx +++ b/packages/dashboard/app/components/TerminalModal.tsx @@ -6,6 +6,8 @@ import { useCallback, type CSSProperties, type MouseEvent as ReactMouseEvent, + type PointerEvent as ReactPointerEvent, + type TouchEvent as ReactTouchEvent, } from "react"; import { useTranslation } from "react-i18next"; import { getErrorMessage } from "@fusion/core"; @@ -1256,10 +1258,21 @@ export function TerminalModal({ isOpen, onClose, initialCommand, initialCommandG /* FNXC:Terminal 2026-06-19-05:05: FN-6697 root cause: shortcut-bar buttons took browser focus on hardware-keyboard surfaces before their click handlers injected bytes, leaving xterm's helper textarea blurred even though the active session's sendInput path was correct. Preserve focus on mousedown and refocus xterm after every shortcut action so sticky modifiers, literal keys, arrows, and Ctrl-letter shortcuts deliver input without stranding subsequent hardware-keyboard typing across desktop and touch surfaces. + + FNXC:Terminal 2026-06-19-10:38: + FN-6737 root cause: touch-primary Ctrl shortcuts still allowed the browser's touchstart default action on shortcut buttons, so a tap on sticky Ctrl could move focus away from xterm's helper textarea before the composed Ctrl-letter byte reached the active PTY. Prevent the focus-taking default for mouse and touch activation, then keep the existing xterm refocus path so Ctrl control codes work from the sticky shortcut panel and physical Ctrl key paths on desktop, touch, and touch-with-hardware-keyboard surfaces. */ - const preserveShortcutFocus = useCallback((event: ReactMouseEvent) => { - event.preventDefault(); - }, []); + const preserveShortcutFocus = useCallback( + ( + event: + | ReactMouseEvent + | ReactPointerEvent + | ReactTouchEvent, + ) => { + event.preventDefault(); + }, + [], + ); const refocusTerminalAfterShortcut = useCallback(() => { xtermRef.current?.focus(); @@ -1569,7 +1582,9 @@ export function TerminalModal({ isOpen, onClose, initialCommand, initialCommandG stickyModifier === "ctrl" ? "is-active" : "" }`} data-testid="terminal-modifier-ctrl" + onPointerDown={preserveShortcutFocus} onMouseDown={preserveShortcutFocus} + onTouchStart={preserveShortcutFocus} onClick={() => toggleModifier("ctrl")} aria-pressed={stickyModifier === "ctrl"} > @@ -1581,7 +1596,9 @@ export function TerminalModal({ isOpen, onClose, initialCommand, initialCommandG stickyModifier === "alt" ? "is-active" : "" }`} data-testid="terminal-modifier-alt" + onPointerDown={preserveShortcutFocus} onMouseDown={preserveShortcutFocus} + onTouchStart={preserveShortcutFocus} onClick={() => toggleModifier("alt")} aria-pressed={stickyModifier === "alt"} > @@ -1590,7 +1607,9 @@ export function TerminalModal({ isOpen, onClose, initialCommand, initialCommandG