Skip to content

Ctrl+C copy doesn't work in TMUX_ENABLED persistent sessions — tmux mouse mode consumes the selection before xterm.js sees it #197

Description

@Leppi83

Summary

The wiki (Terminal and Persistent tmux Sessions) states:

Ctrl+C copies selected text. With no selection, it sends the normal interrupt character to the remote process.

This works as described in a plain (non-tmux) session after #194. It does not work when TMUX_ENABLED=true (the base Compose file's own default) and the remote tmux session has mouse mode on.

Root cause

With tmux's own mouse option on, tmux — not the browser/xterm.js — receives and processes the SGR mouse-drag escape sequences. It performs its own internal copy-mode selection (rendered as inverse-video highlighting that looks identical to a normal xterm.js selection at a glance) and shows its own status message ("Copied N chars to buffer, paste with prefix ]") on mouse-release.

Consequences, confirmed by testing:

  • terminal.hasSelection() / terminal.getSelection() stay empty — tmux consumes the mouse event before xterm.js's own SelectionService ever sees it, so no real xterm selection is ever created.
  • xterm.js's built-in Shift-drag bypass (meant to let local browser selection win over a mouse-tracking-aware app) does not help: holding Shift while dragging still produces tmux's own "copied to buffer" message, not a local xterm selection.
  • Pressing Ctrl+C afterward does nothing — no "Selection copied" nor "Nothing selected to copy" toast appears, because hasSelection() is false, so the code path fixed by Fix terminal selection copying #194 never triggers.

So, under the officially documented and Compose-enabled TMUX_ENABLED=true setup, the wiki's described copy behavior doesn't work via mouse-drag selection at all.

What's actually missing

A different open-source tmux-aware web terminal we also run side-by-side handles this by:

  1. Setting set-clipboard on when it bootstraps its tmux session, so tmux emits an OSC 52 escape sequence on every copy-mode selection.
  2. Implementing an OSC 52 handler client-side that decodes that escape sequence and writes the payload to navigator.clipboard.

WebSSH's tmux bootstrap in app/ssh_manager.py runs a bare tmux new-session/tmux new-session -A, with no set-clipboard option set. static/js/terminal-manager.js and static/js/app.js have no OSC 52 handling at all — grep -rn "osc\|52\b" static/js/ returns no matches.

Question

Is OSC 52 passthrough the intended fix for the TMUX_ENABLED=true case, or is there a different mechanism meant to make Ctrl+C copying work under persistent tmux sessions? Happy to test a patch if there's a preferred direction (e.g. set-clipboard on in the tmux bootstrap command plus an OSC 52 handler registered on the xterm.js Terminal instance).

Environment

  • ghcr.io/bifrost0x/webssh:latest, digest matching the Fix terminal selection copying #194 build (2026-09-03)
  • TMUX_ENABLED=true, TMUX_DEFAULT=true (base Compose file defaults)
  • Reproduced with both a plain drag and a Shift-held drag

Related: #193 / #194 (fixed the separate non-tmux selection/copy path).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinggui

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions