What happens
Select some output with the mouse, press Ctrl+C. The selection is not copied — xterm encodes it as ETX and the daemon forwards it to the pty, so the running program takes an interrupt instead.
On macOS this is invisible: Cmd+C carries no ctrlKey, xterm's encoder ignores it, and the browser's own copy runs. On Linux and Windows there is no second chord to fall back to.
Ctrl+Shift+C is not claimed by anything either — xterm's encoder produces no key for it, so nothing calls preventDefault and Chrome opens the DevTools inspector.
Why
evaluateKeyboardEvent in xterm.js has no notion of a selection: Ctrl+C is a control code and that is the whole rule. Native terminals resolve it in their own key handling (iTerm2 and GNOME Terminal copy when there is a selection, or bind Ctrl+Shift+C), and xterm.js leaves that to the embedder — attachCustomKeyEventHandler is the documented seam for it.
Shape of a fix
web/src/emulator/xterm.ts:98 already holds a custom key handler (it is what Shift+Enter goes through). The same handler can return false for Ctrl/Cmd+C when term.hasSelection(), which stands aside and lets the browser copy, and claim Ctrl+Shift+C for copy so the DevTools chord stops leaking through.
The judgement call worth making deliberately rather than by default: whether an empty selection still sends SIGINT (it must — Ctrl+C is how anybody stops a program) and whether copying should clear the selection afterwards, as most terminals do.
Also worth deciding
Paste. Ctrl+V works today, because the browser's paste event reaches xterm's helper textarea. Ctrl+Shift+V does nothing, which is the chord half of the users typing Ctrl+Shift+C will reach for next.
What happens
Select some output with the mouse, press Ctrl+C. The selection is not copied — xterm encodes it as ETX and the daemon forwards it to the pty, so the running program takes an interrupt instead.
On macOS this is invisible: Cmd+C carries no
ctrlKey, xterm's encoder ignores it, and the browser's own copy runs. On Linux and Windows there is no second chord to fall back to.Ctrl+Shift+C is not claimed by anything either — xterm's encoder produces no key for it, so nothing calls
preventDefaultand Chrome opens the DevTools inspector.Why
evaluateKeyboardEventin xterm.js has no notion of a selection: Ctrl+C is a control code and that is the whole rule. Native terminals resolve it in their own key handling (iTerm2 and GNOME Terminal copy when there is a selection, or bind Ctrl+Shift+C), and xterm.js leaves that to the embedder —attachCustomKeyEventHandleris the documented seam for it.Shape of a fix
web/src/emulator/xterm.ts:98already holds a custom key handler (it is what Shift+Enter goes through). The same handler can returnfalsefor Ctrl/Cmd+C whenterm.hasSelection(), which stands aside and lets the browser copy, and claim Ctrl+Shift+C for copy so the DevTools chord stops leaking through.The judgement call worth making deliberately rather than by default: whether an empty selection still sends SIGINT (it must — Ctrl+C is how anybody stops a program) and whether copying should clear the selection afterwards, as most terminals do.
Also worth deciding
Paste. Ctrl+V works today, because the browser's paste event reaches xterm's helper textarea. Ctrl+Shift+V does nothing, which is the chord half of the users typing Ctrl+Shift+C will reach for next.