diff --git a/frontend/src/components/server/TerminalDialog.tsx b/frontend/src/components/server/TerminalDialog.tsx index 87ef4bb..b0b377d 100644 --- a/frontend/src/components/server/TerminalDialog.tsx +++ b/frontend/src/components/server/TerminalDialog.tsx @@ -132,8 +132,12 @@ export function TerminalDialog({ const ws = new WebSocket(wsUrl); wsRef.current = ws; - // Escape 由 Dialog 捕获后直接转发,xterm 跳过同一次事件以免重复发送。 // Logan.Li - term.attachCustomKeyEventHandler((event) => event.key !== "Escape"); + // xterm 在目标元素阶段直接转发 Escape,避免 Radix 捕获层吞掉 Vim 控制字符。 // Logan.Li + term.attachCustomKeyEventHandler((event) => { + if (event.key !== "Escape") return true; + if (event.type === "keydown") sendTerminalInput("\x1b"); + return false; + }); term.onData(sendTerminalInput); ws.onmessage = (event) => { @@ -221,11 +225,8 @@ export function TerminalDialog({ { - event.preventDefault(); - sendTerminalInput("\x1b"); - }} + // Escape 仅阻止弹框关闭,控制字符由 xterm 键处理器发送。 // Logan.Li + onEscapeKeyDown={(event) => event.preventDefault()} className={cn( "min-w-0 overflow-hidden bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] p-0 gap-0", // 禁用 CSS 过渡:终端窗口应该即时缩放,不需要动画