提交 f502bda8 编写于 作者: A Alex Dima

Try to render keybindings with their physical labels

上级 fd31ff9d
......@@ -35,7 +35,7 @@ var baseModules = [
'https', 'https-proxy-agent', 'iconv-lite', 'ipc', 'menu', 'menu-item', 'net',
'original-fs', 'os', 'path', 'readline', 'remote', 'sax', 'screen', 'semver',
'shell', 'stream', 'string_decoder', 'url', 'vscode-textmate', 'web-frame', 'winreg',
'yauzl'
'yauzl', 'native-keymap'
];
// Build
......
......@@ -439,6 +439,11 @@
}
}
},
"native-keymap": {
"version": "0.0.2",
"from": "native-keymap@0.0.2",
"resolved": "https://registry.npmjs.org/native-keymap/-/native-keymap-0.0.2.tgz"
},
"winreg": {
"version": "0.0.12",
"from": "winreg@0.0.12",
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'native-keymap' {
export interface INativeKeyMap {
key_code: string;
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
}
export function getKeyMap(): INativeKeyMap[];
}
\ No newline at end of file
......@@ -140,7 +140,12 @@ export enum KeyCode {
/**
* For the US standard keyboard, the ''"' key
*/
US_QUOTE
US_QUOTE,
/**
* Placed last to cover the length of the enum.
*/
MAX_VALUE
}
let TO_STRING_MAP: string[] = [];
......@@ -365,15 +370,22 @@ export class Keybinding {
/**
* Format the binding to a format appropiate for rendering in the UI
*/
public static toLabel(value:number): string {
private static _toUSLabel(value:number): string {
return _asString(value, (Platform.isMacintosh ? MacUIKeyLabelProvider.INSTANCE : ClassicUIKeyLabelProvider.INSTANCE));
}
/**
* Format the binding to a format appropiate for rendering in the UI
*/
private static _toCustomLabel(value:number, labelProvider:IKeyBindingLabelProvider): string {
return _asString(value, labelProvider);
}
/**
* This prints the binding in a format suitable for electron's accelerators.
* See https://github.com/atom/electron/blob/master/docs/api/accelerator.md
*/
public static toElectronAccelerator(value:number): string {
private static _toElectronAccelerator(value:number): string {
if (BinaryKeybindings.hasChord(value)) {
// Electron cannot handle chords
return null;
......@@ -426,8 +438,15 @@ export class Keybinding {
/**
* Format the binding to a format appropiate for rendering in the UI
*/
public toLabel(): string {
return Keybinding.toLabel(this.value);
public _toUSLabel(): string {
return Keybinding._toUSLabel(this.value);
}
/**
* Format the binding to a format appropiate for rendering in the UI
*/
public toCustomLabel(labelProvider:IKeyBindingLabelProvider): string {
return Keybinding._toCustomLabel(this.value, labelProvider);
}
/**
......@@ -435,7 +454,7 @@ export class Keybinding {
* See https://github.com/atom/electron/blob/master/docs/api/accelerator.md
*/
public toElectronAccelerator(): string {
return Keybinding.toElectronAccelerator(this.value);
return Keybinding._toElectronAccelerator(this.value);
}
/**
......@@ -447,7 +466,7 @@ export class Keybinding {
}
interface IKeyBindingLabelProvider {
export interface IKeyBindingLabelProvider {
ctrlKeyLabel:string;
shiftKeyLabel:string;
altKeyLabel:string;
......@@ -489,7 +508,7 @@ class ElectronAcceleratorLabelProvider implements IKeyBindingLabelProvider {
/**
* Print for Mac UI
*/
class MacUIKeyLabelProvider implements IKeyBindingLabelProvider {
export class MacUIKeyLabelProvider implements IKeyBindingLabelProvider {
public static INSTANCE = new MacUIKeyLabelProvider();
private static leftArrowUnicodeLabel = String.fromCharCode(8592);
......@@ -523,7 +542,7 @@ class MacUIKeyLabelProvider implements IKeyBindingLabelProvider {
/**
* Print for Windows, Linux UI
*/
class ClassicUIKeyLabelProvider implements IKeyBindingLabelProvider {
export class ClassicUIKeyLabelProvider implements IKeyBindingLabelProvider {
public static INSTANCE = new ClassicUIKeyLabelProvider();
public ctrlKeyLabel = nls.localize('ctrlKey', "Ctrl");
......
......@@ -205,7 +205,7 @@ class ContextMenuController implements EditorCommon.IEditorContribution {
getActionItem: (action) => {
var keybinding = this._keybindingFor(action);
if (keybinding) {
return new ActionBar.ActionItem(action, action, { label: true, keybinding: keybinding.toLabel() });
return new ActionBar.ActionItem(action, action, { label: true, keybinding: this.keybindingService.getLabelFor(keybinding) });
}
var customActionItem = <any>action;
......
......@@ -104,7 +104,7 @@ class DefineKeybindingLauncherWidget implements EditorBrowser.IOverlayWidget {
let keybinding = keybindingService.lookupKeybindings(DefineKeybindingAction.ID);
let extra = '';
if (keybinding.length > 0) {
extra += ' ('+keybinding[0].toLabel()+')';
extra += ' ('+keybindingService.getLabelFor(keybinding[0])+')';
}
this._domNode.appendChild(document.createTextNode(NLS_LAUNCH_MESSAGE + extra));
......
......@@ -113,7 +113,7 @@ export class QuickCommandAction extends EditorQuickOpen.BaseEditorQuickOpenActio
continue; // do not show actions that are not supported in this context
}
var keys = this._keybindingService.lookupKeybindings(editorAction.id).map(k => k.toLabel());
var keys = this._keybindingService.lookupKeybindings(editorAction.id).map(k => this._keybindingService.getLabelFor(k));
if (action.label) {
var highlights = Filters.matchesFuzzy(searchValue, action.label);
......
......@@ -118,6 +118,10 @@ export class AbstractKeybindingService {
this.getContext(this._myContextId).removeValue(key);
}
public getLabelFor(keybinding:Keybinding): string {
throw new Error('Not implemented');
}
public customKeybindingsCount(): number {
throw new Error('Not implemented');
}
......@@ -181,6 +185,10 @@ export class KeybindingService extends AbstractKeybindingService implements IKey
this._toDispose = null;
}
public getLabelFor(keybinding:Keybinding): string {
return keybinding._toUSLabel();
}
protected updateResolver(): void {
this._createOrUpdateResolver(false);
}
......@@ -234,7 +242,7 @@ export class KeybindingService extends AbstractKeybindingService implements IKey
e.preventDefault();
this._currentChord = resolveResult.enterChord;
if (this._messageService) {
let firstPartLabel = Keybinding.toLabel(this._currentChord);
let firstPartLabel = this.getLabelFor(new Keybinding(this._currentChord));
this._currentChordStatusMessage = this._messageService.setStatusMessage(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", firstPartLabel));
}
return;
......@@ -242,8 +250,8 @@ export class KeybindingService extends AbstractKeybindingService implements IKey
if (this._messageService && this._currentChord) {
if (!resolveResult || !resolveResult.commandId) {
let firstPartLabel = Keybinding.toLabel(this._currentChord);
let chordPartLabel = Keybinding.toLabel(e.asKeybinding());
let firstPartLabel = this.getLabelFor(new Keybinding(this._currentChord));
let chordPartLabel = this.getLabelFor(new Keybinding(e.asKeybinding()));
this._messageService.setStatusMessage(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", firstPartLabel, chordPartLabel), 10 * 1000 /* 10s */);
e.preventDefault();
}
......@@ -330,6 +338,10 @@ class ScopedKeybindingService extends AbstractKeybindingService {
this._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR);
}
public getLabelFor(keybinding:Keybinding): string {
return this._parent.getLabelFor(keybinding);
}
public getDefaultKeybindings(): string {
return this._parent.getDefaultKeybindings();
}
......
......@@ -83,6 +83,8 @@ export interface IKeybindingService {
lookupKeybindings(commandId: string): Keybinding[];
customKeybindingsCount(): number;
getLabelFor(keybinding:Keybinding): string;
executeCommand<T>(commandId: string, args?: any): TPromise<T>;
executeCommand(commandId: string, args?: any): TPromise<any>;
}
......@@ -132,7 +132,7 @@ export class ActivitybarPart extends Part implements IActivityService {
let action = this.instantiationService.createInstance(ViewletActivityAction, viewlet.id + '.activity-bar-action', viewlet);
let keybinding: string = null;
let keys = this.keybindingService.lookupKeybindings(viewlet.id).map(k => k.toLabel());
let keys = this.keybindingService.lookupKeybindings(viewlet.id).map(k => this.keybindingService.getLabelFor(k));
if (keys && keys.length) {
keybinding = keys[0];
}
......@@ -202,7 +202,7 @@ export class ActivitybarPart extends Part implements IActivityService {
return actions.map((action: Action) => {
if (primary) {
let keybinding: string = null;
let keys = this.keybindingService.lookupKeybindings(action.id).map(k => k.toLabel());
let keys = this.keybindingService.lookupKeybindings(action.id).map(k => this.keybindingService.getLabelFor(k));
if (keys && keys.length) {
keybinding = keys[0];
}
......
......@@ -367,7 +367,7 @@ export class SidebarPart extends Part implements IViewletService {
}
let keybinding: string = null;
let keys = this.keybindingService.lookupKeybindings(viewletId).map(k => k.toLabel());
let keys = this.keybindingService.lookupKeybindings(viewletId).map(k => this.keybindingService.getLabelFor(k));
if (keys && keys.length) {
keybinding = keys[0];
}
......
......@@ -41,7 +41,7 @@ import {ConfigurationService} from 'vs/workbench/services/configuration/node/con
import {FileService} from 'vs/workbench/services/files/electron-browser/fileService';
import {SearchService} from 'vs/workbench/services/search/node/searchService';
import {LifecycleService} from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService';
import PluginWorkbenchKeybindingService from 'vs/workbench/services/keybinding/browser/pluginKeybindingService';
import PluginWorkbenchKeybindingService from 'vs/workbench/services/keybinding/electron-browser/pluginKeybindingService';
import {MainThreadService} from 'vs/workbench/services/thread/electron-browser/threadService';
import {MarkerService} from 'vs/platform/markers/common/markerService';
import {IActionsService} from 'vs/platform/actions/common/actions';
......
......@@ -38,7 +38,7 @@ export class AbstractDebugAction extends actions.Action {
this.toDispose.push(this.debugService.addListener2(debug.ServiceEvents.STATE_CHANGED, () => this.updateEnablement()));
var keybinding: string = null;
var keys = this.keybindingService.lookupKeybindings(id).map(k => k.toLabel());
var keys = this.keybindingService.lookupKeybindings(id).map(k => this.keybindingService.getLabelFor(k));
if (keys && keys.length) {
keybinding = keys[0];
}
......
......@@ -19,6 +19,7 @@ import {DerivedFrameEditorInput} from 'vs/workbench/parts/files/browser/editors/
import {KeybindingsUtils} from 'vs/platform/keybinding/common/keybindingsUtils';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {FileStat} from 'vs/workbench/parts/files/browser/views/explorerViewModel';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
......@@ -28,7 +29,8 @@ class FilesViewerActionContributor extends ActionBarContributor {
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IKeybindingService private keybindingService: IKeybindingService
) {
super();
}
......@@ -130,7 +132,7 @@ class FilesViewerActionContributor extends ActionBarContributor {
// Any other item with keybinding
let keybinding = keybindingForAction(action.id);
if (keybinding) {
return new ActionItem(context, action, { label: true, keybinding: keybinding.toLabel() });
return new ActionItem(context, action, { label: true, keybinding: this.keybindingService.getLabelFor(keybinding) });
}
}
......
......@@ -241,7 +241,7 @@ export class CommandsHandler extends QuickOpenHandler {
for (let i = 0; i < actionDescriptors.length; i++) {
let actionDescriptor = actionDescriptors[i];
let keys = this.keybindingService.lookupKeybindings(actionDescriptor.id).map(k => k.toLabel());
let keys = this.keybindingService.lookupKeybindings(actionDescriptor.id).map(k => this.keybindingService.getLabelFor(k));
if (actionDescriptor.label) {
let label = actionDescriptor.label;
......@@ -272,7 +272,7 @@ export class CommandsHandler extends QuickOpenHandler {
continue; // do not show actions that are not supported in this context
}
let keys = this.keybindingService.lookupKeybindings(editorAction.id).map(k => k.toLabel());
let keys = this.keybindingService.lookupKeybindings(editorAction.id).map(k => this.keybindingService.getLabelFor(k));
if (action.label) {
let highlights = filters.matchesFuzzy(searchValue, action.label);
......@@ -289,7 +289,7 @@ export class CommandsHandler extends QuickOpenHandler {
let entries: ActionCommandEntry[] = [];
for (let action of actions) {
let keys = this.keybindingService.lookupKeybindings(action.id).map(k => k.toLabel());
let keys = this.keybindingService.lookupKeybindings(action.id).map(k => this.keybindingService.getLabelFor(k));
let highlights = filters.matchesFuzzy(searchValue, action.label);
if (highlights) {
entries.push(this.instantiationService.createInstance(ActionCommandEntry, keys.join(', '), action.label, highlights, action));
......
......@@ -16,7 +16,7 @@ import {IOSupport} from 'vs/platform/keybinding/common/commonKeybindingResolver'
import * as JSONContributionRegistry from 'vs/languages/json/common/jsonContributionRegistry';
import {IJSONSchema} from 'vs/base/common/jsonSchema';
export class WorkbenchKeybindingService extends KeybindingService {
export abstract class WorkbenchKeybindingService extends KeybindingService {
private contextService: IWorkspaceContextService;
private eventService: IEventService;
private telemetryService: ITelemetryService;
......
......@@ -13,10 +13,13 @@ import {IKeybindingItem, IUserFriendlyKeybinding, ICommandHandler} from 'vs/plat
import {PluginsRegistry, IMessageCollector} from 'vs/platform/plugins/common/pluginsRegistry';
import {IPluginService, IPluginDescription, IPointListener, IActivationEventListener} from 'vs/platform/plugins/common/plugins';
import {IOSupport} from 'vs/platform/keybinding/common/commonKeybindingResolver';
import {WorkbenchKeybindingService} from './keybindingService';
import {WorkbenchKeybindingService} from 'vs/workbench/services/keybinding/browser/keybindingService';
import {ICommandDescriptor, ICommandRule, KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry';
import {IMessageService, Severity} from 'vs/platform/message/common/message';
import {IJSONSchema} from 'vs/base/common/jsonSchema';
import {KeyCode, Keybinding, IKeyBindingLabelProvider, MacUIKeyLabelProvider, ClassicUIKeyLabelProvider} from 'vs/base/common/keyCodes';
import * as nativeKeymap from 'native-keymap';
import Platform = require('vs/base/common/platform');
interface ContributedKeyBinding {
command: string;
......@@ -130,6 +133,11 @@ export default class PluginWorkbenchKeybindingService extends WorkbenchKeybindin
this._pluginService = pluginService;
}
public getLabelFor(keybinding:Keybinding): string {
this._ensureNativeKeymap();
return keybinding.toCustomLabel(this._nativeLabelProvider);
}
private _handleKeybindingsExtensionPointUser(isBuiltin: boolean, keybindings:ContributedKeyBinding | ContributedKeyBinding[], collector:IMessageCollector): boolean {
if (isContributedKeyBindingsArray(keybindings)) {
let commandAdded = false;
......@@ -200,4 +208,80 @@ export default class PluginWorkbenchKeybindingService extends WorkbenchKeybindin
return desc;
}
}
\ No newline at end of file
private _gotNativeKeymap = false;
private _nativeLabelProvider:IKeyBindingLabelProvider = null;
private _ensureNativeKeymap(): void {
if (this._gotNativeKeymap) {
return;
}
this._gotNativeKeymap = true;
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
// See https://github.com/alexandrudima/vscode-keyboard/blob/master/deps/chromium/keyboard_codes_win.h
let interesting = {
VKEY_OEM_1: KeyCode.US_SEMICOLON, // (0xBA) as ;
VKEY_OEM_PLUS: KeyCode.US_EQUAL, // (0xBB) as =
VKEY_OEM_COMMA: KeyCode.US_COMMA, // (0xBC) as ,
VKEY_OEM_MINUS: KeyCode.US_MINUS, // (0xBD) as -
VKEY_OEM_PERIOD: KeyCode.US_DOT, // (0xBE) as .
VKEY_OEM_2: KeyCode.US_SLASH, // (0xBF) as /
VKEY_OEM_3: KeyCode.US_BACKTICK, // (0xC0) as `
VKEY_OEM_4: KeyCode.US_OPEN_SQUARE_BRACKET, // (0xDB) as [
VKEY_OEM_5: KeyCode.US_BACKSLASH, // (0xDC) as \
VKEY_OEM_6: KeyCode.US_CLOSE_SQUARE_BRACKET, // (0xDD) as ]
VKEY_OEM_7: KeyCode.US_QUOTE, // (0xDE) as '
};
let remaps:string[] = [];
for (let i = 0, len = KeyCode.MAX_VALUE; i < len; i++) {
remaps[i] = null;
}
let nativeMappings = nativeKeymap.getKeyMap();
for (let i = 0, len = nativeMappings.length; i < len; i++) {
let nativeMapping = nativeMappings[i];
if (interesting[nativeMapping.key_code]) {
let newValue = nativeMapping.value || nativeMapping.withShift;
if (newValue.length > 0) {
remaps[interesting[nativeMapping.key_code]] = newValue;
} else {
// console.warn('invalid remap for ', nativeMapping);
}
}
}
if (Platform.isMacintosh) {
this._nativeLabelProvider = new NativeMacUIKeyLabelProvider(remaps)
} else {
this._nativeLabelProvider = new NativeClassicUIKeyLabelProvider(remaps);
}
}
}
class NativeMacUIKeyLabelProvider extends MacUIKeyLabelProvider {
constructor(private remaps:string[]) {
super();
}
public getLabelForKey(keyCode:KeyCode): string {
if (this.remaps[keyCode]) {
return this.remaps[keyCode];
}
return super.getLabelForKey(keyCode);
}
}
class NativeClassicUIKeyLabelProvider extends ClassicUIKeyLabelProvider {
constructor(private remaps:string[]) {
super();
}
public getLabelForKey(keyCode:KeyCode): string {
if (this.remaps[keyCode]) {
return this.remaps[keyCode];
}
return super.getLabelForKey(keyCode);
}
}
......@@ -159,6 +159,10 @@ export class TestKeybindingService implements IKeybindingService {
return null;
}
public getLabelFor(keybinding:Keybinding): string {
return keybinding._toUSLabel();
}
public createScoped(domNode: HTMLElement): IKeybindingService {
return this;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册