Support color scheme reporting
CSI ? 996 n CSI ? 2031 h CSI ? 2031 l Fixes #5626
This commit is contained in:
@@ -42,7 +42,7 @@ import { SelectionService } from 'browser/services/SelectionService';
|
||||
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
|
||||
import { ThemeService } from 'browser/services/ThemeService';
|
||||
import { KeyboardService } from 'browser/services/KeyboardService';
|
||||
import { channels, color } from 'common/Color';
|
||||
import { channels, color, rgb } from 'common/Color';
|
||||
import { CoreTerminal } from 'common/CoreTerminal';
|
||||
import * as Browser from 'common/Platform';
|
||||
import { ColorRequestType, CoreMouseAction, CoreMouseButton, CoreMouseEventType, IColorEvent, ITerminalOptions, KeyboardResultType, SpecialColorIndex } from 'common/Types';
|
||||
@@ -252,6 +252,20 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the current color scheme (dark or light) based on the relative luminance
|
||||
* of the background and foreground theme colors.
|
||||
* Sends CSI ? 997 ; 1 n for dark mode or CSI ? 997 ; 2 n for light mode.
|
||||
*/
|
||||
private _reportColorScheme(): void {
|
||||
if (!this._themeService) return;
|
||||
const bgLuminance = rgb.relativeLuminance(this._themeService.colors.background.rgba >> 8);
|
||||
const fgLuminance = rgb.relativeLuminance(this._themeService.colors.foreground.rgba >> 8);
|
||||
// Dark mode = background is darker than foreground (lower luminance)
|
||||
const colorSchemeMode = bgLuminance < fgLuminance ? 1 : 2;
|
||||
this.coreService.triggerDataEvent(`${C0.ESC}[?997;${colorSchemeMode}n`);
|
||||
}
|
||||
|
||||
protected _setup(): void {
|
||||
super._setup();
|
||||
|
||||
@@ -495,6 +509,16 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
||||
this._themeService = this._instantiationService.createInstance(ThemeService);
|
||||
this._instantiationService.setService(IThemeService, this._themeService);
|
||||
|
||||
// CSI ? 996 n - color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
|
||||
this._register(this._inputHandler.onRequestColorSchemeQuery(() => this._reportColorScheme()));
|
||||
|
||||
// Emit unsolicited color scheme notification on theme change when DECSET 2031 is enabled
|
||||
this._register(this._themeService.onChangeColors(() => {
|
||||
if (this.coreService.decPrivateModes.colorSchemeUpdates) {
|
||||
this._reportColorScheme();
|
||||
}
|
||||
}));
|
||||
|
||||
this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService);
|
||||
this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService);
|
||||
|
||||
|
||||
@@ -269,6 +269,26 @@ describe('InputHandler', () => {
|
||||
inputHandler.resetModePrivate(Params.fromArray([2004]));
|
||||
assert.equal(coreService.decPrivateModes.bracketedPasteMode, false);
|
||||
});
|
||||
it('should toggle colorSchemeUpdates (DECSET 2031)', () => {
|
||||
const coreService = new MockCoreService();
|
||||
const optionsService = new MockOptionsService();
|
||||
const inputHandler = new TestInputHandler(new MockBufferService(80, 30), new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService());
|
||||
// Set color scheme updates mode (default colorSchemeQuery=true)
|
||||
inputHandler.setModePrivate(Params.fromArray([2031]));
|
||||
assert.equal(coreService.decPrivateModes.colorSchemeUpdates, true);
|
||||
// Reset color scheme updates mode
|
||||
inputHandler.resetModePrivate(Params.fromArray([2031]));
|
||||
assert.equal(coreService.decPrivateModes.colorSchemeUpdates, false);
|
||||
});
|
||||
it('should not toggle colorSchemeUpdates when colorSchemeQuery is disabled', () => {
|
||||
const coreService = new MockCoreService();
|
||||
const optionsService = new MockOptionsService();
|
||||
optionsService.rawOptions.vtExtensions = { colorSchemeQuery: false };
|
||||
const inputHandler = new TestInputHandler(new MockBufferService(80, 30), new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService());
|
||||
// Attempt to set color scheme updates mode
|
||||
inputHandler.setModePrivate(Params.fromArray([2031]));
|
||||
assert.equal(coreService.decPrivateModes.colorSchemeUpdates, false);
|
||||
});
|
||||
});
|
||||
describe('regression tests', function (): void {
|
||||
function termContent(bufferService: IBufferService, trim: boolean): string[] {
|
||||
|
||||
@@ -159,6 +159,8 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
public readonly onTitleChange = this._onTitleChange.event;
|
||||
private readonly _onColor = this._register(new Emitter<IColorEvent>());
|
||||
public readonly onColor = this._onColor.event;
|
||||
private readonly _onRequestColorSchemeQuery = this._register(new Emitter<void>());
|
||||
public readonly onRequestColorSchemeQuery = this._onRequestColorSchemeQuery.event;
|
||||
|
||||
private _parseStack: IParseStack = {
|
||||
paused: false,
|
||||
@@ -2026,6 +2028,11 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
case 2026: // synchronized output (https://github.com/contour-terminal/vt-extensions/blob/master/synchronized-output.md)
|
||||
this._coreService.decPrivateModes.synchronizedOutput = true;
|
||||
break;
|
||||
case 2031: // color scheme updates (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
|
||||
if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
|
||||
this._coreService.decPrivateModes.colorSchemeUpdates = true;
|
||||
}
|
||||
break;
|
||||
case 9001: // win32-input-mode (https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md)
|
||||
if (this._optionsService.rawOptions.vtExtensions?.win32InputMode) {
|
||||
this._coreService.decPrivateModes.win32InputMode = true;
|
||||
@@ -2271,6 +2278,11 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._coreService.decPrivateModes.synchronizedOutput = false;
|
||||
this._onRequestRefreshRows.fire(undefined);
|
||||
break;
|
||||
case 2031: // color scheme updates (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
|
||||
if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
|
||||
this._coreService.decPrivateModes.colorSchemeUpdates = false;
|
||||
}
|
||||
break;
|
||||
case 9001: // win32-input-mode
|
||||
if (this._optionsService.rawOptions.vtExtensions?.win32InputMode) {
|
||||
this._coreService.decPrivateModes.win32InputMode = false;
|
||||
@@ -2774,6 +2786,12 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
// no dec locator/mouse
|
||||
// this.handler(C0.ESC + '[?50n');
|
||||
break;
|
||||
case 996:
|
||||
// color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
|
||||
if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
|
||||
this._onRequestColorSchemeQuery.fire();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ export class MockCoreService implements ICoreService {
|
||||
applicationCursorKeys: false,
|
||||
applicationKeypad: false,
|
||||
bracketedPasteMode: false,
|
||||
colorSchemeUpdates: false,
|
||||
cursorBlink: undefined,
|
||||
cursorStyle: undefined,
|
||||
origin: false,
|
||||
|
||||
@@ -268,6 +268,7 @@ export interface IDecPrivateModes {
|
||||
applicationCursorKeys: boolean;
|
||||
applicationKeypad: boolean;
|
||||
bracketedPasteMode: boolean;
|
||||
colorSchemeUpdates: boolean;
|
||||
cursorBlink: boolean | undefined;
|
||||
cursorStyle: CursorStyle | undefined;
|
||||
origin: boolean;
|
||||
|
||||
@@ -17,6 +17,7 @@ const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({
|
||||
applicationCursorKeys: false,
|
||||
applicationKeypad: false,
|
||||
bracketedPasteMode: false,
|
||||
colorSchemeUpdates: false,
|
||||
cursorBlink: undefined,
|
||||
cursorStyle: undefined,
|
||||
origin: false,
|
||||
|
||||
@@ -313,6 +313,7 @@ export interface IVtExtensions {
|
||||
kittyKeyboard?: boolean;
|
||||
kittySgrBoldFaintControl?: boolean;
|
||||
win32InputMode?: boolean;
|
||||
colorSchemeQuery?: boolean;
|
||||
}
|
||||
|
||||
export const IOscLinkService = createDecorator<IOscLinkService>('OscLinkService');
|
||||
|
||||
Reference in New Issue
Block a user