Skip to content

Make native OS shortcuts (Cmd+C/V/X etc.) work across different terminal emulators #40

@jamescrosswell

Description

@jamescrosswell

Problem

Modifier-based shortcuts like Cmd+C, Cmd+V, Cmd+X are intercepted by the terminal emulator at the application layer (on macOS, by Cocoa) before they ever reach the TUI. The Kitty keyboard protocol — which TuiCode already enables — does not rescue this case, because the keystroke is consumed by the terminal app before the protocol gets a chance to encode and forward it.

There is no programmatic way for a TUI to "claim" these keys. The only fix is per-terminal user configuration that tells the terminal to forward the keystroke as an escape sequence instead of handling it natively.

This umbrella issue tracks the work to make that setup as painless as possible for every popular terminal emulator. #39 is the sub-issue for iTerm2.

Approach

  1. Pick a single canonical escape sequence that the app listens for as "copy" / "paste" / "cut" etc. A CSI u sequence with the Super modifier is a good fit since it's what the Kitty keyboard protocol would have produced anyway — the app's existing key handler likely already understands it.
    • Copy: ESC [ 99 ; 9 u (Cmd+c)
    • Paste: ESC [ 118 ; 9 u (Cmd+v)
    • Cut: ESC [ 120 ; 9 u (Cmd+x)
  2. Ship per-terminal config snippets / dynamic profiles that bind the OS shortcut to that escape sequence.
  3. Detect the terminal via $TERM_PROGRAM / $TERM on first run (or via a tuicode doctor command) and point the user at the right snippet — ideally with a one-click import where the terminal supports it.
  4. Handle the OSC 52 round-trip in the app: when the canonical "copy" sequence arrives, take the in-app selection and emit OSC 52 to put it on the system clipboard. (OSC 52 is broadly supported across all the terminals below.)
  5. Document the fallback: in iTerm2 and similar, Option+drag (or terminal-specific bypass) still gives users native selection when mouse reporting is on, for cases where the keybind hasn't been configured yet.

Per-terminal sub-issues

Terminal Mechanism Sub-issue
iTerm2 Dynamic Profile dropped into ~/Library/Application Support/iTerm2/DynamicProfiles/ with per-app automatic profile switching and key mapping #39
WezTerm Lua module (tuicode.lua) defining a tuicode key table + user-var-changed event handler; activated by OSC 1337 user-var emitted by the app on startup/exit #49
Windows Terminal Remove or remap the default Ctrl+C binding in settings.json TBD
Alacritty key_bindings in alacritty.toml with chars = "\x1b[99;9u" TBD
Kitty map cmd+c send_text all \x1b[99;9u in kitty.conf TBD
Ghostty keybind = cmd+c=text:\x1b[99;9u in config TBD
Terminal.app (macOS) No user-facing remap UI for Cmd+C; likely document as unsupported and recommend a different terminal TBD
foot / others TBD as users request TBD

Notes

  • The Kitty keyboard protocol stays enabled regardless — it already handles every terminal that does forward Cmd+C natively, and it's what makes the canonical CSI u sequence above a natural choice.
  • Clipboard write from the app uses OSC 52, which works across all the terminals in the table above (and tmux with set -g set-clipboard on).
  • Bracketed paste mode handles the paste-data side regardless of how the paste was triggered.

Out of scope

  • Trying to programmatically disable terminal-level Cmd handling. Not possible.
  • Building a custom terminal emulator.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions