mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 23:19:43 +02:00
fix(cjk): forward Ctrl/Alt-modified navigation keys to the CLI
claude advertises "Jump to bottom (ctrl+End)", so that chord has to actually
reach it. But PASSTHROUGH_KEYS carried only the bare forms (End -> \x1b[F) and
CTRL_KEYS held just six letters (c/d/l/z/a/e), which cannot express End. Ctrl+End
therefore failed in both directions:
- with an empty composer it went out as a bare \x1b[F, the modifier silently
dropped, so the CLI received a plain End;
- with text in the composer the forwarding branch requires empty, so nothing was
forwarded and the browser default applied — the caret jumped to the end of the
draft, which is the "the shortcut now edits my input box" the user saw.
Encode them as CSI 1;<mod><final> instead, and forward Ctrl/Alt-modified
navigation keys whether or not the composer is empty: they are commands for the
CLI, and the composer has no editing semantics for them worth preserving (bare
Home/End still use the old table and edit locally).
⚠️ Bare Shift is deliberately excluded: Shift+arrow selects text in the composer,
a real editing gesture that must stay local. Shift held together with Ctrl/Alt is
still encoded into the modifier mask.
This commit is contained in:
@@ -120,6 +120,41 @@ const CjkInput = (() => {
|
||||
c: '\x03', d: '\x04', l: '\x0c', z: '\x1a', a: '\x01', e: '\x05',
|
||||
};
|
||||
|
||||
/** CSI final byte per navigation key, for the modifier-carrying forms below. */
|
||||
const CSI_NAV_FINAL = {
|
||||
ArrowUp: 'A',
|
||||
ArrowDown: 'B',
|
||||
ArrowRight: 'C',
|
||||
ArrowLeft: 'D',
|
||||
End: 'F',
|
||||
Home: 'H',
|
||||
};
|
||||
|
||||
/**
|
||||
* The `CSI 1 ; <mod> <final>` form for a Ctrl/Alt-modified navigation key, or
|
||||
* null when this key is not one.
|
||||
*
|
||||
* A modified navigation key is a terminal COMMAND, not text editing — claude's
|
||||
* own "Jump to bottom (ctrl+End)" is one. PASSTHROUGH_KEYS carries only the
|
||||
* plain forms, so Ctrl+End used to fail in BOTH directions: with an empty
|
||||
* field it was sent as a bare `\x1b[F` (the modifier silently dropped, so the
|
||||
* CLI saw a plain End), and with any text in the field it was not forwarded at
|
||||
* all and the browser's default moved the caret to the end of the composer,
|
||||
* which is what the user sees as "the shortcut does something to the input box
|
||||
* instead".
|
||||
*
|
||||
* ⚠️ Shift ALONE is deliberately excluded: Shift+arrow selects text inside the
|
||||
* composer, which is a real editing gesture worth keeping local. Shift is still
|
||||
* encoded when it accompanies Ctrl or Alt.
|
||||
*/
|
||||
function _modifiedNavSequence(e) {
|
||||
const final = CSI_NAV_FINAL[e.key];
|
||||
if (!final) return null;
|
||||
if (!e.ctrlKey && !e.altKey) return null;
|
||||
const mod = 1 + (e.shiftKey ? 1 : 0) + (e.altKey ? 2 : 0) + (e.ctrlKey ? 4 : 0);
|
||||
return `\x1b[1;${mod}${final}`;
|
||||
}
|
||||
|
||||
function _strip(str) {
|
||||
return str.replace(//g, '');
|
||||
}
|
||||
@@ -321,6 +356,17 @@ const CjkInput = (() => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Alt-modified navigation keys go to the PTY REGARDLESS of whether
|
||||
// the field has text: they are commands for the CLI, and the composer has
|
||||
// no editing behaviour for them worth preserving (plain Home/End still
|
||||
// edit locally through the table below).
|
||||
const modNav = _modifiedNavSequence(e);
|
||||
if (modNav) {
|
||||
e.preventDefault();
|
||||
_send(modNav);
|
||||
return;
|
||||
}
|
||||
|
||||
// Arrow/function keys: forward to PTY when no real text
|
||||
if (PASSTHROUGH_KEYS[e.key] && _isEffectivelyEmpty()) {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user