52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import type { ParsedKey } from '../parse-keypress.js'
|
|
import { TerminalEvent } from './terminal-event.js'
|
|
|
|
/**
|
|
* Keyboard event dispatched through the DOM tree via capture/bubble.
|
|
*
|
|
* Follows browser KeyboardEvent semantics: `key` is the literal character
|
|
* for printable keys ('a', '3', ' ', '/') and a multi-char name for
|
|
* special keys ('down', 'return', 'escape', 'f1'). The idiomatic
|
|
* printable-char check is `e.key.length === 1`.
|
|
*/
|
|
export class KeyboardEvent extends TerminalEvent {
|
|
readonly key: string
|
|
readonly ctrl: boolean
|
|
readonly shift: boolean
|
|
readonly meta: boolean
|
|
readonly superKey: boolean
|
|
readonly fn: boolean
|
|
|
|
constructor(parsedKey: ParsedKey) {
|
|
super('keydown', { bubbles: true, cancelable: true })
|
|
|
|
this.key = keyFromParsed(parsedKey)
|
|
this.ctrl = parsedKey.ctrl
|
|
this.shift = parsedKey.shift
|
|
this.meta = parsedKey.meta || parsedKey.option
|
|
this.superKey = parsedKey.super
|
|
this.fn = parsedKey.fn
|
|
}
|
|
}
|
|
|
|
function keyFromParsed(parsed: ParsedKey): string {
|
|
const seq = parsed.sequence ?? ''
|
|
const name = parsed.name ?? ''
|
|
|
|
// Ctrl combos: sequence is a control byte (\x03 for ctrl+c), name is the
|
|
// letter. Browsers report e.key === 'c' with e.ctrlKey === true.
|
|
if (parsed.ctrl) return name
|
|
|
|
// Single printable char (space through ~, plus anything above ASCII):
|
|
// use the literal char. Browsers report e.key === '3', not 'Digit3'.
|
|
if (seq.length === 1) {
|
|
const code = seq.charCodeAt(0)
|
|
if (code >= 0x20 && code !== 0x7f) return seq
|
|
}
|
|
|
|
// Special keys (arrows, F-keys, return, tab, escape, etc.): sequence is
|
|
// either an escape sequence (\x1b[B) or a control byte (\r, \t), so use
|
|
// the parsed name. Browsers report e.key === 'ArrowDown'.
|
|
return name || seq
|
|
}
|