diff --git a/src/App.js b/src/App.js index 9f69e37..c0e75cc 100644 --- a/src/App.js +++ b/src/App.js @@ -371,6 +371,7 @@ function App() { onToggleInfoPanel={() => setShowInfoPanel(!showInfoPanel)} onOpenSFTP={() => setShowSFTP(true)} showInfoPanel={showInfoPanel} + onCloseTab={() => closeTab(tab.id)} /> )) diff --git a/src/components/Terminal.js b/src/components/Terminal.js index 8c87ab4..9ec11aa 100644 --- a/src/components/Terminal.js +++ b/src/components/Terminal.js @@ -7,7 +7,7 @@ import { WebglAddon } from '@xterm/addon-webgl'; import '@xterm/xterm/css/xterm.css'; import { FiCommand, FiRefreshCw, FiInfo, FiFolder, FiActivity, FiZap } from 'react-icons/fi'; -function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onToggleInfoPanel, onOpenSFTP, showInfoPanel }) { +function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onToggleInfoPanel, onOpenSFTP, showInfoPanel, onCloseTab }) { const containerRef = useRef(null); const terminalRef = useRef(null); const xtermRef = useRef(null); @@ -26,6 +26,12 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT const onConnectionChangeRef = useRef(onConnectionChange); onConnectionChangeRef.current = onConnectionChange; + const onCloseTabRef = useRef(onCloseTab); + onCloseTabRef.current = onCloseTab; + + const onShowCommandPaletteRef = useRef(onShowCommandPalette); + onShowCommandPaletteRef.current = onShowCommandPalette; + const [connectionId, setConnectionId] = useState(null); const [isConnecting, setIsConnecting] = useState(false); const [error, setError] = useState(null); @@ -225,6 +231,27 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT } }); + // 自定义按键处理 - 拦截 Ctrl+W 和 Ctrl+K + term.attachCustomKeyEventHandler((e) => { + // Ctrl+W: 关闭当前标签页 + if ((e.ctrlKey || e.metaKey) && e.key === 'w') { + e.preventDefault(); + if (onCloseTabRef.current) { + onCloseTabRef.current(); + } + return false; // 阻止 xterm 处理 + } + // Ctrl+K: 打开命令面板 + if ((e.ctrlKey || e.metaKey) && e.key === 'k') { + e.preventDefault(); + if (onShowCommandPaletteRef.current) { + onShowCommandPaletteRef.current(); + } + return false; + } + return true; // 允许 xterm 处理其他按键 + }); + // 选中自动复制到剪贴板 term.onSelectionChange(() => { const selection = term.getSelection();