Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/keyboardLayout/common/keyboardLayout.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Event } from '../../../base/common/event.js';
7
import { ScanCode, ScanCodeUtils } from '../../../base/common/keyCodes.js';
8
import { createDecorator } from '../../instantiation/common/instantiation.js';
9
import { IKeyboardEvent } from '../../keybinding/common/keybinding.js';
10
import { IKeyboardMapper } from './keyboardMapper.js';
11
12
export const IKeyboardLayoutService = createDecorator<IKeyboardLayoutService>('keyboardLayoutService');
13
14
export interface IWindowsKeyMapping {
15
vkey: string;
16
value: string;
17
withShift: string;
18
withAltGr: string;
19
withShiftAltGr: string;
20
}
21
export interface IWindowsKeyboardMapping {
22
[code: string]: IWindowsKeyMapping;
23
}
24
export interface ILinuxKeyMapping {
25
value: string;
26
withShift: string;
27
withAltGr: string;
28
withShiftAltGr: string;
29
}
30
export interface ILinuxKeyboardMapping {
31
[code: string]: ILinuxKeyMapping;
32
}
33
export interface IMacKeyMapping {
34
value: string;
35
valueIsDeadKey: boolean;
36
withShift: string;
37
withShiftIsDeadKey: boolean;
38
withAltGr: string;
39
withAltGrIsDeadKey: boolean;
40
withShiftAltGr: string;
41
withShiftAltGrIsDeadKey: boolean;
42
}
43
export interface IMacKeyboardMapping {
44
[code: string]: IMacKeyMapping;
45
}
46
47
export type IMacLinuxKeyMapping = IMacKeyMapping | ILinuxKeyMapping;
48
export type IMacLinuxKeyboardMapping = IMacKeyboardMapping | ILinuxKeyboardMapping;
49
export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping;
50
51
export interface IWindowsKeyboardLayoutInfo {
52
name: string;
53
id: string;
54
text: string;
55
}
56
57
export interface ILinuxKeyboardLayoutInfo {
58
model: string;
59
group: number;
60
layout: string;
61
variant: string;
62
options: string;
63
rules: string;
64
}
65
66
export interface IMacKeyboardLayoutInfo {
67
id: string;
68
lang: string;
69
localizedName?: string;
70
}
71
72
export type IKeyboardLayoutInfo = (IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo) & { isUserKeyboardLayout?: boolean; isUSStandard?: true };
73
74
export interface IKeyboardLayoutService {
75
readonly _serviceBrand: undefined;
76
77
readonly onDidChangeKeyboardLayout: Event<void>;
78
79
getRawKeyboardMapping(): IKeyboardMapping | null;
80
getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null;
81
getAllKeyboardLayouts(): IKeyboardLayoutInfo[];
82
getKeyboardMapper(): IKeyboardMapper;
83
validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void;
84
}
85
86
export function areKeyboardLayoutsEqual(a: IKeyboardLayoutInfo | null, b: IKeyboardLayoutInfo | null): boolean {
87
if (!a || !b) {
88
return false;
89
}
90
91
if ((<IWindowsKeyboardLayoutInfo>a).name && (<IWindowsKeyboardLayoutInfo>b).name && (<IWindowsKeyboardLayoutInfo>a).name === (<IWindowsKeyboardLayoutInfo>b).name) {
92
return true;
93
}
94
95
if ((<IMacKeyboardLayoutInfo>a).id && (<IMacKeyboardLayoutInfo>b).id && (<IMacKeyboardLayoutInfo>a).id === (<IMacKeyboardLayoutInfo>b).id) {
96
return true;
97
}
98
99
if ((<ILinuxKeyboardLayoutInfo>a).model &&
100
(<ILinuxKeyboardLayoutInfo>b).model &&
101
(<ILinuxKeyboardLayoutInfo>a).model === (<ILinuxKeyboardLayoutInfo>b).model &&
102
(<ILinuxKeyboardLayoutInfo>a).layout === (<ILinuxKeyboardLayoutInfo>b).layout
103
) {
104
return true;
105
}
106
107
return false;
108
}
109
110
export function parseKeyboardLayoutDescription(layout: IKeyboardLayoutInfo | null): { label: string; description: string } {
111
if (!layout) {
112
return { label: '', description: '' };
113
}
114
115
if ((<IWindowsKeyboardLayoutInfo>layout).name) {
116
// windows
117
const windowsLayout = <IWindowsKeyboardLayoutInfo>layout;
118
return {
119
label: windowsLayout.text,
120
description: ''
121
};
122
}
123
124
if ((<IMacKeyboardLayoutInfo>layout).id) {
125
const macLayout = <IMacKeyboardLayoutInfo>layout;
126
if (macLayout.localizedName) {
127
return {
128
label: macLayout.localizedName,
129
description: ''
130
};
131
}
132
133
if (/^com\.apple\.keylayout\./.test(macLayout.id)) {
134
return {
135
label: macLayout.id.replace(/^com\.apple\.keylayout\./, '').replace(/-/, ' '),
136
description: ''
137
};
138
}
139
if (/^.*inputmethod\./.test(macLayout.id)) {
140
return {
141
label: macLayout.id.replace(/^.*inputmethod\./, '').replace(/[-\.]/, ' '),
142
description: `Input Method (${macLayout.lang})`
143
};
144
}
145
146
return {
147
label: macLayout.lang,
148
description: ''
149
};
150
}
151
152
const linuxLayout = <ILinuxKeyboardLayoutInfo>layout;
153
154
return {
155
label: linuxLayout.layout,
156
description: ''
157
};
158
}
159
160
export function getKeyboardLayoutId(layout: IKeyboardLayoutInfo): string {
161
if ((<IWindowsKeyboardLayoutInfo>layout).name) {
162
return (<IWindowsKeyboardLayoutInfo>layout).name;
163
}
164
165
if ((<IMacKeyboardLayoutInfo>layout).id) {
166
return (<IMacKeyboardLayoutInfo>layout).id;
167
}
168
169
return (<ILinuxKeyboardLayoutInfo>layout).layout;
170
}
171
172
function windowsKeyMappingEquals(a: IWindowsKeyMapping, b: IWindowsKeyMapping): boolean {
173
if (!a && !b) {
174
return true;
175
}
176
if (!a || !b) {
177
return false;
178
}
179
return (
180
a.vkey === b.vkey
181
&& a.value === b.value
182
&& a.withShift === b.withShift
183
&& a.withAltGr === b.withAltGr
184
&& a.withShiftAltGr === b.withShiftAltGr
185
);
186
}
187
188
export function windowsKeyboardMappingEquals(a: IWindowsKeyboardMapping | null, b: IWindowsKeyboardMapping | null): boolean {
189
if (!a && !b) {
190
return true;
191
}
192
if (!a || !b) {
193
return false;
194
}
195
for (let scanCode = 0; scanCode < ScanCode.MAX_VALUE; scanCode++) {
196
const strScanCode = ScanCodeUtils.toString(scanCode);
197
const aEntry = a[strScanCode];
198
const bEntry = b[strScanCode];
199
if (!windowsKeyMappingEquals(aEntry, bEntry)) {
200
return false;
201
}
202
}
203
return true;
204
}
205
206
function macLinuxKeyMappingEquals(a: IMacLinuxKeyMapping, b: IMacLinuxKeyMapping): boolean {
207
if (!a && !b) {
208
return true;
209
}
210
if (!a || !b) {
211
return false;
212
}
213
return (
214
a.value === b.value
215
&& a.withShift === b.withShift
216
&& a.withAltGr === b.withAltGr
217
&& a.withShiftAltGr === b.withShiftAltGr
218
);
219
}
220
221
export function macLinuxKeyboardMappingEquals(a: IMacLinuxKeyboardMapping | null, b: IMacLinuxKeyboardMapping | null): boolean {
222
if (!a && !b) {
223
return true;
224
}
225
if (!a || !b) {
226
return false;
227
}
228
for (let scanCode = 0; scanCode < ScanCode.MAX_VALUE; scanCode++) {
229
const strScanCode = ScanCodeUtils.toString(scanCode);
230
const aEntry = a[strScanCode];
231
const bEntry = b[strScanCode];
232
if (!macLinuxKeyMappingEquals(aEntry, bEntry)) {
233
return false;
234
}
235
}
236
return true;
237
}
238
239