Problem
Currently, xterm.js treats Shift+Enter identically to Enter (both send \r). Users expect Shift+Enter to insert a newline for multiline command editing — consistent with Claude Code, Warp, Kitty, Ghostty, and other modern terminals.
Current Workaround
Intercept Shift+Enter at the JS level (keybindings.ts) and send \n instead of \r, combined with a zsh ^J rebind in default_init.sh. This works but only handles one key combo and requires shell-side configuration.
Ideal Solution: Kitty Keyboard Protocol
xterm.js v6.1.0-beta.197 already includes a full Kitty keyboard protocol implementation (KittyKeyboard.ts, KeyboardService.ts). Enabling it would:
- Distinguish all modifier+key combinations (Shift+Enter, Ctrl+Enter, etc.)
- Align with Kitty, Ghostty, WezTerm, iTerm2, and other modern terminals
- Eliminate the need for JS-level key interception hacks
What we tried
const term = new XTerm({ vtExtensions: { kittyKeyboard: true } });
printf '\x1b[>1u' # Enable DISAMBIGUATE_ESCAPE_CODES flag
What went wrong
With flag 1, xterm.js encodes Ctrl+C as \x1b[99;5u instead of the legacy \x03. Per the Kitty spec, flag 1 should only re-encode ambiguous keys. Ctrl+C has an unambiguous legacy encoding and should remain \x03. This causes zsh to output raw 9;5u characters.
What needs to happen
- Investigate xterm.js behavior — Determine if this is a bug in xterm.js's Kitty implementation or if shell-side bindkeys are needed for all Ctrl+letter keys
- Shell integration — Add zsh/bash/fish bindings for common CSI u sequences
- Testing — Verify Ctrl+C/Z/D/L and other essential keys still work
- Gradual rollout — Consider making Kitty protocol opt-in via settings initially
Industry Reference
| Terminal |
Shift+Enter approach |
| Kitty/Ghostty |
Kitty protocol (native) |
| VS Code |
F12 proxy sequence (PowerShell only) |
| Warp |
Block editor (UI layer) |
| Hyper/Tabby/ttyd |
Not handled |
| 2code (current) |
JS intercept + zsh ^J rebind |
Problem
Currently, xterm.js treats Shift+Enter identically to Enter (both send
\r). Users expect Shift+Enter to insert a newline for multiline command editing — consistent with Claude Code, Warp, Kitty, Ghostty, and other modern terminals.Current Workaround
Intercept Shift+Enter at the JS level (
keybindings.ts) and send\ninstead of\r, combined with a zsh^Jrebind indefault_init.sh. This works but only handles one key combo and requires shell-side configuration.Ideal Solution: Kitty Keyboard Protocol
xterm.js v6.1.0-beta.197 already includes a full Kitty keyboard protocol implementation (
KittyKeyboard.ts,KeyboardService.ts). Enabling it would:What we tried
What went wrong
With flag 1, xterm.js encodes Ctrl+C as
\x1b[99;5uinstead of the legacy\x03. Per the Kitty spec, flag 1 should only re-encode ambiguous keys. Ctrl+C has an unambiguous legacy encoding and should remain\x03. This causes zsh to output raw9;5ucharacters.What needs to happen
Industry Reference
^Jrebind