対話入力時Ctrl+Cが聞くように。
This commit is contained in:
parent
69eb9e8d3d
commit
c5b3f992db
@ -548,6 +548,18 @@ describe('interactiveMode', () => {
|
||||
expect(result.action).toBe('cancel');
|
||||
});
|
||||
|
||||
it('should handle Ctrl+C (Kitty CSI-u) to cancel input', async () => {
|
||||
// Given: Ctrl+C reported as Kitty keyboard protocol sequence
|
||||
setupRawStdin(['\x1B[99;5u']);
|
||||
setupMockProvider([]);
|
||||
|
||||
// When
|
||||
const result = await interactiveMode('/project');
|
||||
|
||||
// Then: should cancel
|
||||
expect(result.action).toBe('cancel');
|
||||
});
|
||||
|
||||
it('should handle Ctrl+D to cancel input', async () => {
|
||||
// Given: Ctrl+D during input
|
||||
setupRawStdin(['\x04']);
|
||||
@ -560,6 +572,42 @@ describe('interactiveMode', () => {
|
||||
expect(result.action).toBe('cancel');
|
||||
});
|
||||
|
||||
it('should handle Ctrl+D (Kitty CSI-u) to cancel input', async () => {
|
||||
// Given: Ctrl+D reported as Kitty keyboard protocol sequence
|
||||
setupRawStdin(['\x1B[100;5u']);
|
||||
setupMockProvider([]);
|
||||
|
||||
// When
|
||||
const result = await interactiveMode('/project');
|
||||
|
||||
// Then: should cancel
|
||||
expect(result.action).toBe('cancel');
|
||||
});
|
||||
|
||||
it('should handle Ctrl+C (xterm modifyOtherKeys) to cancel input', async () => {
|
||||
// Given: Ctrl+C reported as xterm modifyOtherKeys sequence
|
||||
setupRawStdin(['\x1B[27;5;99~']);
|
||||
setupMockProvider([]);
|
||||
|
||||
// When
|
||||
const result = await interactiveMode('/project');
|
||||
|
||||
// Then: should cancel
|
||||
expect(result.action).toBe('cancel');
|
||||
});
|
||||
|
||||
it('should handle Ctrl+D (xterm modifyOtherKeys) to cancel input', async () => {
|
||||
// Given: Ctrl+D reported as xterm modifyOtherKeys sequence
|
||||
setupRawStdin(['\x1B[27;5;100~']);
|
||||
setupMockProvider([]);
|
||||
|
||||
// When
|
||||
const result = await interactiveMode('/project');
|
||||
|
||||
// Then: should cancel
|
||||
expect(result.action).toBe('cancel');
|
||||
});
|
||||
|
||||
it('should ignore arrow keys in normal mode', async () => {
|
||||
// Given: text with arrow keys interspersed (arrows are ignored)
|
||||
setupRawStdin([
|
||||
|
||||
@ -190,6 +190,45 @@ const ESC_SHIFT_ENTER = '[13;2u';
|
||||
|
||||
type InputState = 'normal' | 'paste';
|
||||
|
||||
/**
|
||||
* Decode Kitty CSI-u key sequence into a control character.
|
||||
* Example: "[99;5u" (Ctrl+C) -> "\x03"
|
||||
*/
|
||||
function decodeCtrlKey(rest: string): { ch: string; consumed: number } | null {
|
||||
// Kitty CSI-u: [codepoint;modifiersu
|
||||
const kittyMatch = rest.match(/^\[(\d+);(\d+)u/);
|
||||
if (kittyMatch) {
|
||||
const codepoint = Number.parseInt(kittyMatch[1]!, 10);
|
||||
const modifiers = Number.parseInt(kittyMatch[2]!, 10);
|
||||
// Kitty modifiers are 1-based; Ctrl bit is 4 in 0-based flags.
|
||||
const ctrlPressed = (((modifiers - 1) & 4) !== 0);
|
||||
if (!ctrlPressed) return null;
|
||||
|
||||
const key = String.fromCodePoint(codepoint);
|
||||
if (!/^[A-Za-z]$/.test(key)) return null;
|
||||
|
||||
const upper = key.toUpperCase();
|
||||
const controlCode = upper.charCodeAt(0) & 0x1f;
|
||||
return { ch: String.fromCharCode(controlCode), consumed: kittyMatch[0].length };
|
||||
}
|
||||
|
||||
// xterm modifyOtherKeys: [27;modifiers;codepoint~
|
||||
const xtermMatch = rest.match(/^\[27;(\d+);(\d+)~/);
|
||||
if (!xtermMatch) return null;
|
||||
|
||||
const modifiers = Number.parseInt(xtermMatch[1]!, 10);
|
||||
const codepoint = Number.parseInt(xtermMatch[2]!, 10);
|
||||
const ctrlPressed = (((modifiers - 1) & 4) !== 0);
|
||||
if (!ctrlPressed) return null;
|
||||
|
||||
const key = String.fromCodePoint(codepoint);
|
||||
if (!/^[A-Za-z]$/.test(key)) return null;
|
||||
|
||||
const upper = key.toUpperCase();
|
||||
const controlCode = upper.charCodeAt(0) & 0x1f;
|
||||
return { ch: String.fromCharCode(controlCode), consumed: xtermMatch[0].length };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse raw stdin data and process each character/sequence.
|
||||
*
|
||||
@ -229,6 +268,12 @@ function parseInputData(
|
||||
i += 1 + ESC_SHIFT_ENTER.length;
|
||||
continue;
|
||||
}
|
||||
const ctrlKey = decodeCtrlKey(rest);
|
||||
if (ctrlKey) {
|
||||
callbacks.onChar(ctrlKey.ch);
|
||||
i += 1 + ctrlKey.consumed;
|
||||
continue;
|
||||
}
|
||||
// Arrow keys and other CSI sequences: skip \x1B[ + letter/params
|
||||
if (rest.startsWith('[')) {
|
||||
const csiMatch = rest.match(/^\[[0-9;]*[A-Za-z~]/);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user