77 */
88
99import {
10+ CAP_BACKGROUND_COLOR ,
11+ CAP_COLORDEPTH ,
12+ CAP_CURSOR_COLOR ,
13+ CAP_FOREGROUND_COLOR ,
14+ CAP_KITTY_GRAPHICS ,
15+ CAP_KITTY_KEYBOARD ,
16+ CAP_POINTER_SHAPE ,
17+ CAP_SYNC_OUTPUT ,
18+ COLORDEPTH_TRUECOLOR ,
1019 createInputNative ,
20+ EVENT_CAPABILITY ,
1121 EVENT_CURSOR ,
1222 EVENT_KEY ,
1323 EVENT_MOUSE ,
@@ -77,7 +87,6 @@ import {
7787 KEY_SUPER_LEFT ,
7888 KEY_SUPER_RIGHT ,
7989 KEY_TAB ,
80- MAX_TERMINFO ,
8190 MOD_ALT ,
8291 MOD_CTRL ,
8392 MOD_MOTION ,
@@ -87,6 +96,8 @@ import {
8796 readEvent ,
8897 SCAN_BUFFER_SIZE ,
8998} from "./input-native.ts" ;
99+ import type { Rgb , TerminalInfo } from "./terminfo.ts" ;
100+ import { rgbOf } from "./terminfo.ts" ;
90101
91102/**
92103 * Modifier keys held during a key or mouse event.
@@ -371,6 +382,57 @@ export interface CursorEvent {
371382 column : number ;
372383}
373384
385+ /** Color depth tier reported by the terminal's XTGETTCAP probe response. */
386+ export type ColorDepth = "truecolor" | "256" | "16" ;
387+
388+ /**
389+ * A probe-response event emitted by scan() when the terminal answers one
390+ * of the capability queries in TerminalInfo.probe. Route to term.update().
391+ */
392+ export type CapabilityEvent =
393+ | {
394+ readonly type : "capability" ;
395+ readonly key : "foreground-color" ;
396+ readonly value : Rgb ;
397+ }
398+ | {
399+ readonly type : "capability" ;
400+ readonly key : "background-color" ;
401+ readonly value : Rgb ;
402+ }
403+ | {
404+ readonly type : "capability" ;
405+ readonly key : "cursor-color" ;
406+ readonly value : Rgb ;
407+ }
408+ | {
409+ readonly type : "capability" ;
410+ readonly key : "colordepth" ;
411+ readonly value : ColorDepth ;
412+ }
413+ | {
414+ readonly type : "capability" ;
415+ readonly key : "sync-output" ;
416+ readonly value : boolean ;
417+ }
418+ | {
419+ readonly type : "capability" ;
420+ readonly key : "kitty-keyboard" ;
421+ readonly value : boolean ;
422+ }
423+ | {
424+ readonly type : "capability" ;
425+ readonly key : "kitty-graphics" ;
426+ readonly value : boolean ;
427+ }
428+ | {
429+ readonly type : "capability" ;
430+ readonly key : "pointer-shape" ;
431+ readonly value : boolean ;
432+ } ;
433+
434+ export type { Rgb } ;
435+
374436import type { PointerEvent } from "./term.ts" ;
375437
376438export type InputEvent =
@@ -381,6 +443,7 @@ export type InputEvent =
381443 | WheelEvent
382444 | ResizeEvent
383445 | CursorEvent
446+ | CapabilityEvent
384447 | PointerEvent ;
385448
386449/**
@@ -426,38 +489,31 @@ export interface Input {
426489export interface InputOptions {
427490 /**
428491 * Milliseconds to wait before resolving a lone ESC byte as the Escape
429- * key rather than the start of an escape sequence. Lower values feel
430- * snappier but risk misinterpreting sequences on slow connections.
431- *
432- * For reference, Vim's `ttimeoutlen` defaults to 100ms and ncurses
433- * `ESCDELAY` defaults to 1000ms. The default of 25ms is tuned for
434- * local terminals where escape sequences arrive within microseconds.
492+ * key rather than the start of an escape sequence.
435493 *
436494 * @default 25
437495 */
438496 escLatency ?: number ;
439497
440498 /**
441- * Compiled terminfo binary to load terminal-specific escape sequences.
442- *
443- * This is the format used by files like /usr/lib/terminfo/78/xterm-256color
444- * and they can be directly loaded from disk into this option.
445- *
446- * If no terminfo is provided it will use xterm capabilities as the default
499+ * Terminal detection from detectTerminal(). Seeds the key trie from
500+ * terminfo.keys and uses terminfo.capabilities.colors for
501+ * colordepth denial events. When omitted, the parser uses xterm
502+ * default key sequences and a 256-color baseline.
447503 */
448- terminfo ?: Uint8Array ;
504+ terminfo ?: TerminalInfo ;
449505}
450506
451507export async function createInput ( options : InputOptions = { } ) : Promise < Input > {
452508 let { escLatency = 25 , terminfo } = options ;
453509
454- if ( terminfo && terminfo . byteLength > MAX_TERMINFO ) {
455- throw new RangeError (
456- ` terminfo exceeds ${ MAX_TERMINFO } byte limit (got ${ terminfo . byteLength } )` ,
457- ) ;
458- }
510+ let native = await createInputNative (
511+ escLatency ,
512+ terminfo ?. keys ,
513+ terminfo ?. capabilities . colors ,
514+ ) ;
459515
460- let native = await createInputNative ( escLatency ) ;
516+ let initialColors = terminfo ?. capabilities . colors ?? 256 ;
461517
462518 return {
463519 scan ( bytes : Uint8Array = new Uint8Array ( 0 ) ) : ScanResult {
@@ -482,8 +538,11 @@ export async function createInput(options: InputOptions = {}): Promise<Input> {
482538 let view = new DataView ( native . memory . buffer ) ;
483539 for ( let i = 0 ; i < count ; i ++ ) {
484540 let ptr = native . event ( native . state , i ) ;
485- if ( ptr !== 0 ) {
486- events . push ( mapEvent ( readEvent ( view , ptr ) ) ) ;
541+ let event = ptr !== 0
542+ ? mapEvent ( readEvent ( view , ptr ) , initialColors )
543+ : undefined ;
544+ if ( event ) {
545+ events . push ( event ) ;
487546 }
488547 }
489548
@@ -632,8 +691,70 @@ function mapKeyEvent(native: NativeInputEvent): KeyEvent {
632691 return ev ;
633692}
634693
635- function mapEvent ( native : NativeInputEvent ) : InputEvent {
694+ function mapCapEvent (
695+ native : NativeInputEvent ,
696+ initialColors : number ,
697+ ) : CapabilityEvent | undefined {
698+ switch ( native . key ) {
699+ case CAP_FOREGROUND_COLOR :
700+ return {
701+ type : "capability" ,
702+ key : "foreground-color" ,
703+ value : rgbOf ( native . ch ) ,
704+ } ;
705+ case CAP_BACKGROUND_COLOR :
706+ return {
707+ type : "capability" ,
708+ key : "background-color" ,
709+ value : rgbOf ( native . ch ) ,
710+ } ;
711+ case CAP_CURSOR_COLOR :
712+ return {
713+ type : "capability" ,
714+ key : "cursor-color" ,
715+ value : rgbOf ( native . ch ) ,
716+ } ;
717+ case CAP_COLORDEPTH : {
718+ let value : ColorDepth = native . ch === COLORDEPTH_TRUECOLOR
719+ ? "truecolor"
720+ : initialColors <= 16
721+ ? "16"
722+ : "256" ;
723+ return { type : "capability" , key : "colordepth" , value } ;
724+ }
725+ case CAP_SYNC_OUTPUT :
726+ return { type : "capability" , key : "sync-output" , value : native . ch !== 0 } ;
727+ case CAP_KITTY_KEYBOARD :
728+ return {
729+ type : "capability" ,
730+ key : "kitty-keyboard" ,
731+ value : native . ch !== 0 ,
732+ } ;
733+ case CAP_KITTY_GRAPHICS :
734+ return {
735+ type : "capability" ,
736+ key : "kitty-graphics" ,
737+ value : native . ch !== 0 ,
738+ } ;
739+ case CAP_POINTER_SHAPE :
740+ return {
741+ type : "capability" ,
742+ key : "pointer-shape" ,
743+ value : native . ch !== 0 ,
744+ } ;
745+ default :
746+ return undefined ;
747+ }
748+ }
749+
750+ function mapEvent (
751+ native : NativeInputEvent ,
752+ initialColors : number ,
753+ ) : InputEvent | undefined {
636754 switch ( native . type ) {
755+ case EVENT_CAPABILITY : {
756+ return mapCapEvent ( native , initialColors ) ;
757+ }
637758 case EVENT_KEY : {
638759 return mapKeyEvent ( native ) ;
639760 }
0 commit comments