#11512·tabby

Alt+Left / Alt+Right sends Ctrl+arrow escape sequences instead of Alt (meta) sequences

Author: bptrsnCreated Jul 24, 2026Updated Sep 14, 2026
LabelsT: Bug

Alt+Left / Alt+Right sends Ctrl+arrow escape sequences instead of Alt (meta) sequences

Version: 1.0.235 Platform: Windows x64 [Version 10.0.26200.8875] Frontend: xterm-webgl

Summary

Pressing Alt+Right (or Alt+Left) in a terminal application sends the escape sequence for Ctrl+Right (ESC [1;5C) instead of the Alt-modified sequence (ESC [1;3C). As a consequence, applications cannot distinguish Alt+arrow from Ctrl+arrow at all, and any Alt+arrow keybinding in a TUI is unreachable. For example, WeeChat's default Alt+arrow buffer-switching doesn't work; the only workaround is pressing Esc followed by the arrow key as two separate keystrokes, which correctly produces a meta-arrow.

Steps to reproduce

  1. Open a terminal (observed over SSH; the transport shouldn't matter).
  2. Run WeeChat and enter /input grab_key (or use cat -v / showkey -a in a shell).
  3. Press Alt+Right.

Expected: the application receives ESC [1;3C (modifier 3 = Alt), which WeeChat reports as meta-right — the same thing it reports for the Esc, Right two-keystroke sequence.

Actual: the application receives ESC [1;5C (modifier 5 = Ctrl); WeeChat reports ctrl-right. Alt+Left likewise produces ESC [1;5D / ctrl-left.

Root cause

This is a deliberate remapping inside the xterm.js version Tabby ships. tabby-terminal/package.json depends on @xterm/xterm ^5.4.0, which resolves to 5.5.0. In that release, src/common/input/Keyboard.ts (evaluateKeyboardEvent) contains:

case 39:
  // right-arrow
  ...
  if (modifiers) {
    result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C';
    // HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
    // http://unix.stackexchange.com/a/108106
    // macOS uses different escape sequences than linux
    if (result.key === C0.ESC + '[1;3C') {
      result.key = C0.ESC + (isMac ? 'f' : '[1;5C');
    }
  }

i.e. whenever the computed sequence is exactly the Alt+arrow one (1;3C / 1;3D), it is silently rewritten to the Ctrl+arrow sequence on non-macOS (and to ESC f / ESC b on macOS). The Alt-modified arrow sequences are therefore impossible to produce from the keyboard.

Tabby's own key handling doesn't compensate. In tabby-terminal/src/frontends/xtermFrontend.ts, keyboardEventHandler deliberately passes single-modifier arrow keys straight through to xterm when the alternate screen is active (so full-screen apps receive them instead of Tabby hotkeys) — which is the right idea, but xterm then mangles the sequence as above. There is also no setting that helps on Windows: the "Alt is Meta" option maps to xterm's macOptionIsMeta, which only affects macOS.

Upstream status

xterm.js has removed this hack on their side: PR xtermjs/xterm.js#5346 "Remove alt -> ctrl+arrow hack in favor of embedder-specific solutions", shipped in xterm.js 6.0.0 (confirmed absent from the 6.0.0 tag's Keyboard.ts; see also the long-standing report xtermjs/xterm.js#239 "Wrong sequence on alt + arrow"). The stated direction is that word-jump conveniences should be implemented by the embedding application, not by falsifying escape sequences.

Suggested fix

  • Upgrading to @xterm/xterm 6.x fixes this outright. Tabby is well positioned for the "embedder-specific solution" xterm.js asks for, since it already has configurable previous-word / next-word hotkeys (tabby-terminal/src/api/baseTerminalTab.component.ts) that send word-jump sequences — anyone who wants the old Alt+arrow word-jump behavior can simply bind those hotkeys to Alt+Left/Alt+Right.
  • If the 6.x upgrade is a larger undertaking, an interim fix could intercept Alt+arrow in attachCustomKeyEventHandler and send the correct ESC [1;3C / ESC [1;3D sequences directly, bypassing xterm's remapping.

Happy to test a build or provide additional key-sequence dumps if useful.

Generated with Claude.