feat: terminal auto-copy on select and right-click paste

This commit is contained in:
Ethanfly 2025-12-29 14:51:42 +08:00
parent 97a1b3d7b0
commit f6511010bd
2 changed files with 48 additions and 20 deletions

View File

@ -292,11 +292,10 @@ function HostManager({ hosts, initialEditHost, onClose, onConnect, onUpdate }) {
{/* 导入导出结果提示 */} {/* 导入导出结果提示 */}
{importExportResult && ( {importExportResult && (
<div className={`mx-6 mt-4 p-3 rounded-lg border ${ <div className={`mx-6 mt-4 p-3 rounded-lg border ${importExportResult.type === 'success'
importExportResult.type === 'success' ? 'bg-shell-success/10 border-shell-success/30 text-shell-success'
? 'bg-shell-success/10 border-shell-success/30 text-shell-success' : 'bg-shell-error/10 border-shell-error/30 text-shell-error'
: 'bg-shell-error/10 border-shell-error/30 text-shell-error' }`}>
}`}>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{importExportResult.type === 'success' ? <FiCheck size={16} /> : <FiX size={16} />} {importExportResult.type === 'success' ? <FiCheck size={16} /> : <FiX size={16} />}
@ -547,11 +546,10 @@ function HostManager({ hosts, initialEditHost, onClose, onConnect, onUpdate }) {
key={color} key={color}
type="button" type="button"
onClick={() => setFormData({ ...formData, color })} onClick={() => setFormData({ ...formData, color })}
className={`w-8 h-8 rounded-lg transition-all ${ className={`w-8 h-8 rounded-lg transition-all ${formData.color === color
formData.color === color ? 'ring-2 ring-offset-2 ring-offset-shell-surface ring-white/50 scale-110'
? 'ring-2 ring-offset-2 ring-offset-shell-surface ring-white/50 scale-110' : 'hover:scale-105'
: 'hover:scale-105' }`}
}`}
style={{ backgroundColor: color }} style={{ backgroundColor: color }}
/> />
))} ))}
@ -577,11 +575,10 @@ function HostManager({ hosts, initialEditHost, onClose, onConnect, onUpdate }) {
{/* 测试结果 */} {/* 测试结果 */}
{testResult && ( {testResult && (
<div <div
className={`p-4 rounded-lg border ${ className={`p-4 rounded-lg border ${testResult.success
testResult.success ? 'bg-shell-success/10 border-shell-success/30 text-shell-success'
? 'bg-shell-success/10 border-shell-success/30 text-shell-success' : 'bg-shell-error/10 border-shell-error/30 text-shell-error'
: 'bg-shell-error/10 border-shell-error/30 text-shell-error' }`}
}`}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{testResult.success ? <FiCheck size={18} /> : <FiX size={18} />} {testResult.success ? <FiCheck size={18} /> : <FiX size={18} />}

View File

@ -18,6 +18,7 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
const initTimerRef = useRef(null); const initTimerRef = useRef(null);
const hasConnectedRef = useRef(false); const hasConnectedRef = useRef(false);
const resizeObserverRef = useRef(null); const resizeObserverRef = useRef(null);
const contextMenuHandlerRef = useRef(null);
const onConnectionChangeRef = useRef(onConnectionChange); const onConnectionChangeRef = useRef(onConnectionChange);
onConnectionChangeRef.current = onConnectionChange; onConnectionChangeRef.current = onConnectionChange;
@ -204,6 +205,30 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
} }
}); });
// 选中自动复制到剪贴板
term.onSelectionChange(() => {
const selection = term.getSelection();
if (selection && selection.length > 0) {
navigator.clipboard.writeText(selection).catch(err => {
console.error('复制到剪贴板失败:', err);
});
}
});
// 右键粘贴
contextMenuHandlerRef.current = async (e) => {
e.preventDefault();
try {
const text = await navigator.clipboard.readText();
if (text && connectionIdRef.current && window.electronAPI) {
window.electronAPI.ssh.write(connectionIdRef.current, text);
}
} catch (err) {
console.error('从剪贴板粘贴失败:', err);
}
};
container.addEventListener('contextmenu', contextMenuHandlerRef.current);
resizeObserverRef.current = new ResizeObserver(() => { resizeObserverRef.current = new ResizeObserver(() => {
fitTerminal(); fitTerminal();
}); });
@ -248,6 +273,12 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
resizeObserverRef.current = null; resizeObserverRef.current = null;
} }
// 清理右键菜单事件监听器
if (contextMenuHandlerRef.current && terminalRef.current) {
terminalRef.current.removeEventListener('contextmenu', contextMenuHandlerRef.current);
contextMenuHandlerRef.current = null;
}
if (cleanupListenersRef.current) { if (cleanupListenersRef.current) {
cleanupListenersRef.current(); cleanupListenersRef.current();
cleanupListenersRef.current = null; cleanupListenersRef.current = null;