Clean up, add sgr extension to api

This commit is contained in:
Daniel Imms
2026-01-10 04:38:06 -08:00
parent 50b0f3d7ee
commit 73cba6dda3
4 changed files with 105 additions and 103 deletions
@@ -124,7 +124,8 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
'windowsPty',
];
const nestedBooleanOptions: { label: string, parent: string, prop: string }[] = [
{ label: 'vtExtensions.kittyKeyboard', parent: 'vtExtensions', prop: 'kittyKeyboard' }
{ label: 'vtExtensions.kittyKeyboard', parent: 'vtExtensions', prop: 'kittyKeyboard' },
{ label: 'vtExtensions.kittySgrBoldFaintControl', parent: 'vtExtensions', prop: 'kittySgrBoldFaintControl' }
];
const stringOptions: { [key: string]: string[] | null } = {
cursorStyle: ['block', 'underline', 'bar'],
+2 -2
View File
@@ -5,7 +5,7 @@
import { IKeyboardService } from 'browser/services/Services';
import { evaluateKeyboardEvent } from 'common/input/Keyboard';
import { evaluateKeyboardEventKitty, KittyKeyboardEventType, shouldUseKittyProtocol } from 'common/input/KittyKeyboard';
import { evaluateKeyboardEventKitty, KittyKeyboardEventType, KittyKeyboardFlags, shouldUseKittyProtocol } from 'common/input/KittyKeyboard';
import { isMac } from 'common/Platform';
import { ICoreService, IOptionsService } from 'common/services/Services';
import { IKeyboardResult } from 'common/Types';
@@ -28,7 +28,7 @@ export class KeyboardService implements IKeyboardService {
public evaluateKeyUp(event: KeyboardEvent): IKeyboardResult | undefined {
const kittyFlags = this._coreService.kittyKeyboard.flags;
if (this.useKitty && (kittyFlags & 0b10)) { // REPORT_EVENT_TYPES flag
if (this.useKitty && (kittyFlags & KittyKeyboardFlags.REPORT_EVENT_TYPES)) {
return evaluateKeyboardEventKitty(event, kittyFlags, KittyKeyboardEventType.RELEASE);
}
return undefined;
+101 -99
View File
@@ -3002,105 +3002,6 @@ export class InputHandler extends Disposable implements IInputHandler {
return true;
}
/**
* CSI = flags ; mode u
* Set Kitty keyboard protocol flags.
* mode: 1=set, 2=set-only-specified, 3=reset-only-specified
*
* @vt: #Y CSI KKBDSET "Kitty Keyboard Set" "CSI = Ps ; Pm u" "Set Kitty keyboard protocol flags."
*/
public kittyKeyboardSet(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const flags = params.params[0] || 0;
const mode = params.params[1] || 1;
const state = this._coreService.kittyKeyboard;
switch (mode) {
case 1: // Set all flags
state.flags = flags;
break;
case 2: // Set only specified flags (OR)
state.flags |= flags;
break;
case 3: // Reset only specified flags (AND NOT)
state.flags &= ~flags;
break;
}
return true;
}
/**
* CSI ? u
* Query Kitty keyboard protocol flags.
* Terminal responds with CSI ? flags u
*
* @vt: #Y CSI KKBDQUERY "Kitty Keyboard Query" "CSI ? u" "Query Kitty keyboard protocol flags."
*/
public kittyKeyboardQuery(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const flags = this._coreService.kittyKeyboard.flags;
this._coreService.triggerDataEvent(`${C0.ESC}[?${flags}u`);
return true;
}
/**
* CSI > flags u
* Push Kitty keyboard flags onto stack and set new flags.
*
* @vt: #Y CSI KKBDPUSH "Kitty Keyboard Push" "CSI > Ps u" "Push keyboard flags to stack and set new flags."
*/
public kittyKeyboardPush(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const flags = params.params[0] || 0;
const state = this._coreService.kittyKeyboard;
const isAlt = this._bufferService.buffer === this._bufferService.buffers.alt;
const stack = isAlt ? state.altStack : state.mainStack;
// Evict oldest entry if stack is full (DoS protection, limit of 16)
if (stack.length >= 16) {
stack.shift();
}
// Push current flags onto stack and set new flags
stack.push(state.flags);
state.flags = flags;
return true;
}
/**
* CSI < count u
* Pop Kitty keyboard flags from stack.
*
* @vt: #Y CSI KKBDPOP "Kitty Keyboard Pop" "CSI < Ps u" "Pop keyboard flags from stack."
*/
public kittyKeyboardPop(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const count = Math.max(1, params.params[0] || 1);
const state = this._coreService.kittyKeyboard;
const isAlt = this._bufferService.buffer === this._bufferService.buffers.alt;
const stack = isAlt ? state.altStack : state.mainStack;
// Pop specified number of entries from stack
for (let i = 0; i < count && stack.length > 0; i++) {
state.flags = stack.pop()!;
}
// If stack is empty after popping, reset to 0
if (stack.length === 0 && count > 0) {
state.flags = 0;
}
return true;
}
/**
* OSC 2; <data> ST (set window title)
* Proxy to set window title.
@@ -3612,6 +3513,107 @@ export class InputHandler extends Disposable implements IInputHandler {
public markRangeDirty(y1: number, y2: number): void {
this._dirtyRowTracker.markRangeDirty(y1, y2);
}
// #region Kitty keyboard
/**
* CSI = flags ; mode u
* Set Kitty keyboard protocol flags.
* mode: 1=set, 2=set-only-specified, 3=reset-only-specified
*
* @vt: #Y CSI KKBDSET "Kitty Keyboard Set" "CSI = Ps ; Pm u" "Set Kitty keyboard protocol flags."
*/
public kittyKeyboardSet(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const flags = params.params[0] || 0;
const mode = params.params[1] || 1;
const state = this._coreService.kittyKeyboard;
switch (mode) {
case 1: // Set all flags
state.flags = flags;
break;
case 2: // Set only specified flags (OR)
state.flags |= flags;
break;
case 3: // Reset only specified flags (AND NOT)
state.flags &= ~flags;
break;
}
return true;
}
/**
* CSI ? u
* Query Kitty keyboard protocol flags.
* Terminal responds with CSI ? flags u
*
* @vt: #Y CSI KKBDQUERY "Kitty Keyboard Query" "CSI ? u" "Query Kitty keyboard protocol flags."
*/
public kittyKeyboardQuery(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const flags = this._coreService.kittyKeyboard.flags;
this._coreService.triggerDataEvent(`${C0.ESC}[?${flags}u`);
return true;
}
/**
* CSI > flags u
* Push Kitty keyboard flags onto stack and set new flags.
*
* @vt: #Y CSI KKBDPUSH "Kitty Keyboard Push" "CSI > Ps u" "Push keyboard flags to stack and set new flags."
*/
public kittyKeyboardPush(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const flags = params.params[0] || 0;
const state = this._coreService.kittyKeyboard;
const isAlt = this._bufferService.buffer === this._bufferService.buffers.alt;
const stack = isAlt ? state.altStack : state.mainStack;
// Evict oldest entry if stack is full (DoS protection, limit of 16)
if (stack.length >= 16) {
stack.shift();
}
// Push current flags onto stack and set new flags
stack.push(state.flags);
state.flags = flags;
return true;
}
/**
* CSI < count u
* Pop Kitty keyboard flags from stack.
*
* @vt: #Y CSI KKBDPOP "Kitty Keyboard Pop" "CSI < Ps u" "Pop keyboard flags from stack."
*/
public kittyKeyboardPop(params: IParams): boolean {
if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
return true;
}
const count = Math.max(1, params.params[0] || 1);
const state = this._coreService.kittyKeyboard;
const isAlt = this._bufferService.buffer === this._bufferService.buffers.alt;
const stack = isAlt ? state.altStack : state.mainStack;
// Pop specified number of entries from stack
for (let i = 0; i < count && stack.length > 0; i++) {
state.flags = stack.pop()!;
}
// If stack is empty after popping, reset to 0
if (stack.length === 0 && count > 0) {
state.flags = 0;
}
return true;
}
// #endregion
}
export interface IDirtyRowTracker {
-1
View File
@@ -206,7 +206,6 @@ function encodeModifiers(ev: IKeyboardEvent): number {
if (ev.altKey) mods |= KittyKeyboardModifiers.ALT;
if (ev.ctrlKey) mods |= KittyKeyboardModifiers.CTRL;
if (ev.metaKey) mods |= KittyKeyboardModifiers.SUPER;
// Note: getModifierState would be needed for CAPS_LOCK/NUM_LOCK but not in IKeyboardEvent
return mods > 0 ? mods + 1 : 0;
}