}
document.getElementById('btn-paste').onclick = openPasteModal;
+ // ESC 关闭 modal(监听 document,避免焦点不在 pasteInput 时失效)
+ document.addEventListener('keydown', (e) => {
+ if (e.key === 'Escape' && pasteModal.style.display === 'flex') {
+ e.preventDefault();
+ closePasteModal();
+ }
+ });
+ // 点击遮罩层(modal 外部)关闭
+ pasteModal.addEventListener('click', (e) => {
+ if (e.target === pasteModal) closePasteModal();
+ });
+
// textarea 的 paste 事件:文字直接插入,图片上传后加 chip
pasteInput.addEventListener('paste', async (e) => {
if (!e.clipboardData) return;
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
sendPasteContent();
- } else if (e.key === 'Escape') {
- e.preventDefault();
- closePasteModal();
}
+ // ESC 关闭由 document 级监听器统一处理
});
function initTerminal() {
term.open(termContainer);
fitAddon.fit();
+ // 复制支持:有选区时 Ctrl+C 复制到剪贴板(不发中断信号)
+ // Ctrl+Shift+C 也复制(xterm 默认行为)
+ term.attachCustomKeyEventHandler((e) => {
+ // 复制:Ctrl+C 且有选区
+ if (e.type === 'keydown' && e.ctrlKey && !e.shiftKey && !e.altKey && e.key === 'c') {
+ const sel = term.getSelection();
+ if (sel) {
+ // 写入剪贴板
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(sel).catch(() => {});
+ } else {
+ // HTTP 下 navigator.clipboard 可能不可用,用临时 textarea 兜底
+ const ta = document.createElement('textarea');
+ ta.value = sel; ta.style.position = 'fixed'; ta.style.opacity = '0';
+ document.body.appendChild(ta); ta.select();
+ try { document.execCommand('copy'); } catch(_) {}
+ document.body.removeChild(ta);
+ }
+ return false; // 不传给终端
+ }
+ }
+ return true;
+ });
+
term.onData(data => sendInput(data));
term.onResize(({ cols, rows }) => {
if (ws && ws.readyState === WebSocket.OPEN && pid) ws.send(JSON.stringify({ type: 'resize', cols, rows }));