Merge pull request #98 from Vasanthdev2004/windows-csiu-input-fix
fix: support CSI-u printable input on Windows
This commit is contained in:
49
src/ink/parse-keypress.test.ts
Normal file
49
src/ink/parse-keypress.test.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { expect, test } from 'bun:test'
|
||||||
|
|
||||||
|
import {
|
||||||
|
INITIAL_STATE,
|
||||||
|
parseMultipleKeypresses,
|
||||||
|
type ParsedKey,
|
||||||
|
} from './parse-keypress.ts'
|
||||||
|
import { InputEvent } from './events/input-event.ts'
|
||||||
|
|
||||||
|
function parseInputEvent(sequence: string): InputEvent {
|
||||||
|
const [items] = parseMultipleKeypresses(INITIAL_STATE, sequence)
|
||||||
|
|
||||||
|
expect(items).toHaveLength(1)
|
||||||
|
|
||||||
|
const item = items[0]
|
||||||
|
expect(item?.kind).toBe('key')
|
||||||
|
|
||||||
|
return new InputEvent(item as ParsedKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
test('treats CSI-u modifier 0 as unmodified printable input', () => {
|
||||||
|
const event = parseInputEvent('\x1b[47;0u')
|
||||||
|
|
||||||
|
expect(event.input).toBe('/')
|
||||||
|
expect(event.key.ctrl).toBe(false)
|
||||||
|
expect(event.key.meta).toBe(false)
|
||||||
|
expect(event.key.shift).toBe(false)
|
||||||
|
expect(event.key.super).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('preserves printable Unicode CSI-u input', () => {
|
||||||
|
const event = parseInputEvent('\x1b[231u')
|
||||||
|
|
||||||
|
expect(event.input).toBe('ç')
|
||||||
|
expect(event.key.ctrl).toBe(false)
|
||||||
|
expect(event.key.meta).toBe(false)
|
||||||
|
expect(event.key.shift).toBe(false)
|
||||||
|
expect(event.key.super).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('preserves printable Unicode CSI-u input with explicit modifier 0', () => {
|
||||||
|
const event = parseInputEvent('\x1b[231;0u')
|
||||||
|
|
||||||
|
expect(event.input).toBe('ç')
|
||||||
|
expect(event.key.ctrl).toBe(false)
|
||||||
|
expect(event.key.meta).toBe(false)
|
||||||
|
expect(event.key.shift).toBe(false)
|
||||||
|
expect(event.key.super).toBe(false)
|
||||||
|
})
|
||||||
@@ -468,7 +468,10 @@ function decodeModifier(modifier: number): {
|
|||||||
ctrl: boolean
|
ctrl: boolean
|
||||||
super: boolean
|
super: boolean
|
||||||
} {
|
} {
|
||||||
const m = modifier - 1
|
// Some Windows VT stacks use 0 instead of 1 for an unmodified CSI-u key.
|
||||||
|
// Clamp to the protocol default so plain printable keys don't look like
|
||||||
|
// ctrl+meta+shift+super all at once.
|
||||||
|
const m = Math.max(modifier, 1) - 1
|
||||||
return {
|
return {
|
||||||
shift: !!(m & 1),
|
shift: !!(m & 1),
|
||||||
meta: !!(m & 2),
|
meta: !!(m & 2),
|
||||||
@@ -477,6 +480,14 @@ function decodeModifier(modifier: number): {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPrivateUseCodepoint(codepoint: number): boolean {
|
||||||
|
return (
|
||||||
|
(codepoint >= 0xe000 && codepoint <= 0xf8ff) ||
|
||||||
|
(codepoint >= 0xf0000 && codepoint <= 0xffffd) ||
|
||||||
|
(codepoint >= 0x100000 && codepoint <= 0x10fffd)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map keycode to key name for modifyOtherKeys/CSI u sequences.
|
* Map keycode to key name for modifyOtherKeys/CSI u sequences.
|
||||||
* Handles both ASCII keycodes and Kitty keyboard protocol functional keys.
|
* Handles both ASCII keycodes and Kitty keyboard protocol functional keys.
|
||||||
@@ -536,6 +547,21 @@ function keycodeToName(keycode: number): string | undefined {
|
|||||||
if (keycode >= 32 && keycode <= 126) {
|
if (keycode >= 32 && keycode <= 126) {
|
||||||
return String.fromCharCode(keycode).toLowerCase()
|
return String.fromCharCode(keycode).toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CSI-u can carry printable Unicode codepoints directly on some
|
||||||
|
// Windows terminals and keyboard layouts. Keep kitty's private-use
|
||||||
|
// functional key range excluded so special keys still stay non-text.
|
||||||
|
if (
|
||||||
|
keycode > 0x1f &&
|
||||||
|
keycode !== 0x7f &&
|
||||||
|
(keycode < 0x80 || keycode > 0x9f) &&
|
||||||
|
keycode <= 0x10ffff &&
|
||||||
|
(keycode < 0xd800 || keycode > 0xdfff) &&
|
||||||
|
!isPrivateUseCodepoint(keycode)
|
||||||
|
) {
|
||||||
|
return String.fromCodePoint(keycode)
|
||||||
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user