@vscodium/native-keymap 3.3.7-258412

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.nvmrc +1 -0
  2. package/.release-it.yml +8 -0
  3. package/LICENSE +22 -0
  4. package/README.md +82 -0
  5. package/ThirdPartyNotices.txt +42 -0
  6. package/binding.gyp +92 -0
  7. package/collected-artifacts/native-keymap-darwin-arm64/native-keymap-3.3.7-258412-darwin-arm64.tar.gz +0 -0
  8. package/collected-artifacts/native-keymap-darwin-arm64/native-keymap-3.3.7-258412-darwin-arm64.tar.gz.sha256 +1 -0
  9. package/collected-artifacts/native-keymap-darwin-x64/native-keymap-3.3.7-258412-darwin-x64.tar.gz +0 -0
  10. package/collected-artifacts/native-keymap-darwin-x64/native-keymap-3.3.7-258412-darwin-x64.tar.gz.sha256 +1 -0
  11. package/collected-artifacts/native-keymap-linux-arm64/native-keymap-3.3.7-258412-linux-arm64.tar.gz +0 -0
  12. package/collected-artifacts/native-keymap-linux-arm64/native-keymap-3.3.7-258412-linux-arm64.tar.gz.sha256 +1 -0
  13. package/collected-artifacts/native-keymap-linux-armhf/native-keymap-3.3.7-258412-linux-armhf.tar.gz +0 -0
  14. package/collected-artifacts/native-keymap-linux-armhf/native-keymap-3.3.7-258412-linux-armhf.tar.gz.sha256 +1 -0
  15. package/collected-artifacts/native-keymap-linux-loong64/native-keymap-3.3.7-258412-linux-loong64.tar.gz +0 -0
  16. package/collected-artifacts/native-keymap-linux-loong64/native-keymap-3.3.7-258412-linux-loong64.tar.gz.sha256 +1 -0
  17. package/collected-artifacts/native-keymap-linux-ppc64le/native-keymap-3.3.7-258412-linux-ppc64le.tar.gz +0 -0
  18. package/collected-artifacts/native-keymap-linux-ppc64le/native-keymap-3.3.7-258412-linux-ppc64le.tar.gz.sha256 +1 -0
  19. package/collected-artifacts/native-keymap-linux-riscv64/native-keymap-3.3.7-258412-linux-riscv64.tar.gz +0 -0
  20. package/collected-artifacts/native-keymap-linux-riscv64/native-keymap-3.3.7-258412-linux-riscv64.tar.gz.sha256 +1 -0
  21. package/collected-artifacts/native-keymap-linux-s390x/native-keymap-3.3.7-258412-linux-s390x.tar.gz +0 -0
  22. package/collected-artifacts/native-keymap-linux-s390x/native-keymap-3.3.7-258412-linux-s390x.tar.gz.sha256 +1 -0
  23. package/collected-artifacts/native-keymap-linux-x64/native-keymap-3.3.7-258412-linux-x64.tar.gz +0 -0
  24. package/collected-artifacts/native-keymap-linux-x64/native-keymap-3.3.7-258412-linux-x64.tar.gz.sha256 +1 -0
  25. package/collected-artifacts/native-keymap-win32-arm64/native-keymap-3.3.7-258412-win32-arm64.tar.gz +0 -0
  26. package/collected-artifacts/native-keymap-win32-arm64/native-keymap-3.3.7-258412-win32-arm64.tar.gz.sha256 +1 -0
  27. package/collected-artifacts/native-keymap-win32-x64/native-keymap-3.3.7-258412-win32-x64.tar.gz +0 -0
  28. package/collected-artifacts/native-keymap-win32-x64/native-keymap-3.3.7-258412-win32-x64.tar.gz.sha256 +1 -0
  29. package/deps/chromium/dom_code_data.inc +618 -0
  30. package/deps/chromium/keyboard_codes.h +23 -0
  31. package/deps/chromium/macros.h +32 -0
  32. package/deps/chromium/x/keysym_to_unicode.cc +896 -0
  33. package/deps/chromium/x/keysym_to_unicode.h +26 -0
  34. package/index.d.ts +70 -0
  35. package/index.js +70 -0
  36. package/package.json +25 -0
  37. package/release/native-keymap-3.3.7-258412-darwin-arm64.tar.gz +0 -0
  38. package/release/native-keymap-3.3.7-258412-darwin-arm64.tar.gz.sha256 +1 -0
  39. package/release/native-keymap-3.3.7-258412-darwin-x64.tar.gz +0 -0
  40. package/release/native-keymap-3.3.7-258412-darwin-x64.tar.gz.sha256 +1 -0
  41. package/release/native-keymap-3.3.7-258412-linux-arm64.tar.gz +0 -0
  42. package/release/native-keymap-3.3.7-258412-linux-arm64.tar.gz.sha256 +1 -0
  43. package/release/native-keymap-3.3.7-258412-linux-armhf.tar.gz +0 -0
  44. package/release/native-keymap-3.3.7-258412-linux-armhf.tar.gz.sha256 +1 -0
  45. package/release/native-keymap-3.3.7-258412-linux-loong64.tar.gz +0 -0
  46. package/release/native-keymap-3.3.7-258412-linux-loong64.tar.gz.sha256 +1 -0
  47. package/release/native-keymap-3.3.7-258412-linux-ppc64le.tar.gz +0 -0
  48. package/release/native-keymap-3.3.7-258412-linux-ppc64le.tar.gz.sha256 +1 -0
  49. package/release/native-keymap-3.3.7-258412-linux-riscv64.tar.gz +0 -0
  50. package/release/native-keymap-3.3.7-258412-linux-riscv64.tar.gz.sha256 +1 -0
  51. package/release/native-keymap-3.3.7-258412-linux-s390x.tar.gz +0 -0
  52. package/release/native-keymap-3.3.7-258412-linux-s390x.tar.gz.sha256 +1 -0
  53. package/release/native-keymap-3.3.7-258412-linux-x64.tar.gz +0 -0
  54. package/release/native-keymap-3.3.7-258412-linux-x64.tar.gz.sha256 +1 -0
  55. package/release/native-keymap-3.3.7-258412-win32-arm64.tar.gz +0 -0
  56. package/release/native-keymap-3.3.7-258412-win32-arm64.tar.gz.sha256 +1 -0
  57. package/release/native-keymap-3.3.7-258412-win32-x64.tar.gz +0 -0
  58. package/release/native-keymap-3.3.7-258412-win32-x64.tar.gz.sha256 +1 -0
  59. package/src/common.h +92 -0
  60. package/src/keyboard_mac.mm +209 -0
  61. package/src/keyboard_win.cc +476 -0
  62. package/src/keyboard_x.cc +407 -0
  63. package/src/keymapping.cc +147 -0
  64. package/src/keymapping.h +65 -0
  65. package/src/string_conversion.cc +67 -0
  66. package/src/string_conversion.h +18 -0
@@ -0,0 +1,407 @@
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
+ #include "keymapping.h"
7
+ #include "string_conversion.h"
8
+ #include "common.h"
9
+
10
+ #include <X11/XKBlib.h>
11
+ #include <X11/Xlib.h>
12
+ #include <X11/Xutil.h>
13
+ #include <X11/extensions/XKBrules.h>
14
+
15
+ #include "../deps/chromium/macros.h"
16
+ #include "../deps/chromium/x/keysym_to_unicode.h"
17
+
18
+ typedef struct _XDisplay XDisplay;
19
+
20
+ namespace {
21
+
22
+ class KeyModifierMaskToXModifierMask {
23
+ public:
24
+ static KeyModifierMaskToXModifierMask& GetInstance() {
25
+ static KeyModifierMaskToXModifierMask instance;
26
+ return instance;
27
+ }
28
+
29
+ void Initialize(Display* display) {
30
+ alt_modifier_ = 0;
31
+ meta_modifier_ = 0;
32
+ num_lock_modifier_ = 0;
33
+ mode_switch_modifier_ = 0;
34
+ level3_modifier_ = 0; // AltGr is often mapped to the level3 modifier
35
+ level5_modifier_ = 0; // AltGr is mapped to the level5 modifier in the Neo layout family
36
+ effective_group_index_ = 0;
37
+
38
+ if (!display) {
39
+ return;
40
+ }
41
+
42
+ // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#determining_keyboard_state
43
+ XkbStateRec xkb_state;
44
+ XkbGetState(display, XkbUseCoreKbd, &xkb_state);
45
+ effective_group_index_ = xkb_state.group;
46
+
47
+ XModifierKeymap* mod_map = XGetModifierMapping(display);
48
+ int max_mod_keys = mod_map->max_keypermod;
49
+ for (int mod_index = 0; mod_index <= 8; ++mod_index) {
50
+ for (int key_index = 0; key_index < max_mod_keys; ++key_index) {
51
+ int key = mod_map->modifiermap[mod_index * max_mod_keys + key_index];
52
+ if (!key) {
53
+ continue;
54
+ }
55
+
56
+ int keysym = XkbKeycodeToKeysym(display, key, 0, 0);
57
+ if (!keysym) {
58
+ continue;
59
+ }
60
+
61
+ if (keysym == XK_Alt_L || keysym == XK_Alt_R) {
62
+ alt_modifier_ = 1 << mod_index;
63
+ }
64
+ if (keysym == XK_Mode_switch) {
65
+ mode_switch_modifier_ = 1 << mod_index;
66
+ }
67
+ if (keysym == XK_Meta_L || keysym == XK_Super_L || keysym == XK_Meta_R || keysym == XK_Super_R) {
68
+ meta_modifier_ = 1 << mod_index;
69
+ }
70
+ if (keysym == XK_Num_Lock) {
71
+ num_lock_modifier_ = 1 << mod_index;
72
+ }
73
+ if (keysym == XK_ISO_Level3_Shift) {
74
+ level3_modifier_ = 1 << mod_index;
75
+ }
76
+ if (keysym == XK_ISO_Level5_Shift) {
77
+ level5_modifier_ = 1 << mod_index;
78
+ }
79
+ }
80
+ }
81
+
82
+ XFreeModifiermap(mod_map);
83
+ }
84
+
85
+ int XStateFromKeyMod(int keyMod) {
86
+ int x_modifier = 0;
87
+
88
+ // Ctrl + Alt => AltGr
89
+ if (keyMod & kControlKeyModifierMask && keyMod & kAltKeyModifierMask) {
90
+ x_modifier |= mode_switch_modifier_;//alt_r_modifier;
91
+ } else if (keyMod & kControlKeyModifierMask) {
92
+ x_modifier |= ControlMask;
93
+ } else if (keyMod & kAltKeyModifierMask) {
94
+ x_modifier |= alt_modifier_;
95
+ }
96
+
97
+ if (keyMod & kShiftKeyModifierMask) {
98
+ x_modifier |= ShiftMask;
99
+ }
100
+
101
+ if (keyMod & kMetaKeyModifierMask) {
102
+ x_modifier |= meta_modifier_;
103
+ }
104
+
105
+ if (keyMod & kNumLockKeyModifierMask) {
106
+ x_modifier |= num_lock_modifier_;
107
+ }
108
+
109
+ if (keyMod & kLevel3KeyModifierMask) {
110
+ x_modifier |= level3_modifier_;
111
+ }
112
+
113
+ if (keyMod & kLevel5KeyModifierMask) {
114
+ x_modifier |= level5_modifier_;
115
+ }
116
+
117
+ // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#xkb_state_to_core_protocol_state_transformation
118
+ x_modifier |= (effective_group_index_ << 13);
119
+
120
+ return x_modifier;
121
+ }
122
+
123
+ private:
124
+ KeyModifierMaskToXModifierMask() {
125
+ Initialize(NULL);
126
+ }
127
+
128
+ int alt_modifier_;
129
+ int meta_modifier_;
130
+ int num_lock_modifier_;
131
+ int mode_switch_modifier_;
132
+ int level3_modifier_;
133
+ int level5_modifier_;
134
+ int effective_group_index_;
135
+
136
+ KeyModifierMaskToXModifierMask(const KeyModifierMaskToXModifierMask&) = delete;
137
+ KeyModifierMaskToXModifierMask& operator=(const KeyModifierMaskToXModifierMask&) = delete;
138
+ };
139
+
140
+ std::string GetStrFromXEvent(const XEvent* xev) {
141
+ const XKeyEvent* xkey = &xev->xkey;
142
+ KeySym keysym = XK_VoidSymbol;
143
+ XLookupString(const_cast<XKeyEvent*>(xkey), NULL, 0, &keysym, NULL);
144
+ uint16_t character = ui::GetUnicodeCharacterFromXKeySym(keysym);
145
+
146
+ if (!character)
147
+ return std::string();
148
+
149
+ wchar_t value = character;
150
+
151
+ return vscode_keyboard::UTF16toUTF8(&value, 1);
152
+ }
153
+
154
+ } // namespace
155
+
156
+
157
+ namespace vscode_keyboard {
158
+
159
+ #define DOM_CODE(usb, evdev, xkb, win, mac, code, id) {usb, xkb, code}
160
+ #define DOM_CODE_DECLARATION const KeycodeMapEntry usb_keycode_map[] =
161
+ #include "../deps/chromium/dom_code_data.inc"
162
+ #undef DOM_CODE
163
+ #undef DOM_CODE_DECLARATION
164
+
165
+ napi_value GetKeyMapImpl(napi_env env, napi_callback_info info) {
166
+
167
+ napi_value result;
168
+ NAPI_CALL(env, napi_create_object(env, &result));
169
+
170
+ Display *display;
171
+ if (!(display = XOpenDisplay(""))) {
172
+ return result;
173
+ }
174
+
175
+ XEvent event;
176
+ memset(&event, 0, sizeof(XEvent));
177
+ XKeyEvent* key_event = &event.xkey;
178
+ key_event->display = display;
179
+ key_event->type = KeyPress;
180
+
181
+ KeyModifierMaskToXModifierMask *mask_provider = &KeyModifierMaskToXModifierMask::GetInstance();
182
+ mask_provider->Initialize(display);
183
+
184
+ size_t cnt = sizeof(usb_keycode_map) / sizeof(usb_keycode_map[0]);
185
+
186
+ for (size_t i = 0; i < cnt; ++i) {
187
+ const char *code = usb_keycode_map[i].code;
188
+ int native_keycode = usb_keycode_map[i].native_keycode;
189
+
190
+ if (!code || native_keycode <= 0) {
191
+ continue;
192
+ }
193
+
194
+ napi_value entry;
195
+ NAPI_CALL(env, napi_create_object(env, &entry));
196
+
197
+ key_event->keycode = native_keycode;
198
+ {
199
+ key_event->state = mask_provider->XStateFromKeyMod(0);
200
+ std::string value = GetStrFromXEvent(&event);
201
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "value", value.c_str()));
202
+ }
203
+
204
+ {
205
+ key_event->state = mask_provider->XStateFromKeyMod(kShiftKeyModifierMask);
206
+ std::string with_shift = GetStrFromXEvent(&event);
207
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShift", with_shift.c_str()));
208
+ }
209
+
210
+ {
211
+ key_event->state = mask_provider->XStateFromKeyMod(kLevel3KeyModifierMask);
212
+ std::string with_alt_gr = GetStrFromXEvent(&event);
213
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withAltGr", with_alt_gr.c_str()));
214
+ }
215
+
216
+ {
217
+ key_event->state = mask_provider->XStateFromKeyMod(kShiftKeyModifierMask | kLevel3KeyModifierMask);
218
+ std::string with_shift_alt_gr = GetStrFromXEvent(&event);
219
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShiftAltGr", with_shift_alt_gr.c_str()));
220
+ }
221
+
222
+ {
223
+ // level 5 is important for the Neo layout family
224
+ key_event->state = mask_provider->XStateFromKeyMod(kLevel5KeyModifierMask);
225
+ std::string with_level5 = GetStrFromXEvent(&event);
226
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withLevel5", with_level5.c_str()));
227
+ }
228
+
229
+ {
230
+ // level3 + level5 is Level 6 in terms of the Neo layout family. (Shift + level5 has no special meaning.)
231
+ key_event->state = mask_provider->XStateFromKeyMod(kLevel3KeyModifierMask | kLevel5KeyModifierMask);
232
+ std::string with_level3_level5 = GetStrFromXEvent(&event);
233
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withLevel3Level5", with_level3_level5.c_str()));
234
+ }
235
+
236
+ NAPI_CALL(env, napi_set_named_property(env, result, code, entry));
237
+ }
238
+
239
+ XFlush(display);
240
+ XCloseDisplay(display);
241
+
242
+ return result;
243
+ }
244
+
245
+ napi_value GetCurrentKeyboardLayoutImpl(napi_env env, napi_callback_info info) {
246
+
247
+ napi_value result;
248
+ NAPI_CALL(env, napi_get_null(env, &result));
249
+
250
+ Display *display;
251
+ if (!(display = XOpenDisplay(""))) {
252
+ return result;
253
+ }
254
+
255
+ // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#determining_keyboard_state
256
+ XkbStateRec xkb_state;
257
+ XkbGetState(display, XkbUseCoreKbd, &xkb_state);
258
+ int effective_group_index = xkb_state.group;
259
+
260
+ XkbRF_VarDefsRec vdr;
261
+ char *tmp = NULL;
262
+ int res = XkbRF_GetNamesProp(display, &tmp, &vdr);
263
+ if (res) {
264
+ NAPI_CALL(env, napi_create_object(env, &result));
265
+
266
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "model", vdr.model ? vdr.model : ""));
267
+ NAPI_CALL(env, napi_set_named_property_int32(env, result, "group", effective_group_index));
268
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "layout", vdr.layout ? vdr.layout : ""));
269
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "variant", vdr.variant ? vdr.variant : ""));
270
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "options", vdr.options ? vdr.options : ""));
271
+ NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "rules", tmp ? tmp : ""));
272
+ }
273
+
274
+ XFlush(display);
275
+ XCloseDisplay(display);
276
+ return result;
277
+ }
278
+
279
+ typedef struct {
280
+ int effective_group_index;
281
+ std::string layout;
282
+ std::string variant;
283
+ } KbState;
284
+
285
+ bool KbStatesEqual(KbState *a, KbState *b) {
286
+ return (
287
+ a->effective_group_index == b->effective_group_index
288
+ && a->layout == b->layout
289
+ && a->variant == b->variant
290
+ );
291
+ }
292
+
293
+ void ReadKbState(Display *display, KbState *dst) {
294
+ // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#determining_keyboard_state
295
+ // Get effective group index
296
+ XkbStateRec xkb_state;
297
+ XkbGetState(display, XkbUseCoreKbd, &xkb_state);
298
+ dst->effective_group_index = xkb_state.group;
299
+
300
+ XkbRF_VarDefsRec vdr;
301
+ char *tmp = NULL;
302
+ int res = XkbRF_GetNamesProp(display, &tmp, &vdr);
303
+ if (res) {
304
+ dst->layout = (vdr.layout ? vdr.layout : "");
305
+ dst->variant = (vdr.variant ? vdr.variant : "");
306
+ } else {
307
+ dst->layout = "";
308
+ dst->variant = "";
309
+ }
310
+ }
311
+
312
+ static void FlushAndCloseDisplay(void *arg) {
313
+ Display *display = static_cast<Display*>(arg);
314
+ XFlush(display);
315
+ XCloseDisplay(display);
316
+ }
317
+
318
+ void* ListenToXEvents(void *arg) {
319
+ NotificationCallbackData *data = static_cast<NotificationCallbackData*>(arg);
320
+
321
+ Display *display;
322
+ if (!(display = XOpenDisplay(""))) {
323
+ return NULL;
324
+ }
325
+
326
+ pthread_cleanup_push(FlushAndCloseDisplay, display);
327
+
328
+ int xkblib_major = XkbMajorVersion;
329
+ int xkblib_minor = XkbMinorVersion;
330
+ if (!XkbLibraryVersion(&xkblib_major, &xkblib_minor)) {
331
+ return NULL;
332
+ }
333
+
334
+ int opcode = 0;
335
+ int xkb_base_event_code = 0;
336
+ int xkb_base_error_code = 0;
337
+ if (!XkbQueryExtension(display, &opcode, &xkb_base_event_code, &xkb_base_error_code, &xkblib_major, &xkblib_minor)) {
338
+ return NULL;
339
+ }
340
+
341
+ // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#xkb_event_types
342
+ // Listen only to the `XkbStateNotify` event
343
+ XkbSelectEvents(display, XkbUseCoreKbd, XkbAllEventsMask, XkbStateNotifyMask);
344
+
345
+ KbState last_state;
346
+ ReadKbState(display, &last_state);
347
+
348
+ XkbEvent event;
349
+ KbState current_state;
350
+ fd_set in_fds;
351
+ struct timeval tv;
352
+ int x11_fd = ConnectionNumber(display);
353
+
354
+ while (true) {
355
+ // See https://stackoverflow.com/a/8592969 which explains
356
+ // the technique of waiting for an XEvent with a timeout
357
+
358
+ // Create a File Description Set containing x11_fd
359
+ FD_ZERO(&in_fds);
360
+ FD_SET(x11_fd, &in_fds);
361
+
362
+ // Set the timer to 1s.
363
+ tv.tv_usec = 0;
364
+ tv.tv_sec = 1;
365
+
366
+ // Wait for X Event or the timer
367
+ select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
368
+
369
+ // Handle pending XEvents
370
+ while (XPending(display)) {
371
+
372
+ XNextEvent(display, &event.core);
373
+
374
+ if (event.type == xkb_base_event_code && event.any.xkb_type == XkbStateNotify) {
375
+ ReadKbState(display, &current_state);
376
+ // printf("current state: %d | %s | %s\n", current_state.effective_group_index, current_state.layout.c_str(), current_state.variant.c_str());
377
+ if (!KbStatesEqual(&last_state, &current_state)) {
378
+ last_state.effective_group_index = current_state.effective_group_index;
379
+ last_state.layout = current_state.layout;
380
+ last_state.variant = current_state.variant;
381
+
382
+ InvokeNotificationCallback(data);
383
+ }
384
+ }
385
+ }
386
+ }
387
+
388
+ pthread_cleanup_pop(1);
389
+
390
+ return NULL;
391
+ }
392
+
393
+ void RegisterKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) {
394
+ pthread_create(&data->tid, NULL, &ListenToXEvents, data);
395
+ }
396
+
397
+ void DisposeKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) {
398
+ pthread_cancel(data->tid);
399
+ void *res;
400
+ pthread_join(data->tid, &res);
401
+ }
402
+
403
+ napi_value IsISOKeyboardImpl(napi_env env, napi_callback_info info) {
404
+ return napi_fetch_undefined(env);
405
+ }
406
+
407
+ } // namespace vscode_keyboard
@@ -0,0 +1,147 @@
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
+ #define NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT
7
+ #include <node.h>
8
+ #include <map>
9
+
10
+ #include "keymapping.h"
11
+ #include "common.h"
12
+
13
+ namespace vscode_keyboard {
14
+
15
+ napi_status napi_set_named_property_string_utf8(napi_env env, napi_value object, const char *utf8_name, const char *value) {
16
+ napi_value _value;
17
+ NAPI_CALL_RETURN_STATUS(env, napi_create_string_utf8(env, value, NAPI_AUTO_LENGTH, &_value));
18
+ NAPI_CALL_RETURN_STATUS(env, napi_set_named_property(env, object, utf8_name, _value));
19
+ return napi_ok;
20
+ }
21
+
22
+ napi_status napi_set_named_property_int32(napi_env env, napi_value object, const char *utf8_name, int value) {
23
+ napi_value _value;
24
+ NAPI_CALL_RETURN_STATUS(env, napi_create_int32(env, value, &_value));
25
+ NAPI_CALL_RETURN_STATUS(env, napi_set_named_property(env, object, utf8_name, _value));
26
+ return napi_ok;
27
+ }
28
+
29
+ napi_value napi_fetch_null(napi_env env) {
30
+ napi_value result;
31
+ NAPI_CALL(env, napi_get_null(env, &result));
32
+ return result;
33
+ }
34
+
35
+ napi_value napi_fetch_undefined(napi_env env) {
36
+ napi_value result;
37
+ NAPI_CALL(env, napi_get_undefined(env, &result));
38
+ return result;
39
+ }
40
+
41
+ napi_value napi_fetch_boolean(napi_env env, bool value) {
42
+ napi_value result;
43
+ NAPI_CALL(env, napi_get_boolean(env, value, &result));
44
+ return result;
45
+ }
46
+
47
+ void InvokeNotificationCallback(NotificationCallbackData *data) {
48
+ if (data->tsfn == NULL) {
49
+ // This indicates we are in the shutdown phase and the thread safe function has been finalized
50
+ return;
51
+ }
52
+
53
+ // No need to call napi_acquire_threadsafe_function because
54
+ // the refcount is set to 1 in the main thread.
55
+ napi_call_threadsafe_function(data->tsfn, NULL, napi_tsfn_blocking);
56
+ }
57
+
58
+ static void NotifyJS(napi_env env, napi_value func, void* context, void* data) {
59
+ // env may be NULL if nodejs is shutting down
60
+ if (env != NULL) {
61
+ napi_value global;
62
+ NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global));
63
+
64
+ std::vector<napi_value> argv;
65
+ NAPI_CALL_RETURN_VOID(env, napi_call_function(env, global, func, argv.size(), argv.data(), NULL));
66
+ }
67
+ }
68
+
69
+ static void FinalizeThreadsafeFunction(napi_env env, void* raw_data, void* hint) {
70
+ NotificationCallbackData *data;
71
+ napi_get_instance_data(env, (void**)&data);
72
+ data->tsfn = NULL;
73
+ }
74
+
75
+ static void EnvCleanupHook(void *raw_data) {
76
+ NotificationCallbackData* data = static_cast<NotificationCallbackData*>(raw_data);
77
+ DisposeKeyboardLayoutChangeListenerImpl(data);
78
+ }
79
+
80
+ napi_value OnDidChangeKeyboardLayoutImpl(napi_env env, napi_callback_info info) {
81
+ size_t argc = 2;
82
+ napi_value args[2];
83
+ NotificationCallbackData *data;
84
+ NAPI_CALL(env, napi_get_instance_data(env, (void**)&data));
85
+ NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
86
+
87
+ NAPI_ASSERT(env, argc == 1, "Wrong number of arguments. Expects a single argument.");
88
+
89
+ napi_valuetype valuetype0;
90
+ NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
91
+ NAPI_ASSERT(env, valuetype0 == napi_function, "Wrong type of arguments. Expects a function as first argument.");
92
+
93
+ napi_value func = args[0];
94
+
95
+ napi_value resource_name;
96
+ NAPI_CALL(env, napi_create_string_utf8(env, "onDidChangeKeyboardLayoutCallback", NAPI_AUTO_LENGTH, &resource_name));
97
+
98
+ // Convert the callback retrieved from JavaScript into a thread-safe function
99
+ napi_threadsafe_function tsfn;
100
+ NAPI_CALL(env, napi_create_threadsafe_function(env, func, NULL, resource_name, 0, 1, NULL,
101
+ FinalizeThreadsafeFunction, NULL, NotifyJS,
102
+ &tsfn));
103
+ data->tsfn = tsfn;
104
+
105
+ RegisterKeyboardLayoutChangeListenerImpl(data);
106
+
107
+ napi_add_env_cleanup_hook(env, EnvCleanupHook, data);
108
+
109
+ return napi_fetch_undefined(env);
110
+ }
111
+
112
+ void DeleteInstanceData(napi_env env, void *raw_data, void *hint) {
113
+ NotificationCallbackData *data = static_cast<NotificationCallbackData*>(raw_data);
114
+ delete data;
115
+ }
116
+
117
+ napi_value Init(napi_env env, napi_value exports) {
118
+ NotificationCallbackData *data = new NotificationCallbackData();
119
+ NAPI_CALL(env, napi_set_instance_data(env, data, DeleteInstanceData, NULL));
120
+
121
+ {
122
+ napi_value get_key_map_fn;
123
+ NAPI_CALL(env, napi_create_function(env, NULL, 0, GetKeyMapImpl, NULL, &get_key_map_fn));
124
+ NAPI_CALL(env, napi_set_named_property(env, exports, "getKeyMap", get_key_map_fn));
125
+ }
126
+ {
127
+ napi_value get_current_keyboard_layout_fn;
128
+ NAPI_CALL(env, napi_create_function(env, NULL, 0, GetCurrentKeyboardLayoutImpl, NULL, &get_current_keyboard_layout_fn));
129
+ NAPI_CALL(env, napi_set_named_property(env, exports, "getCurrentKeyboardLayout", get_current_keyboard_layout_fn));
130
+ }
131
+ {
132
+ napi_value on_did_change_keyboard_layout_fn;
133
+ NAPI_CALL(env, napi_create_function(env, NULL, 0, OnDidChangeKeyboardLayoutImpl, NULL, &on_did_change_keyboard_layout_fn));
134
+ NAPI_CALL(env, napi_set_named_property(env, exports, "onDidChangeKeyboardLayout", on_did_change_keyboard_layout_fn));
135
+ }
136
+ {
137
+ napi_value is_iso_keyboard_fn;
138
+ NAPI_CALL(env, napi_create_function(env, NULL, 0, IsISOKeyboardImpl, NULL, &is_iso_keyboard_fn));
139
+ NAPI_CALL(env, napi_set_named_property(env, exports, "isISOKeyboard", is_iso_keyboard_fn));
140
+ }
141
+
142
+ return exports;
143
+ }
144
+
145
+ NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
146
+
147
+ } // namespace vscode_keyboard
@@ -0,0 +1,65 @@
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
+ #ifndef KEYMAPPING_H_
7
+ #define KEYMAPPING_H_
8
+
9
+ #include <node_api.h>
10
+
11
+ #include <string>
12
+ #include <vector>
13
+ #include "../deps/chromium/keyboard_codes.h"
14
+
15
+ #if defined(__unix__)
16
+ #include <pthread.h>
17
+ #endif
18
+
19
+ namespace vscode_keyboard {
20
+
21
+ // This structure is used to define the keycode mapping table.
22
+ // It is defined here because the unittests need access to it.
23
+ typedef struct {
24
+ // USB keycode:
25
+ // Upper 16-bits: USB Usage Page.
26
+ // Lower 16-bits: USB Usage Id: Assigned ID within this usage page.
27
+ uint32_t usb_keycode;
28
+
29
+ // Contains one of the following:
30
+ // On Linux: XKB scancode
31
+ // On Windows: Windows OEM scancode
32
+ // On Mac: Mac keycode
33
+ int native_keycode;
34
+
35
+ // The UIEvents (aka: DOM4Events) |code| value as defined in:
36
+ // http://www.w3.org/TR/DOM-Level-3-Events-code/
37
+ const char* code;
38
+ } KeycodeMapEntry;
39
+
40
+ typedef struct {
41
+ #if defined(_WIN32)
42
+ void* listener;
43
+ #endif
44
+ #if defined(__unix__)
45
+ pthread_t tid;
46
+ #endif
47
+ volatile napi_threadsafe_function tsfn;
48
+ } NotificationCallbackData;
49
+
50
+ napi_value GetKeyMapImpl(napi_env env, napi_callback_info info);
51
+ napi_value GetCurrentKeyboardLayoutImpl(napi_env env, napi_callback_info info);
52
+ void RegisterKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data);
53
+ void DisposeKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data);
54
+ napi_value IsISOKeyboardImpl(napi_env env, napi_callback_info info);
55
+
56
+ void InvokeNotificationCallback(NotificationCallbackData *data);
57
+ napi_status napi_set_named_property_string_utf8(napi_env env, napi_value object, const char *utf8_name, const char *value);
58
+ napi_status napi_set_named_property_int32(napi_env env, napi_value object, const char *utf8_name, int value);
59
+ napi_value napi_fetch_null(napi_env env);
60
+ napi_value napi_fetch_undefined(napi_env env);
61
+ napi_value napi_fetch_boolean(napi_env env, bool value);
62
+
63
+ } // namespace vscode_keyboard
64
+
65
+ #endif // KEYMAPPING_H_
@@ -0,0 +1,67 @@
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
+ #include "string_conversion.h"
7
+
8
+ namespace vscode_keyboard {
9
+
10
+ wchar_t conversion_buffer[10];
11
+
12
+ std::string UTF16toUTF8(const wchar_t * in, int length) {
13
+ if (length < 10) {
14
+ for (int i = 0; i < length; ++i) {
15
+ conversion_buffer[i] = in[i];
16
+ }
17
+ conversion_buffer[length] = 0;
18
+ return UTF16to8(conversion_buffer);
19
+ }
20
+
21
+ wchar_t *t = new wchar_t[length + 1];
22
+ for (int i = 0; i < length; ++i) {
23
+ t[i] = in[i];
24
+ }
25
+ t[length] = 0;
26
+ std::string result = UTF16to8(t);
27
+ delete []t;
28
+
29
+ return result;
30
+ }
31
+
32
+ // http://stackoverflow.com/a/148766
33
+ std::string UTF16to8(const wchar_t * in) {
34
+ std::string out;
35
+ unsigned int codepoint = 0;
36
+ for (; *in != 0; ++in) {
37
+ if (*in >= 0xd800 && *in <= 0xdbff) {
38
+ codepoint = ((*in - 0xd800) << 10) + 0x10000;
39
+ } else {
40
+ if (*in >= 0xdc00 && *in <= 0xdfff) {
41
+ codepoint |= *in - 0xdc00;
42
+ } else {
43
+ codepoint = *in;
44
+ }
45
+
46
+ if (codepoint <= 0x7f) {
47
+ out.append(1, static_cast<char>(codepoint));
48
+ } else if (codepoint <= 0x7ff) {
49
+ out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
50
+ out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
51
+ } else if (codepoint <= 0xffff) {
52
+ out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
53
+ out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
54
+ out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
55
+ } else {
56
+ out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
57
+ out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
58
+ out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
59
+ out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
60
+ }
61
+ codepoint = 0;
62
+ }
63
+ }
64
+ return out;
65
+ }
66
+
67
+ } // namespace vscode_keyboard
@@ -0,0 +1,18 @@
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
+ #ifndef STRING_CONVERSION_H_
7
+ #define STRING_CONVERSION_H_
8
+
9
+ #include <string>
10
+
11
+ namespace vscode_keyboard {
12
+
13
+ std::string UTF16to8(const wchar_t * in);
14
+ std::string UTF16toUTF8(const wchar_t * in, int length);
15
+
16
+ } // namespace vscode_keyboard
17
+
18
+ #endif // STRING_CONVERSION_H_