browser keybinding service

This commit is contained in:
Peng Lyu
2019-06-12 15:07:01 -07:00
parent 9557b28aee
commit e26d5ac79f
11 changed files with 381 additions and 173 deletions
+1 -22
View File
@@ -13,7 +13,7 @@ import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
// tslint:disable-next-line: import-patterns no-standalone-editor
import { StandaloneKeybindingService, SimpleResourcePropertiesService } from 'vs/editor/standalone/browser/simpleServices';
import { SimpleResourcePropertiesService } from 'vs/editor/standalone/browser/simpleServices';
import { IDownloadService } from 'vs/platform/download/common/download';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IExtensionHostDebugParams, IDebugParams } from 'vs/platform/environment/common/environment';
@@ -21,10 +21,7 @@ import { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOper
import { IPager } from 'vs/base/common/paging';
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { ILogService, LogLevel, ConsoleLogService } from 'vs/platform/log/common/log';
import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
@@ -40,7 +37,6 @@ import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IReloadSessionEvent, IExtensionHostDebugService, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug';
@@ -638,23 +634,6 @@ registerSingleton(IExtensionUrlHandler, SimpleExtensionURLHandler, true);
//#endregion
//#region Keybinding
export class SimpleKeybindingService extends StandaloneKeybindingService {
constructor(
@IContextKeyService contextKeyService: IContextKeyService,
@ICommandService commandService: ICommandService,
@ITelemetryService telemetryService: ITelemetryService,
@INotificationService notificationService: INotificationService,
) {
super(contextKeyService, commandService, telemetryService, notificationService, window.document.body);
}
}
registerSingleton(IKeybindingService, SimpleKeybindingService);
//#endregion
//#region Lifecycle
export class SimpleLifecycleService extends AbstractLifecycleService {
+1 -1
View File
@@ -19,7 +19,7 @@ import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/n
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { stat } from 'vs/base/node/pfs';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { webFrame } from 'electron';
import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
+1 -1
View File
@@ -21,7 +21,7 @@ import { IWorkbenchThemeService, VS_HC_THEME } from 'vs/workbench/services/theme
import * as browser from 'vs/base/browser/browser';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IResourceInput } from 'vs/platform/editor/common/editor';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService';
import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions';
@@ -0,0 +1,48 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IKeymapService, IKeyboardLayoutInfo, IKeyboardMapping } from 'vs/workbench/services/keybinding/common/keymapService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig';
import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper';
import { OS, OperatingSystem } from 'vs/base/common/platform';
import { WindowsKeyboardMapper } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper';
import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper';
class BrowserKeymapService extends Disposable implements IKeymapService {
public _serviceBrand: any;
private readonly _onDidChangeKeyboardMapper = new Emitter<void>();
public readonly onDidChangeKeyboardMapper: Event<void> = this._onDidChangeKeyboardMapper.event;
constructor() {
super();
}
getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper {
return this._createKeyboardMapper(dispatchConfig);
}
private _createKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper {
if (OS === OperatingSystem.Windows) {
return new WindowsKeyboardMapper(true, {});
}
// Looks like reading the mappings failed (most likely Mac + Japanese/Chinese keyboard layouts)
return new MacLinuxFallbackKeyboardMapper(OS);
}
public getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null {
return null;
}
public getRawKeyboardMapping(): IKeyboardMapping | null {
return null;
}
}
registerSingleton(IKeymapService, BrowserKeymapService, true);
@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as nativeKeymap from 'native-keymap';
import { release } from 'os';
import * as dom from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { Emitter, Event } from 'vs/base/common/event';
@@ -30,14 +28,12 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { keybindingsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { IUserKeybindingItem, KeybindingIO, OutputBuilder } from 'vs/workbench/services/keybinding/common/keybindingIO';
import { CachedKeyboardMapper, IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper';
import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper';
import { IMacLinuxKeyboardMapping, MacLinuxKeyboardMapper, macLinuxKeyboardMappingEquals } from 'vs/workbench/services/keybinding/common/macLinuxKeyboardMapper';
import { IWindowsKeyboardMapping, WindowsKeyboardMapper, windowsKeyboardMappingEquals } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper';
import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MenuRegistry } from 'vs/platform/actions/common/actions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
// tslint:disable-next-line: import-patterns
import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
@@ -46,121 +42,8 @@ import { IFileService, FileChangesEvent, FileChangeType } from 'vs/platform/file
import { dirname, isEqual } from 'vs/base/common/resources';
import { parse } from 'vs/base/common/json';
import * as objects from 'vs/base/common/objects';
export class KeyboardMapperFactory {
public static readonly INSTANCE = new KeyboardMapperFactory();
private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo | null;
private _rawMapping: nativeKeymap.IKeyboardMapping | null;
private _keyboardMapper: IKeyboardMapper | null;
private _initialized: boolean;
private readonly _onDidChangeKeyboardMapper = new Emitter<void>();
public readonly onDidChangeKeyboardMapper: Event<void> = this._onDidChangeKeyboardMapper.event;
private constructor() {
this._layoutInfo = null;
this._rawMapping = null;
this._keyboardMapper = null;
this._initialized = false;
}
public _onKeyboardLayoutChanged(): void {
if (this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
}
public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper {
if (!this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
if (dispatchConfig === DispatchConfig.KeyCode) {
// Forcefully set to use keyCode
return new MacLinuxFallbackKeyboardMapper(OS);
}
return this._keyboardMapper!;
}
public getCurrentKeyboardLayout(): nativeKeymap.IKeyboardLayoutInfo | null {
if (!this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
return this._layoutInfo;
}
private static _isUSStandard(_kbInfo: nativeKeymap.IKeyboardLayoutInfo): boolean {
if (OS === OperatingSystem.Linux) {
const kbInfo = <nativeKeymap.ILinuxKeyboardLayoutInfo>_kbInfo;
return (kbInfo && kbInfo.layout === 'us');
}
if (OS === OperatingSystem.Macintosh) {
const kbInfo = <nativeKeymap.IMacKeyboardLayoutInfo>_kbInfo;
return (kbInfo && kbInfo.id === 'com.apple.keylayout.US');
}
if (OS === OperatingSystem.Windows) {
const kbInfo = <nativeKeymap.IWindowsKeyboardLayoutInfo>_kbInfo;
return (kbInfo && kbInfo.name === '00000409');
}
return false;
}
public getRawKeyboardMapping(): nativeKeymap.IKeyboardMapping | null {
if (!this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
return this._rawMapping;
}
private _setKeyboardData(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void {
this._layoutInfo = layoutInfo;
if (this._initialized && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) {
// nothing to do...
return;
}
this._initialized = true;
this._rawMapping = rawMapping;
this._keyboardMapper = new CachedKeyboardMapper(
KeyboardMapperFactory._createKeyboardMapper(this._layoutInfo, this._rawMapping)
);
this._onDidChangeKeyboardMapper.fire();
}
private static _createKeyboardMapper(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper {
const isUSStandard = KeyboardMapperFactory._isUSStandard(layoutInfo);
if (OS === OperatingSystem.Windows) {
return new WindowsKeyboardMapper(isUSStandard, <IWindowsKeyboardMapping>rawMapping);
}
if (Object.keys(rawMapping).length === 0) {
// Looks like reading the mappings failed (most likely Mac + Japanese/Chinese keyboard layouts)
return new MacLinuxFallbackKeyboardMapper(OS);
}
if (OS === OperatingSystem.Macintosh) {
const kbInfo = <nativeKeymap.IMacKeyboardLayoutInfo>layoutInfo;
if (kbInfo.id === 'com.apple.keylayout.DVORAK-QWERTYCMD') {
// Use keyCode based dispatching for DVORAK - QWERTY ⌘
return new MacLinuxFallbackKeyboardMapper(OS);
}
}
return new MacLinuxKeyboardMapper(isUSStandard, <IMacLinuxKeyboardMapping>rawMapping, OS);
}
private static _equals(a: nativeKeymap.IKeyboardMapping | null, b: nativeKeymap.IKeyboardMapping | null): boolean {
if (OS === OperatingSystem.Windows) {
return windowsKeyboardMappingEquals(<IWindowsKeyboardMapping>a, <IWindowsKeyboardMapping>b);
}
return macLinuxKeyboardMappingEquals(<IMacLinuxKeyboardMapping>a, <IMacLinuxKeyboardMapping>b);
}
}
import { IKeymapService } from 'vs/workbench/services/keybinding/common/keymapService';
import { getDispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig';
interface ContributedKeyBinding {
command: string;
@@ -257,17 +140,6 @@ const keybindingsExtPoint = ExtensionsRegistry.registerExtensionPoint<Contribute
}
});
export const enum DispatchConfig {
Code,
KeyCode
}
function getDispatchConfig(configurationService: IConfigurationService): DispatchConfig {
const keyboard = configurationService.getValue('keyboard');
const r = (keyboard ? (<any>keyboard).dispatch : null);
return (r === 'keyCode' ? DispatchConfig.KeyCode : DispatchConfig.Code);
}
export class WorkbenchKeybindingService extends AbstractKeybindingService {
private _keyboardMapper: IKeyboardMapper;
@@ -283,7 +155,8 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
@IConfigurationService configurationService: IConfigurationService,
@IWindowService private readonly windowService: IWindowService,
@IExtensionService extensionService: IExtensionService,
@IFileService fileService: IFileService
@IFileService fileService: IFileService,
@IKeymapService private readonly keymapService: IKeymapService
) {
super(contextKeyService, commandService, telemetryService, notificationService);
@@ -297,13 +170,13 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
}
dispatchConfig = newDispatchConfig;
this._keyboardMapper = KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig);
this._keyboardMapper = this.keymapService.getKeyboardMapper(dispatchConfig);
this.updateResolver({ source: KeybindingSource.Default });
});
this._keyboardMapper = KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig);
KeyboardMapperFactory.INSTANCE.onDidChangeKeyboardMapper(() => {
this._keyboardMapper = KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig);
this._keyboardMapper = this.keymapService.getKeyboardMapper(dispatchConfig);
this.keymapService.onDidChangeKeyboardMapper(() => {
this._keyboardMapper = this.keymapService.getKeyboardMapper(dispatchConfig);
this.updateResolver({ source: KeybindingSource.Default });
});
@@ -353,7 +226,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
}));
keybindingsTelemetry(telemetryService, this);
let data = KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout();
let data = this.keymapService.getCurrentKeyboardLayout();
/* __GDPR__
"keyboardLayout" : {
"currentKeyboardLayout": { "${inline}": [ "${IKeyboardLayoutInfo}" ] }
@@ -365,9 +238,9 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
}
public _dumpDebugInfo(): string {
const layoutInfo = JSON.stringify(KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout(), null, '\t');
const layoutInfo = JSON.stringify(this.keymapService.getCurrentKeyboardLayout(), null, '\t');
const mapperInfo = this._keyboardMapper.dumpDebugInfo();
const rawMapping = JSON.stringify(KeyboardMapperFactory.INSTANCE.getRawKeyboardMapping(), null, '\t');
const rawMapping = JSON.stringify(this.keymapService.getRawKeyboardMapping(), null, '\t');
return `Layout info:\n${layoutInfo}\n${mapperInfo}\n\nRaw mapping:\n${rawMapping}`;
}
@@ -559,7 +432,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
}
// consult the KeyboardMapperFactory to check the given event for
// a printable value.
const mapping = KeyboardMapperFactory.INSTANCE.getRawKeyboardMapping();
const mapping = this.keymapService.getRawKeyboardMapping();
if (!mapping) {
return false;
}
@@ -799,13 +672,8 @@ const keyboardConfiguration: IConfigurationNode = {
'default': 'code',
'markdownDescription': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`."),
'included': OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux
},
'keyboard.touchbar.enabled': {
'type': 'boolean',
'default': true,
'description': nls.localize('touchbar.enabled', "Enables the macOS touchbar buttons on the keyboard if available."),
'included': OS === OperatingSystem.Macintosh && parseFloat(release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x)
}
// no touch bar support
}
};
@@ -0,0 +1,17 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export const enum DispatchConfig {
Code,
KeyCode
}
export function getDispatchConfig(configurationService: IConfigurationService): DispatchConfig {
const keyboard = configurationService.getValue('keyboard');
const r = (keyboard ? (<any>keyboard).dispatch : null);
return (r === 'keyCode' ? DispatchConfig.KeyCode : DispatchConfig.Code);
}
@@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig';
import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper';
export interface IWindowsKeyMapping {
vkey: string;
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
}
export interface IWindowsKeyboardMapping {
[code: string]: IWindowsKeyMapping;
}
export interface ILinuxKeyMapping {
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
}
export interface ILinuxKeyboardMapping {
[code: string]: ILinuxKeyMapping;
}
export interface IMacKeyMapping {
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
valueIsDeadKey: boolean;
withShiftIsDeadKey: boolean;
withAltGrIsDeadKey: boolean;
withShiftAltGrIsDeadKey: boolean;
}
export interface IMacKeyboardMapping {
[code: string]: IMacKeyMapping;
}
export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping;
/* __GDPR__FRAGMENT__
"IKeyboardLayoutInfo" : {
"name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"text": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface IWindowsKeyboardLayoutInfo {
name: string;
id: string;
text: string;
}
/* __GDPR__FRAGMENT__
"IKeyboardLayoutInfo" : {
"model" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"layout": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"variant": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"options": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"rules": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface ILinuxKeyboardLayoutInfo {
model: string;
layout: string;
variant: string;
options: string;
rules: string;
}
/* __GDPR__FRAGMENT__
"IKeyboardLayoutInfo" : {
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"lang": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface IMacKeyboardLayoutInfo {
id: string;
lang: string;
}
export type IKeyboardLayoutInfo = IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo;
export const IKeymapService = createDecorator<IKeymapService>('keymapService');
export interface IKeymapService {
_serviceBrand: ServiceIdentifier<any>;
onDidChangeKeyboardMapper: Event<void>;
getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper;
getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null;
getRawKeyboardMapping(): IKeyboardMapping | null;
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { release } from 'os';
import { OS, OperatingSystem } from 'vs/base/common/platform';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigExtensions.Configuration);
const keyboardConfiguration: IConfigurationNode = {
'id': 'keyboard',
'order': 15,
'type': 'object',
'title': nls.localize('keyboardConfigurationTitle', "Keyboard"),
'overridable': true,
'properties': {
'keyboard.dispatch': {
'type': 'string',
'enum': ['code', 'keyCode'],
'default': 'code',
'markdownDescription': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`."),
'included': OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux
},
'keyboard.touchbar.enabled': {
'type': 'boolean',
'default': true,
'description': nls.localize('touchbar.enabled', "Enables the macOS touchbar buttons on the keyboard if available."),
'included': OS === OperatingSystem.Macintosh && parseFloat(release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x)
}
}
};
configurationRegistry.registerConfiguration(keyboardConfiguration);
@@ -0,0 +1,160 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nativeKeymap from 'native-keymap';
import { Disposable } from 'vs/base/common/lifecycle';
import { IKeymapService, IKeyboardLayoutInfo, IKeyboardMapping } from 'vs/workbench/services/keybinding/common/keymapService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IKeyboardMapper, CachedKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper';
import { Emitter, Event } from 'vs/base/common/event';
import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig';
import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper';
import { OS, OperatingSystem } from 'vs/base/common/platform';
import { WindowsKeyboardMapper, windowsKeyboardMappingEquals } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper';
import { MacLinuxKeyboardMapper, macLinuxKeyboardMappingEquals, IMacLinuxKeyboardMapping } from 'vs/workbench/services/keybinding/common/macLinuxKeyboardMapper';
export class KeyboardMapperFactory {
public static readonly INSTANCE = new KeyboardMapperFactory();
private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo | null;
private _rawMapping: nativeKeymap.IKeyboardMapping | null;
private _keyboardMapper: IKeyboardMapper | null;
private _initialized: boolean;
private readonly _onDidChangeKeyboardMapper = new Emitter<void>();
public readonly onDidChangeKeyboardMapper: Event<void> = this._onDidChangeKeyboardMapper.event;
private constructor() {
this._layoutInfo = null;
this._rawMapping = null;
this._keyboardMapper = null;
this._initialized = false;
}
public _onKeyboardLayoutChanged(): void {
if (this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
}
public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper {
if (!this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
if (dispatchConfig === DispatchConfig.KeyCode) {
// Forcefully set to use keyCode
return new MacLinuxFallbackKeyboardMapper(OS);
}
return this._keyboardMapper!;
}
public getCurrentKeyboardLayout(): nativeKeymap.IKeyboardLayoutInfo | null {
if (!this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
return this._layoutInfo;
}
private static _isUSStandard(_kbInfo: nativeKeymap.IKeyboardLayoutInfo): boolean {
if (OS === OperatingSystem.Linux) {
const kbInfo = <nativeKeymap.ILinuxKeyboardLayoutInfo>_kbInfo;
return (kbInfo && kbInfo.layout === 'us');
}
if (OS === OperatingSystem.Macintosh) {
const kbInfo = <nativeKeymap.IMacKeyboardLayoutInfo>_kbInfo;
return (kbInfo && kbInfo.id === 'com.apple.keylayout.US');
}
if (OS === OperatingSystem.Windows) {
const kbInfo = <nativeKeymap.IWindowsKeyboardLayoutInfo>_kbInfo;
return (kbInfo && kbInfo.name === '00000409');
}
return false;
}
public getRawKeyboardMapping(): nativeKeymap.IKeyboardMapping | null {
if (!this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
return this._rawMapping;
}
private _setKeyboardData(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void {
this._layoutInfo = layoutInfo;
if (this._initialized && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) {
// nothing to do...
return;
}
this._initialized = true;
this._rawMapping = rawMapping;
this._keyboardMapper = new CachedKeyboardMapper(
KeyboardMapperFactory._createKeyboardMapper(this._layoutInfo, this._rawMapping)
);
this._onDidChangeKeyboardMapper.fire();
}
private static _createKeyboardMapper(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper {
const isUSStandard = KeyboardMapperFactory._isUSStandard(layoutInfo);
if (OS === OperatingSystem.Windows) {
return new WindowsKeyboardMapper(isUSStandard, <nativeKeymap.IWindowsKeyboardMapping>rawMapping);
}
if (Object.keys(rawMapping).length === 0) {
// Looks like reading the mappings failed (most likely Mac + Japanese/Chinese keyboard layouts)
return new MacLinuxFallbackKeyboardMapper(OS);
}
if (OS === OperatingSystem.Macintosh) {
const kbInfo = <nativeKeymap.IMacKeyboardLayoutInfo>layoutInfo;
if (kbInfo.id === 'com.apple.keylayout.DVORAK-QWERTYCMD') {
// Use keyCode based dispatching for DVORAK - QWERTY ⌘
return new MacLinuxFallbackKeyboardMapper(OS);
}
}
return new MacLinuxKeyboardMapper(isUSStandard, <IMacLinuxKeyboardMapping>rawMapping, OS);
}
private static _equals(a: nativeKeymap.IKeyboardMapping | null, b: nativeKeymap.IKeyboardMapping | null): boolean {
if (OS === OperatingSystem.Windows) {
return windowsKeyboardMappingEquals(<nativeKeymap.IWindowsKeyboardMapping>a, <nativeKeymap.IWindowsKeyboardMapping>b);
}
return macLinuxKeyboardMappingEquals(<IMacLinuxKeyboardMapping>a, <IMacLinuxKeyboardMapping>b);
}
}
class NativeKeymapService extends Disposable implements IKeymapService {
public _serviceBrand: any;
private readonly _onDidChangeKeyboardMapper = new Emitter<void>();
public readonly onDidChangeKeyboardMapper: Event<void> = this._onDidChangeKeyboardMapper.event;
constructor() {
super();
this._register(KeyboardMapperFactory.INSTANCE.onDidChangeKeyboardMapper(() => {
this._onDidChangeKeyboardMapper.fire();
}));
}
getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper {
return KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig);
}
public getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null {
return KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout();
}
public getRawKeyboardMapping(): IKeyboardMapping | null {
return KeyboardMapperFactory.INSTANCE.getRawKeyboardMapping();
}
}
registerSingleton(IKeymapService, NativeKeymapService, true);
+3 -1
View File
@@ -117,7 +117,9 @@ import 'vs/workbench/services/editor/browser/editorService';
import 'vs/workbench/services/history/browser/history';
import 'vs/workbench/services/activity/browser/activityService';
import 'vs/workbench/browser/parts/views/views';
import 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService';
import 'vs/workbench/services/keybinding/electron-browser/keybinding.contribution';
import 'vs/workbench/services/keybinding/browser/keybindingService';
import 'vs/workbench/services/untitled/common/untitledEditorService';
import 'vs/workbench/services/textfile/node/textResourcePropertiesService';
import 'vs/workbench/services/mode/common/workbenchModeService';
+2 -1
View File
@@ -117,7 +117,8 @@ import 'vs/workbench/services/editor/browser/editorService';
import 'vs/workbench/services/history/browser/history';
import 'vs/workbench/services/activity/browser/activityService';
import 'vs/workbench/browser/parts/views/views';
// import 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import 'vs/workbench/services/keybinding/browser/browserKeymapService';
import 'vs/workbench/services/keybinding/browser/keybindingService';
import 'vs/workbench/services/untitled/common/untitledEditorService';
// import 'vs/workbench/services/textfile/node/textResourcePropertiesService';
import 'vs/workbench/services/mode/common/workbenchModeService';