Path: blob/main/src/vs/platform/keyboardLayout/common/keyboardLayout.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Event } from '../../../base/common/event.js';6import { ScanCode, ScanCodeUtils } from '../../../base/common/keyCodes.js';7import { createDecorator } from '../../instantiation/common/instantiation.js';8import { IKeyboardEvent } from '../../keybinding/common/keybinding.js';9import { IKeyboardMapper } from './keyboardMapper.js';1011export const IKeyboardLayoutService = createDecorator<IKeyboardLayoutService>('keyboardLayoutService');1213export interface IWindowsKeyMapping {14vkey: string;15value: string;16withShift: string;17withAltGr: string;18withShiftAltGr: string;19}20export interface IWindowsKeyboardMapping {21[code: string]: IWindowsKeyMapping;22}23export interface ILinuxKeyMapping {24value: string;25withShift: string;26withAltGr: string;27withShiftAltGr: string;28}29export interface ILinuxKeyboardMapping {30[code: string]: ILinuxKeyMapping;31}32export interface IMacKeyMapping {33value: string;34valueIsDeadKey: boolean;35withShift: string;36withShiftIsDeadKey: boolean;37withAltGr: string;38withAltGrIsDeadKey: boolean;39withShiftAltGr: string;40withShiftAltGrIsDeadKey: boolean;41}42export interface IMacKeyboardMapping {43[code: string]: IMacKeyMapping;44}4546export type IMacLinuxKeyMapping = IMacKeyMapping | ILinuxKeyMapping;47export type IMacLinuxKeyboardMapping = IMacKeyboardMapping | ILinuxKeyboardMapping;48export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping;4950export interface IWindowsKeyboardLayoutInfo {51name: string;52id: string;53text: string;54}5556export interface ILinuxKeyboardLayoutInfo {57model: string;58group: number;59layout: string;60variant: string;61options: string;62rules: string;63}6465export interface IMacKeyboardLayoutInfo {66id: string;67lang: string;68localizedName?: string;69}7071export type IKeyboardLayoutInfo = (IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo) & { isUserKeyboardLayout?: boolean; isUSStandard?: true };7273export interface IKeyboardLayoutService {74readonly _serviceBrand: undefined;7576readonly onDidChangeKeyboardLayout: Event<void>;7778getRawKeyboardMapping(): IKeyboardMapping | null;79getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null;80getAllKeyboardLayouts(): IKeyboardLayoutInfo[];81getKeyboardMapper(): IKeyboardMapper;82validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void;83}8485export function areKeyboardLayoutsEqual(a: IKeyboardLayoutInfo | null, b: IKeyboardLayoutInfo | null): boolean {86if (!a || !b) {87return false;88}8990if ((<IWindowsKeyboardLayoutInfo>a).name && (<IWindowsKeyboardLayoutInfo>b).name && (<IWindowsKeyboardLayoutInfo>a).name === (<IWindowsKeyboardLayoutInfo>b).name) {91return true;92}9394if ((<IMacKeyboardLayoutInfo>a).id && (<IMacKeyboardLayoutInfo>b).id && (<IMacKeyboardLayoutInfo>a).id === (<IMacKeyboardLayoutInfo>b).id) {95return true;96}9798if ((<ILinuxKeyboardLayoutInfo>a).model &&99(<ILinuxKeyboardLayoutInfo>b).model &&100(<ILinuxKeyboardLayoutInfo>a).model === (<ILinuxKeyboardLayoutInfo>b).model &&101(<ILinuxKeyboardLayoutInfo>a).layout === (<ILinuxKeyboardLayoutInfo>b).layout102) {103return true;104}105106return false;107}108109export function parseKeyboardLayoutDescription(layout: IKeyboardLayoutInfo | null): { label: string; description: string } {110if (!layout) {111return { label: '', description: '' };112}113114if ((<IWindowsKeyboardLayoutInfo>layout).name) {115// windows116const windowsLayout = <IWindowsKeyboardLayoutInfo>layout;117return {118label: windowsLayout.text,119description: ''120};121}122123if ((<IMacKeyboardLayoutInfo>layout).id) {124const macLayout = <IMacKeyboardLayoutInfo>layout;125if (macLayout.localizedName) {126return {127label: macLayout.localizedName,128description: ''129};130}131132if (/^com\.apple\.keylayout\./.test(macLayout.id)) {133return {134label: macLayout.id.replace(/^com\.apple\.keylayout\./, '').replace(/-/, ' '),135description: ''136};137}138if (/^.*inputmethod\./.test(macLayout.id)) {139return {140label: macLayout.id.replace(/^.*inputmethod\./, '').replace(/[-\.]/, ' '),141description: `Input Method (${macLayout.lang})`142};143}144145return {146label: macLayout.lang,147description: ''148};149}150151const linuxLayout = <ILinuxKeyboardLayoutInfo>layout;152153return {154label: linuxLayout.layout,155description: ''156};157}158159export function getKeyboardLayoutId(layout: IKeyboardLayoutInfo): string {160if ((<IWindowsKeyboardLayoutInfo>layout).name) {161return (<IWindowsKeyboardLayoutInfo>layout).name;162}163164if ((<IMacKeyboardLayoutInfo>layout).id) {165return (<IMacKeyboardLayoutInfo>layout).id;166}167168return (<ILinuxKeyboardLayoutInfo>layout).layout;169}170171function windowsKeyMappingEquals(a: IWindowsKeyMapping, b: IWindowsKeyMapping): boolean {172if (!a && !b) {173return true;174}175if (!a || !b) {176return false;177}178return (179a.vkey === b.vkey180&& a.value === b.value181&& a.withShift === b.withShift182&& a.withAltGr === b.withAltGr183&& a.withShiftAltGr === b.withShiftAltGr184);185}186187export function windowsKeyboardMappingEquals(a: IWindowsKeyboardMapping | null, b: IWindowsKeyboardMapping | null): boolean {188if (!a && !b) {189return true;190}191if (!a || !b) {192return false;193}194for (let scanCode = 0; scanCode < ScanCode.MAX_VALUE; scanCode++) {195const strScanCode = ScanCodeUtils.toString(scanCode);196const aEntry = a[strScanCode];197const bEntry = b[strScanCode];198if (!windowsKeyMappingEquals(aEntry, bEntry)) {199return false;200}201}202return true;203}204205function macLinuxKeyMappingEquals(a: IMacLinuxKeyMapping, b: IMacLinuxKeyMapping): boolean {206if (!a && !b) {207return true;208}209if (!a || !b) {210return false;211}212return (213a.value === b.value214&& a.withShift === b.withShift215&& a.withAltGr === b.withAltGr216&& a.withShiftAltGr === b.withShiftAltGr217);218}219220export function macLinuxKeyboardMappingEquals(a: IMacLinuxKeyboardMapping | null, b: IMacLinuxKeyboardMapping | null): boolean {221if (!a && !b) {222return true;223}224if (!a || !b) {225return false;226}227for (let scanCode = 0; scanCode < ScanCode.MAX_VALUE; scanCode++) {228const strScanCode = ScanCodeUtils.toString(scanCode);229const aEntry = a[strScanCode];230const bEntry = b[strScanCode];231if (!macLinuxKeyMappingEquals(aEntry, bEntry)) {232return false;233}234}235return true;236}237238239