Compare commits

...
Author SHA1 Message Date
陈大猫 f5543c6550 fix(terminal): do not restore pane zoom on Escape 2026-11-07 09:24:51 +08:00
7 changed files with 30 additions and 47 deletions

No files matched your search

+19 -20
View File
@@ -377,7 +377,7 @@ test('move-focus shortcut cannot send input behind a magnified pane', () => {
assert.equal(moveCalls, 0);
});
test('Escape restores magnification after transient dialogs are closed', () => {
test('Escape leaves magnification unchanged and reaches the terminal', () => {
let restores = 0;
let prevented = false;
let stopped = false;
@@ -405,30 +405,29 @@ test('Escape restores magnification after transient dialogs are closed', () => {
},
}), event);
assert.equal(restores, 1);
assert.equal(prevented, true);
assert.equal(stopped, true);
assert.equal(restores, 0);
assert.equal(prevented, false);
assert.equal(stopped, false);
});
test('consumed Escape does not restore magnification', () => {
let restores = 0;
test('Escape closes the quick switcher', () => {
let open = true;
handleEscapeKeyDownImpl(() => ({
isQuickSwitcherOpen: false,
setIsQuickSwitcherOpen: () => {},
terminalPaneMagnificationRef: {
current: {
getState: () => 'focused',
focus: () => false,
restore: () => {
restores += 1;
return true;
},
toggle: () => false,
},
},
isQuickSwitcherOpen: open,
setIsQuickSwitcherOpen: (value: boolean) => { open = value; },
}), { key: 'Escape', defaultPrevented: false } as KeyboardEvent);
assert.equal(open, false);
});
test('consumed Escape leaves the quick switcher open', () => {
let open = true;
handleEscapeKeyDownImpl(() => ({
isQuickSwitcherOpen: open,
setIsQuickSwitcherOpen: (value: boolean) => { open = value; },
}), { key: 'Escape', defaultPrevented: true } as KeyboardEvent);
assert.equal(restores, 0);
assert.equal(open, true);
});
test('close tab hotkey routes native plugin view tabs through their owner', () => {
-9
View File
@@ -365,8 +365,6 @@ export function handleEscapeKeyDownImpl(getCtx: AppContextGetter, e: KeyboardEve
const {
isQuickSwitcherOpen,
setIsQuickSwitcherOpen,
sftpPaneMagnificationRef,
terminalPaneMagnificationRef,
} = getCtx();
{
if (e.key !== 'Escape' || e.defaultPrevented) return;
@@ -374,13 +372,6 @@ export function handleEscapeKeyDownImpl(getCtx: AppContextGetter, e: KeyboardEve
setIsQuickSwitcherOpen(false);
return;
}
if (getAvailablePaneMagnificationController([
sftpPaneMagnificationRef?.current,
terminalPaneMagnificationRef?.current,
])?.restore()) {
e.preventDefault();
e.stopPropagation();
}
}
}
@@ -4,12 +4,13 @@ import test from 'node:test';
const source = readFileSync(new URL('./AppSideEffects.tsx', import.meta.url), 'utf8');
test('terminal Escape restoration runs before xterm can stop propagation', () => {
const effectStart = source.indexOf("const onCaptureKeyDown = (e: KeyboardEvent) => {");
const effectSource = source.slice(effectStart, effectStart + 900);
test('quick-switcher Escape handling stays in the bubble phase', () => {
const effectStart = source.indexOf('const onKeyDown = (e: KeyboardEvent) => {\n _handleEscapeKeyDown(e);');
const effectEnd = source.indexOf('}, [appLockLocked]);', effectStart);
const effectSource = source.slice(effectStart, effectEnd);
assert.notEqual(effectStart, -1);
assert.match(effectSource, /target\.closest\('\.xterm'\)/);
assert.match(effectSource, /window\.addEventListener\('keydown', onCaptureKeyDown, true\)/);
assert.match(effectSource, /window\.removeEventListener\('keydown', onCaptureKeyDown, true\)/);
assert.match(effectSource, /window\.addEventListener\('keydown', onKeyDown\)/);
assert.match(effectSource, /window\.removeEventListener\('keydown', onKeyDown\)/);
assert.doesNotMatch(source, /onCaptureKeyDown/);
});
+1 -9
View File
@@ -613,7 +613,7 @@ export function AppSideEffects() {
const _handleTrayPanelConnect = useEffectEvent((hostId: string) => { return handleTrayPanelConnectImpl(() => ({ addConnectionLog, connectToHost, hostId, hosts, identities, keys, resolveEffectiveHost, resolveHostAuth, systemInfoRef, t, toast }), hostId); });
const _handleTrayPanelConnectRequest = useEffectEvent((hostId: string) => { return handleTrayPanelConnectRequestImpl(() => ({ connectNow: _handleTrayPanelConnect, hostId, isVaultInitialized, queueConnect: (queuedHostId: string) => setPendingTrayPanelConnectHostIds((prev) => [...prev, queuedHostId]) }), hostId); });
const _handleGlobalHotkeyKeyDown = useEffectEvent((e: KeyboardEvent) => { return handleGlobalHotkeyKeyDownImpl(() => ({ HOTKEY_DEBUG, closeTabKeyStr, e, executeHotkeyAction, hotkeyScheme, keyBindings, matchesKeyBinding }), e); });
const _handleEscapeKeyDown = useEffectEvent((e: KeyboardEvent) => { return handleEscapeKeyDownImpl(() => ({ e, isQuickSwitcherOpen, setIsQuickSwitcherOpen, sftpPaneMagnificationRef, terminalPaneMagnificationRef }), e); });
const _handleEscapeKeyDown = useEffectEvent((e: KeyboardEvent) => { return handleEscapeKeyDownImpl(() => ({ e, isQuickSwitcherOpen, setIsQuickSwitcherOpen }), e); });
// Vault hosts for tray / auto-start; terminalHosts (vault + ephemeral) only for
// dedicated transfer resume so quick-connect rows do not break tray connect.
@@ -1233,19 +1233,11 @@ export function AppSideEffects() {
useEffect(() => {
if (appLockLocked) return;
const onCaptureKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Escape') return;
const target = e.target;
if (!(target instanceof HTMLElement) || !target.closest('.xterm')) return;
_handleEscapeKeyDown(e);
};
const onKeyDown = (e: KeyboardEvent) => {
_handleEscapeKeyDown(e);
};
window.addEventListener('keydown', onCaptureKeyDown, true);
window.addEventListener('keydown', onKeyDown);
return () => {
window.removeEventListener('keydown', onCaptureKeyDown, true);
window.removeEventListener('keydown', onKeyDown);
};
}, [appLockLocked]);
+1 -1
View File
@@ -759,7 +759,7 @@ const SftpViewInner: React.FC<SftpViewProps> = ({
data-section="pane-magnification-hint"
>
{t('terminal.paneMagnification.hint')}: {t('terminal.layer.sftp')}
{paneMagnificationShortcutLabel ? ` · ${paneMagnificationShortcutLabel} / Esc` : ' · Esc'}
{paneMagnificationShortcutLabel ? ` · ${paneMagnificationShortcutLabel}` : ''}
</div>
)}
</div>
@@ -1577,7 +1577,7 @@ function TerminalLayerSidePanelInner({ ctx, pluginSidebar }: { ctx: SidePanelCon
data-section="pane-magnification-hint"
>
{t('terminal.paneMagnification.hint')}: {sidePanelToolLabels.get(magnifiedSidePane.tool) ?? magnifiedSidePane.tool}
{paneMagnificationShortcutLabel ? ` · ${paneMagnificationShortcutLabel} / Esc` : ' · Esc'}
{paneMagnificationShortcutLabel ? ` · ${paneMagnificationShortcutLabel}` : ''}
</div>
)}
</div>,
@@ -340,7 +340,7 @@ function TerminalLayerWorkspaceSectionInner({ ctx }: { ctx: WorkspaceContext })
aria-label={t('terminal.paneMagnification.restore')}
>
{t('terminal.paneMagnification.hint')}: {t('terminal.layer.terminal')}
{paneMagnificationShortcutLabel ? ` · ${paneMagnificationShortcutLabel} / Esc` : ' · Esc'}
{paneMagnificationShortcutLabel ? ` · ${paneMagnificationShortcutLabel}` : ''}
</button>
)}
</>,