fix(keyboard): Implement Tab and Backspace handling for Kitty Protocol (#7006)

This commit is contained in:
Abhi
2025-08-25 14:41:10 -04:00
committed by GitHub
parent 776627c855
commit 41ece1a8b7
3 changed files with 107 additions and 1 deletions

View File

@@ -17,6 +17,8 @@ import { EventEmitter } from 'events';
import { import {
KITTY_KEYCODE_ENTER, KITTY_KEYCODE_ENTER,
KITTY_KEYCODE_NUMPAD_ENTER, KITTY_KEYCODE_NUMPAD_ENTER,
KITTY_KEYCODE_TAB,
KITTY_KEYCODE_BACKSPACE,
CHAR_CODE_ESC, CHAR_CODE_ESC,
CHAR_CODE_LEFT_BRACKET, CHAR_CODE_LEFT_BRACKET,
CHAR_CODE_1, CHAR_CODE_1,
@@ -282,6 +284,82 @@ describe('KeypressContext - Kitty Protocol', () => {
}); });
}); });
describe('Tab and Backspace handling', () => {
it('should recognize Tab key in kitty protocol', async () => {
const keyHandler = vi.fn();
const { result } = renderHook(() => useKeypressContext(), { wrapper });
act(() => result.current.subscribe(keyHandler));
act(() => {
stdin.sendKittySequence(`\x1b[${KITTY_KEYCODE_TAB}u`);
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'tab',
kittyProtocol: true,
shift: false,
}),
);
});
it('should recognize Shift+Tab in kitty protocol', async () => {
const keyHandler = vi.fn();
const { result } = renderHook(() => useKeypressContext(), { wrapper });
act(() => result.current.subscribe(keyHandler));
// Modifier 2 is Shift
act(() => {
stdin.sendKittySequence(`\x1b[${KITTY_KEYCODE_TAB};2u`);
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'tab',
kittyProtocol: true,
shift: true,
}),
);
});
it('should recognize Backspace key in kitty protocol', async () => {
const keyHandler = vi.fn();
const { result } = renderHook(() => useKeypressContext(), { wrapper });
act(() => result.current.subscribe(keyHandler));
act(() => {
stdin.sendKittySequence(`\x1b[${KITTY_KEYCODE_BACKSPACE}u`);
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'backspace',
kittyProtocol: true,
meta: false,
}),
);
});
it('should recognize Option+Backspace in kitty protocol', async () => {
const keyHandler = vi.fn();
const { result } = renderHook(() => useKeypressContext(), { wrapper });
act(() => result.current.subscribe(keyHandler));
// Modifier 3 is Alt/Option
act(() => {
stdin.sendKittySequence(`\x1b[${KITTY_KEYCODE_BACKSPACE};3u`);
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'backspace',
kittyProtocol: true,
meta: true,
}),
);
});
});
describe('paste mode', () => { describe('paste mode', () => {
it('should handle multiline paste as a single event', async () => { it('should handle multiline paste as a single event', async () => {
const keyHandler = vi.fn(); const keyHandler = vi.fn();

View File

@@ -22,8 +22,10 @@ import { PassThrough } from 'stream';
import { import {
BACKSLASH_ENTER_DETECTION_WINDOW_MS, BACKSLASH_ENTER_DETECTION_WINDOW_MS,
KITTY_CTRL_C, KITTY_CTRL_C,
KITTY_KEYCODE_BACKSPACE,
KITTY_KEYCODE_ENTER, KITTY_KEYCODE_ENTER,
KITTY_KEYCODE_NUMPAD_ENTER, KITTY_KEYCODE_NUMPAD_ENTER,
KITTY_KEYCODE_TAB,
MAX_KITTY_SEQUENCE_LENGTH, MAX_KITTY_SEQUENCE_LENGTH,
} from '../utils/platformConstants.js'; } from '../utils/platformConstants.js';
@@ -136,6 +138,30 @@ export function KeypressProvider({
}; };
} }
if (keyCode === KITTY_KEYCODE_TAB) {
return {
name: 'tab',
ctrl,
meta: alt,
shift,
paste: false,
sequence,
kittyProtocol: true,
};
}
if (keyCode === KITTY_KEYCODE_BACKSPACE) {
return {
name: 'backspace',
ctrl,
meta: alt,
shift,
paste: false,
sequence,
kittyProtocol: true,
};
}
if ( if (
keyCode === KITTY_KEYCODE_ENTER || keyCode === KITTY_KEYCODE_ENTER ||
keyCode === KITTY_KEYCODE_NUMPAD_ENTER keyCode === KITTY_KEYCODE_NUMPAD_ENTER

View File

@@ -22,6 +22,8 @@ export const KITTY_CTRL_C = '[99;5u';
*/ */
export const KITTY_KEYCODE_ENTER = 13; export const KITTY_KEYCODE_ENTER = 13;
export const KITTY_KEYCODE_NUMPAD_ENTER = 57414; export const KITTY_KEYCODE_NUMPAD_ENTER = 57414;
export const KITTY_KEYCODE_TAB = 9;
export const KITTY_KEYCODE_BACKSPACE = 127;
/** /**
* Timing constants for terminal interactions * Timing constants for terminal interactions