diff --git a/public/index.html b/public/index.html
index 3f82dee..7964e5e 100644
--- a/public/index.html
+++ b/public/index.html
@@ -18179,8 +18179,20 @@
⌨️ Keyboard Shortcuts
// browser restoring focus after an alt-tab — leaves the pane visually active but
// deaf. A click on it is an unambiguous "I am typing here"; don't steal focus back
// when the user is dragging out a selection.
+ //
+ // Copy-on-select rides the same mouseup. xterm has no built-in option for it
+ // (that was an xterm v4 option, removed upstream), and a right-click can't
+ // fall back to the browser's native "Copy" because xterm clears the selection
+ // on the right mousedown before the context menu opens. It is NOT wired to
+ // `term.onSelectionChange`: that fires from the selection service's refresh on
+ // every animation frame while the mouse is still dragging, which is a
+ // clipboard write per frame — and over plain http `copyText()` falls back to a
+ // focused off-screen textarea, so it would also steal focus mid-drag.
host.addEventListener('mouseup', () => {
- if (term.hasSelection && term.hasSelection()) return;
+ if (term.hasSelection && term.hasSelection()) {
+ copyText(term.getSelection()).catch(() => {});
+ return;
+ }
try { term.focus(); } catch {}
});
_connectTerminalWs(sessionId);
diff --git a/test/composer-terminal.test.js b/test/composer-terminal.test.js
index d774711..efa6877 100644
--- a/test/composer-terminal.test.js
+++ b/test/composer-terminal.test.js
@@ -203,8 +203,13 @@ check('a reconnect refocuses the pane',
/ws\.onopen = \(\) => \{[\s\S]{0,700}?requestAnimationFrame\(\(\) => \{ try \{ term\.focus\(\); \} catch \{\} \}\);/.test(TB), true);
check('clicking the pane refocuses it',
/host\.addEventListener\('mouseup'[\s\S]{0,260}?term\.focus\(\)/.test(TB), true);
-check('but not while a selection is being dragged out',
- /host\.addEventListener\('mouseup'[\s\S]{0,160}?if \(term\.hasSelection && term\.hasSelection\(\)\) return;/.test(TB), true);
+check('but not while a selection is being dragged out — that mouseup copies the selection instead',
+ /host\.addEventListener\('mouseup'[\s\S]{0,160}?if \(term\.hasSelection && term\.hasSelection\(\)\) \{\s*copyText\(term\.getSelection\(\)\)[^\n]*\n\s*return;/.test(TB), true);
+// xterm fires onSelectionChange from the selection service's refresh on every
+// animation frame while the mouse is still dragging — a clipboard write per frame,
+// and over plain http copyText()'s textarea fallback steals focus mid-drag.
+check('copy-on-select is not wired to term.onSelectionChange',
+ /term\.onSelectionChange\(/.test(TB), false);
console.log('\n— i18n: the three new keys exist in all five locales —');