Keyboard shortcuts on Linux pass through multiple translation layers—from hardware scancodes and XKB/Wayland compositors, to terminal emulators (such as Kitty or Chrome's hterm / Secure Shell), down to terminal multiplexers (tmux) and TUI applications.
Traditional Unix terminals communicate keystrokes over a pseudo-terminal (PTY) byte stream using ASCII and C0 control characters (0x00–0x1F). Because legacy control characters collapse several distinct physical keys into the same byte—for example, Tab and Ctrl+I both produce 0x09 (\t), while Enter and Ctrl+M both produce 0x0D (\r)—combinations like Ctrl+Tab or Ctrl+Shift+Tab have no standard ASCII control code.
To disambiguate modified keys without breaking legacy PTY compatibility, modern terminal emulators emit Control Sequence Introducer (CSI) sequences (such as xterm's modifyOtherKeys or the Kitty keyboard protocol):
Ctrl+Tab: \x1b[1;5I (or \x1b[27;5;9~)Ctrl+Backspace: \x17 (^W, word erase) or \x08 (^H)In kitty.conf, arbitrary byte sequences can be emitted for any shortcut using send_text:
map ctrl+tab send_text all \x1b[1;5I
map ctrl+backspace send_text all \x17
nassh / hterm)Chrome's Secure Shell extension (iodihamcpbpeioajjeobimgagajmlibd) uses the hterm JavaScript terminal emulator.
Ctrl+Tab Fails by Default in htermIn hterm's built-in keymap (hterm_keyboard_keymap.js), pressing Tab (keyCode 9) with Ctrl invokes onCtrlTab_:
pass-ctrl-tab preference ("Ctrl+Tab switch tab behavior") is true, hterm returns PASS, letting Chrome switch browser tabs.pass-ctrl-tab is false (the default), hterm returns STRIP, which strips the Ctrl modifier and sends a plain \t (0x09) to the remote host.As a result, remote applications like tmux only receive a standard Tab character unless overridden via hterm's custom keybindings preference.
nassh_preferences_editor.htmlIn Secure Shell's Options (chrome-extension://iodihamcpbpeioajjeobimgagajmlibd/html/nassh_preferences_editor.html) under Terminal Settings → Keyboard → Keyboard bindings/shortcuts (keybindings), map Ctrl+Tab to emit \x1b[1;5I:
{
"Ctrl+Tab": "'\u001b[1;5I'"
}
Two details are essential when configuring hterm keybindings:
hterm first parses the preference as JSON (which decodes \u001b into the literal ESC byte 0x1b), and then passes the resulting string value ('‹ESC›[1;5I') to hterm.Parser.parseKeyAction(). String actions in hterm must be enclosed in nested single or double quotes ('...' emits the enclosed characters literally).Ctrl+Tab, Ctrl+W, Ctrl+T, Ctrl+N) when running inside a standard browser tab (crbug.com/671774). Secure Shell must run in a dedicated standalone window (its default mode when launched from the extension popup, or via ?openas=window) for hterm to receive Ctrl+Tab.display-popup Trapsuser-keysWhen a terminal emulator emits a raw CSI sequence like \e[1;5I for Ctrl+Tab, tmux can register that sequence as a custom User0 key and bind it directly in ~/.tmux.conf:
set -s user-keys[0] "\e[1;5I"
bind-key -n User0 display-popup -E -w 95% -h 40% "tmux-window-popup.sh"
PATH Trap in display-popup -E)A common trap when binding a key to tmux display-popup -E "<command>" is that the popup frame flashes briefly and immediately closes.
-E flag instructs tmux to close the popup automatically as soon as the command exits (regardless of exit code). Unlike interactive panes—which launch default-command (such as fish) and source interactive shell configurations—tmux executes display-popup and run-shell commands via non-interactive /bin/sh using the tmux server's global PATH. If a tool used by the popup script (such as fzf installed in ~/.fzf/bin or via Nix Package Manager in ~/.nix-profile/bin) is only added to PATH in interactive shell startup files (~/.bashrc or Fish's conf.d/), the command fails with command not found in milliseconds and display-popup -E immediately closes the popup.~/.tmux.conf (tmux set-environment -g PATH ...) and the popup script itself explicitly prepend user binary directories ($HOME/.nix-profile/bin, $HOME/.fzf/bin, $HOME/.local/bin) to PATH.