未验证 提交 56f008e7 编写于 作者: D Daniel Imms 提交者: GitHub

Merge pull request #77252 from microsoft/tyriar/a11y_keybinding

Add a accessibility mode context key and a terminal "line navigation mode" and keybindings
......@@ -140,8 +140,6 @@ export module StaticServices {
export const notificationService = define(INotificationService, () => new SimpleNotificationService());
export const accessibilityService = define(IAccessibilityService, () => new BrowserAccessibilityService());
export const markerService = define(IMarkerService, () => new MarkerService());
export const modeService = define(IModeService, (o) => new ModeServiceImpl());
......@@ -194,6 +192,8 @@ export class DynamicStandaloneServices extends Disposable {
let contextKeyService = ensure(IContextKeyService, () => this._register(new ContextKeyService(configurationService)));
ensure(IAccessibilityService, () => new BrowserAccessibilityService(contextKeyService, configurationService));
ensure(IListService, () => new ListService(contextKeyService));
let commandService = ensure(ICommandService, () => new StandaloneCommandService(this._instantiationService));
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
import { Event, Emitter } from 'vs/base/common/event';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export abstract class AbstractAccessibilityService extends Disposable implements IAccessibilityService {
_serviceBrand: any;
private _accessibilityModeEnabledContext: IContextKey<boolean>;
protected readonly _onDidChangeAccessibilitySupport = new Emitter<void>();
readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event;
constructor(
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super();
this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor.accessibilitySupport')) {
this._updateContextKey();
}
}));
this._updateContextKey();
this.onDidChangeAccessibilitySupport(() => this._updateContextKey());
}
abstract alwaysUnderlineAccessKeys(): Promise<boolean>;
abstract getAccessibilitySupport(): AccessibilitySupport;
abstract setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void;
private _updateContextKey(): void {
const detected = this.getAccessibilitySupport() === AccessibilitySupport.Enabled;
const config = this._configurationService.getValue('editor.accessibilitySupport');
this._accessibilityModeEnabledContext.set(config === 'on' || (config === 'auto' && detected));
}
}
\ No newline at end of file
......@@ -5,6 +5,7 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
export const IAccessibilityService = createDecorator<IAccessibilityService>('accessibilityService');
......@@ -27,4 +28,6 @@ export const enum AccessibilitySupport {
Disabled = 1,
Enabled = 2
}
\ No newline at end of file
}
export const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey<boolean>('accessibilityModeEnabled', false);
......@@ -3,17 +3,23 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService';
export class BrowserAccessibilityService extends Disposable implements IAccessibilityService {
export class BrowserAccessibilityService extends AbstractAccessibilityService implements IAccessibilityService {
_serviceBrand: any;
private _accessibilitySupport = AccessibilitySupport.Unknown;
private readonly _onDidChangeAccessibilitySupport = new Emitter<void>();
readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event;
constructor(
@IContextKeyService readonly contextKeyService: IContextKeyService,
@IConfigurationService readonly configurationService: IConfigurationService,
) {
super(contextKeyService, configurationService);
}
alwaysUnderlineAccessKeys(): Promise<boolean> {
return Promise.resolve(false);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { Terminal, ITerminalAddon } from 'xterm';
import { addDisposableListener } from 'vs/base/browser/dom';
import { INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal';
export class NavigationModeAddon implements INavigationMode, ITerminalAddon {
private _terminal: Terminal;
constructor(
private _navigationModeContextKey: IContextKey<boolean>
) { }
activate(terminal: Terminal): void {
this._terminal = terminal;
}
dispose() { }
exitNavigationMode(): void {
this._terminal.scrollToBottom();
this._terminal.focus();
}
focusPreviousLine(): void {
// Focus previous row if a row is already focused
if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) {
const element = <HTMLElement | null>document.activeElement.previousElementSibling;
if (element) {
element.focus();
const disposable = addDisposableListener(element, 'blur', () => {
this._navigationModeContextKey.set(false);
disposable.dispose();
});
this._navigationModeContextKey.set(true);
}
return;
}
// Ensure a11y tree exists
const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree');
if (!treeContainer) {
return;
}
// Target is row before the cursor
const targetRow = Math.max(this._terminal.buffer.cursorY - 1, 0);
// Check bounds
if (treeContainer.childElementCount < targetRow) {
return;
}
// Focus
const element = <HTMLElement>treeContainer.childNodes.item(targetRow);
element.focus();
const disposable = addDisposableListener(element, 'blur', () => {
this._navigationModeContextKey.set(false);
disposable.dispose();
});
this._navigationModeContextKey.set(true);
}
focusNextLine(): void {
// Focus previous row if a row is already focused
if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) {
const element = <HTMLElement | null>document.activeElement.nextElementSibling;
if (element) {
element.focus();
const disposable = addDisposableListener(element, 'blur', () => {
this._navigationModeContextKey.set(false);
disposable.dispose();
});
this._navigationModeContextKey.set(true);
}
return;
}
// Ensure a11y tree exists
const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree');
if (!treeContainer) {
return;
}
// Target is cursor row
const targetRow = this._terminal.buffer.cursorY;
// Check bounds
if (treeContainer.childElementCount < targetRow) {
return;
}
// Focus row before cursor
const element = <HTMLElement>treeContainer.childNodes.item(targetRow);
element.focus();
const disposable = addDisposableListener(element, 'blur', () => {
this._navigationModeContextKey.set(false);
disposable.dispose();
});
this._navigationModeContextKey.set(true);
}
}
\ No newline at end of file
......@@ -20,10 +20,10 @@ import * as panel from 'vs/workbench/browser/panel';
import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { Extensions as QuickOpenExtensions, IQuickOpenRegistry, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand, NavigationModeFocusPreviousTerminalAction, NavigationModeFocusNextTerminalAction, NavigationModeExitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel';
import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen';
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal';
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS } from 'vs/workbench/contrib/terminal/common/terminal';
import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu';
......@@ -33,6 +33,7 @@ import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/br
import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig';
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
registerSingleton(ITerminalService, TerminalService, true);
......@@ -459,6 +460,21 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextComm
primary: 0,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeExitTerminalAction, NavigationModeExitTerminalAction.ID, NavigationModeExitTerminalAction.LABEL, {
primary: KeyCode.Escape
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Exit Navigation Mode', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.UpArrow
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.UpArrow
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.DownArrow
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.DownArrow
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category);
......
......@@ -887,6 +887,71 @@ export class ScrollToTopTerminalAction extends Action {
}
}
export class NavigationModeExitTerminalAction extends Action {
public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT;
public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeExit', "Exit Navigation Mode");
constructor(
id: string, label: string,
@ITerminalService private readonly terminalService: ITerminalService
) {
super(id, label);
}
public run(event?: any): Promise<any> {
const terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance && terminalInstance.navigationMode) {
terminalInstance.navigationMode.exitNavigationMode();
}
return Promise.resolve(undefined);
}
}
export class NavigationModeFocusPreviousTerminalAction extends Action {
public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS;
public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusPrevious', "Focus Previous Line (Navigation Mode)");
constructor(
id: string, label: string,
@ITerminalService private readonly terminalService: ITerminalService
) {
super(id, label);
}
public run(event?: any): Promise<any> {
const terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance && terminalInstance.navigationMode) {
terminalInstance.navigationMode.focusPreviousLine();
}
return Promise.resolve(undefined);
}
}
export class NavigationModeFocusNextTerminalAction extends Action {
public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT;
public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusNext', "Focus Next Line (Navigation Mode)");
constructor(
id: string, label: string,
@ITerminalService private readonly terminalService: ITerminalService
) {
super(id, label);
}
public run(event?: any): Promise<any> {
const terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance && terminalInstance.navigationMode) {
terminalInstance.navigationMode.focusNextLine();
}
return Promise.resolve(undefined);
}
}
export class ClearTerminalAction extends Action {
public static readonly ID = TERMINAL_COMMAND_ID.CLEAR;
......
......@@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal';
import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
......@@ -35,8 +35,9 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
import { Terminal as XTermTerminal, IBuffer } from 'xterm';
import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm';
import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon';
// How long in milliseconds should an average frame take to render for a notification to appear
// which suggests the fallback DOM-based renderer
......@@ -91,6 +92,9 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
TERMINAL_COMMAND_ID.SPLIT_IN_ACTIVE_WORKSPACE,
TERMINAL_COMMAND_ID.SPLIT,
TERMINAL_COMMAND_ID.TOGGLE,
TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT,
TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT,
TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS,
'editor.action.toggleTabFocusMode',
'workbench.action.quickOpen',
'workbench.action.quickOpenPreviousEditor',
......@@ -183,6 +187,7 @@ export class TerminalInstance implements ITerminalInstance {
private _xtermSearch: SearchAddon | undefined;
private _xtermElement: HTMLDivElement;
private _terminalHasTextContextKey: IContextKey<boolean>;
private _terminalA11yTreeFocusContextKey: IContextKey<boolean>;
private _cols: number;
private _rows: number;
private _dimensionsOverride: ITerminalDimensions | undefined;
......@@ -197,6 +202,7 @@ export class TerminalInstance implements ITerminalInstance {
private _widgetManager: TerminalWidgetManager;
private _linkHandler: TerminalLinkHandler;
private _commandTracker: TerminalCommandTracker;
private _navigationModeAddon: INavigationMode & ITerminalAddon | undefined;
public disableLayout: boolean;
public get id(): number { return this._id; }
......@@ -224,6 +230,7 @@ export class TerminalInstance implements ITerminalInstance {
public get isTitleSetByProcess(): boolean { return !!this._messageTitleDisposable; }
public get shellLaunchConfig(): IShellLaunchConfig { return this._shellLaunchConfig; }
public get commandTracker(): TerminalCommandTracker { return this._commandTracker; }
public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; }
private readonly _onExit = new Emitter<number>();
public get onExit(): Event<number> { return this._onExit.event; }
......@@ -280,6 +287,7 @@ export class TerminalInstance implements ITerminalInstance {
});
this._terminalHasTextContextKey = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.bindTo(this._contextKeyService);
this._terminalA11yTreeFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS.bindTo(this._contextKeyService);
this.disableLayout = false;
this._logService.trace(`terminalInstance#ctor (id: ${this.id})`, this._shellLaunchConfig);
......@@ -462,13 +470,13 @@ export class TerminalInstance implements ITerminalInstance {
letterSpacing: font.letterSpacing,
lineHeight: font.lineHeight,
bellStyle: config.enableBell ? 'sound' : 'none',
screenReaderMode: this._isScreenReaderOptimized(),
macOptionIsMeta: config.macOptionIsMeta,
macOptionClickForcesSelection: config.macOptionClickForcesSelection,
rightClickSelectsWord: config.rightClickBehavior === 'selectWord',
// TODO: Guess whether to use canvas or dom better
rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType
});
this.updateAccessibilitySupport();
this._terminalInstanceService.getXtermSearchConstructor().then(Addon => {
this._xtermSearch = new Addon();
this._xterm.loadAddon(this._xtermSearch);
......@@ -958,7 +966,6 @@ export class TerminalInstance implements ITerminalInstance {
private _refreshSelectionContextKey() {
const activePanel = this._panelService.getActivePanel();
const isActive = !!activePanel && activePanel.getId() === TERMINAL_PANEL_ID;
this._terminalHasTextContextKey.set(isActive && this.hasSelection());
}
......@@ -1224,7 +1231,17 @@ export class TerminalInstance implements ITerminalInstance {
}
public updateAccessibilitySupport(): void {
this._xterm.setOption('screenReaderMode', this._isScreenReaderOptimized());
const isEnabled = this._isScreenReaderOptimized();
if (isEnabled) {
this._navigationModeAddon = new NavigationModeAddon(this._terminalA11yTreeFocusContextKey);
this._xterm.loadAddon(this._navigationModeAddon);
} else {
if (this._navigationModeAddon) {
this._navigationModeAddon.dispose();
this._navigationModeAddon = undefined;
}
}
this._xterm.setOption('screenReaderMode', isEnabled);
}
private _setCursorBlink(blink: boolean): void {
......
......@@ -21,6 +21,8 @@ export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey<boolean>('t
export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey<boolean>('terminalFocus', false);
/** A context key that is set when the integrated terminal does not have focus. */
export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated();
/** A context key that is set when the user is navigating the accessibility tree */
export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey<boolean>('terminalA11yTreeFocus', false);
/** A keybinding context key that is set when the integrated terminal has text selected. */
export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey<boolean>('terminalTextSelected', false);
......@@ -483,6 +485,8 @@ export interface ITerminalInstance {
*/
readonly commandTracker: ITerminalCommandTracker;
readonly navigationMode: INavigationMode | undefined;
/**
* Dispose the terminal instance, removing it from the panel/service and freeing up resources.
*
......@@ -629,17 +633,6 @@ export interface ITerminalInstance {
*/
attachToElement(container: HTMLElement): void;
/**
* Updates the configuration of the terminal instance.
*/
updateConfig(): void;
/**
* Updates the accessibility support state of the terminal instance.
* @param isEnabled Whether it's enabled.
*/
updateAccessibilitySupport(isEnabled: boolean): void;
/**
* Configure the dimensions of the terminal instance.
*
......@@ -687,6 +680,12 @@ export interface ITerminalCommandTracker {
selectToNextLine(): void;
}
export interface INavigationMode {
exitNavigationMode(): void;
focusPreviousLine(): void;
focusNextLine(): void;
}
export interface IBeforeProcessDataEvent {
/**
* The data of the event, this can be modified by the event listener to change what gets sent
......
......@@ -68,6 +68,9 @@ export const enum TERMINAL_COMMAND_ID {
TOGGLE_FIND_REGEX_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindRegexTerminalFocus',
TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindWholeWordTerminalFocus',
TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindCaseSensitiveTerminalFocus',
NAVIGATION_MODE_EXIT = 'workbench.action.terminal.navigationModeExit',
NAVIGATION_MODE_FOCUS_NEXT = 'workbench.action.terminal.navigationModeFocusNext',
NAVIGATION_MODE_FOCUS_PREVIOUS = 'workbench.action.terminal.navigationModeFocusPrevious'
}
export function setupTerminalCommands(): void {
......
......@@ -5,19 +5,23 @@
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { isWindows } from 'vs/base/common/platform';
import { Emitter, Event } from 'vs/base/common/event';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService';
export class AccessibilityService implements IAccessibilityService {
export class AccessibilityService extends AbstractAccessibilityService implements IAccessibilityService {
_serviceBrand: any;
private _accessibilitySupport = AccessibilitySupport.Unknown;
private readonly _onDidChangeAccessibilitySupport = new Emitter<void>();
readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event;
constructor(
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
) { }
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IContextKeyService readonly contextKeyService: IContextKeyService,
@IConfigurationService readonly configurationService: IConfigurationService
) {
super(contextKeyService, configurationService);
}
alwaysUnderlineAccessKeys(): Promise<boolean> {
if (!isWindows) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册