@theia/core 1.53.0-next.55 → 1.53.0-next.64
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.
- package/README.md +6 -6
- package/i18n/nls.cs.json +582 -582
- package/i18n/nls.de.json +582 -582
- package/i18n/nls.es.json +582 -582
- package/i18n/nls.fr.json +582 -582
- package/i18n/nls.hu.json +582 -582
- package/i18n/nls.it.json +582 -582
- package/i18n/nls.ja.json +582 -582
- package/i18n/nls.json +582 -582
- package/i18n/nls.ko.json +582 -582
- package/i18n/nls.pl.json +582 -582
- package/i18n/nls.pt-br.json +582 -582
- package/i18n/nls.ru.json +582 -582
- package/i18n/nls.tr.json +582 -582
- package/i18n/nls.zh-cn.json +582 -582
- package/i18n/nls.zh-tw.json +582 -582
- package/lib/browser/catalog.json +54 -6
- package/lib/browser/common-frontend-contribution.js +3 -3
- package/lib/browser/common-styling-participants.js +166 -166
- package/lib/browser/progress-location-service.spec.js +7 -7
- package/lib/browser/storage-service.js +3 -3
- package/lib/browser/tree/tree.spec.js +75 -75
- package/lib/node/process-utils.spec.js +8 -8
- package/package.json +4 -4
- package/shared/ajv/index.d.ts +2 -2
- package/shared/markdown-it.d.ts +2 -2
- package/shared/markdown-it.js +1 -1
- package/shared/reflect-metadata/index.d.ts +1 -1
- package/shared/reflect-metadata/index.js +1 -1
- package/shared/vscode-languageserver-types/index.d.ts +1 -1
- package/src/browser/about-dialog.tsx +137 -137
- package/src/browser/authentication-service.ts +467 -467
- package/src/browser/breadcrumbs/breadcrumb-popup-container.ts +101 -101
- package/src/browser/breadcrumbs/breadcrumb-renderer.tsx +41 -41
- package/src/browser/breadcrumbs/breadcrumbs-constants.ts +79 -79
- package/src/browser/breadcrumbs/breadcrumbs-renderer.tsx +185 -185
- package/src/browser/breadcrumbs/breadcrumbs-service.ts +108 -108
- package/src/browser/breadcrumbs/index.ts +21 -21
- package/src/browser/browser-clipboard-service.ts +122 -122
- package/src/browser/browser.ts +239 -239
- package/src/browser/clipboard-service.ts +23 -23
- package/src/browser/color-application-contribution.ts +110 -110
- package/src/browser/color-registry.ts +60 -60
- package/src/browser/command-open-handler.ts +54 -54
- package/src/browser/common-frontend-contribution.ts +2680 -2680
- package/src/browser/common-styling-participants.ts +361 -361
- package/src/browser/connection-status-service.spec.ts +200 -200
- package/src/browser/connection-status-service.ts +216 -216
- package/src/browser/context-key-service.ts +142 -142
- package/src/browser/context-menu-renderer.ts +124 -124
- package/src/browser/core-preferences.ts +343 -343
- package/src/browser/credentials-service.ts +106 -106
- package/src/browser/decoration-style.ts +65 -65
- package/src/browser/decorations-service.ts +209 -209
- package/src/browser/dialogs/react-dialog.tsx +56 -56
- package/src/browser/dialogs.ts +534 -534
- package/src/browser/diff-uris.ts +117 -117
- package/src/browser/encoding-registry.ts +97 -97
- package/src/browser/endpoint.spec.ts +148 -148
- package/src/browser/endpoint.ts +136 -136
- package/src/browser/external-uri-service.ts +79 -79
- package/src/browser/file-icons-js.d.ts +20 -20
- package/src/browser/frontend-application-bindings.ts +62 -62
- package/src/browser/frontend-application-config-provider.spec.ts +45 -45
- package/src/browser/frontend-application-config-provider.ts +50 -50
- package/src/browser/frontend-application-contribution.ts +110 -110
- package/src/browser/frontend-application-module.ts +474 -474
- package/src/browser/frontend-application-state.ts +74 -74
- package/src/browser/frontend-application.ts +326 -326
- package/src/browser/hover-service.ts +218 -218
- package/src/browser/http-open-handler.ts +49 -49
- package/src/browser/i18n/i18n-frontend-module.ts +27 -27
- package/src/browser/i18n/language-quick-pick-service.ts +130 -130
- package/src/browser/icon-registry.ts +87 -87
- package/src/browser/icon-theme-contribution.ts +64 -64
- package/src/browser/icon-theme-service.ts +217 -217
- package/src/browser/icons/CollapseAll.svg +7 -7
- package/src/browser/icons/CollapseAll_inverse.svg +7 -7
- package/src/browser/icons/Refresh.svg +7 -7
- package/src/browser/icons/Refresh_inverse.svg +7 -7
- package/src/browser/icons/add-inverse.svg +4 -4
- package/src/browser/icons/add.svg +4 -4
- package/src/browser/icons/arrow-down-bright.svg +6 -6
- package/src/browser/icons/arrow-down-dark.svg +6 -6
- package/src/browser/icons/arrow-up-bright.svg +6 -6
- package/src/browser/icons/arrow-up-dark.svg +6 -6
- package/src/browser/icons/case-sensitive-dark.svg +16 -16
- package/src/browser/icons/case-sensitive.svg +16 -16
- package/src/browser/icons/chevron-right-dark.svg +5 -5
- package/src/browser/icons/chevron-right-light.svg +6 -6
- package/src/browser/icons/circle-bright.svg +7 -7
- package/src/browser/icons/circle-dark.svg +7 -7
- package/src/browser/icons/clear-search-results-dark.svg +7 -7
- package/src/browser/icons/clear-search-results.svg +7 -7
- package/src/browser/icons/close-all-bright.svg +7 -7
- package/src/browser/icons/close-all-dark.svg +7 -7
- package/src/browser/icons/close-bright.svg +7 -7
- package/src/browser/icons/close-dark.svg +7 -7
- package/src/browser/icons/collapse.svg +4 -4
- package/src/browser/icons/edit-json-dark.svg +6 -6
- package/src/browser/icons/edit-json.svg +6 -6
- package/src/browser/icons/expand.svg +4 -4
- package/src/browser/icons/loading-dark.svg +6 -6
- package/src/browser/icons/loading-light.svg +6 -6
- package/src/browser/icons/open-change-bright.svg +3 -3
- package/src/browser/icons/open-change-dark.svg +4 -4
- package/src/browser/icons/open-file-bright.svg +4 -4
- package/src/browser/icons/open-file-dark.svg +4 -4
- package/src/browser/icons/preview-bright.svg +3 -3
- package/src/browser/icons/preview-dark.svg +3 -3
- package/src/browser/icons/regex-dark.svg +10 -10
- package/src/browser/icons/regex.svg +10 -10
- package/src/browser/icons/remove-all-inverse.svg +4 -4
- package/src/browser/icons/remove-all.svg +4 -4
- package/src/browser/icons/replace-all-inverse.svg +13 -13
- package/src/browser/icons/replace-all.svg +13 -13
- package/src/browser/icons/replace-inverse.svg +15 -15
- package/src/browser/icons/replace.svg +15 -15
- package/src/browser/icons/whole-word-dark.svg +19 -19
- package/src/browser/icons/whole-word.svg +19 -19
- package/src/browser/index.ts +50 -50
- package/src/browser/json-schema-store.ts +118 -118
- package/src/browser/keybinding.spec.ts +554 -554
- package/src/browser/keybinding.ts +759 -759
- package/src/browser/keyboard/browser-keyboard-frontend-contribution.ts +108 -108
- package/src/browser/keyboard/browser-keyboard-layout-provider.spec.ts +171 -171
- package/src/browser/keyboard/browser-keyboard-layout-provider.ts +469 -469
- package/src/browser/keyboard/browser-keyboard-module.ts +30 -30
- package/src/browser/keyboard/index.ts +20 -20
- package/src/browser/keyboard/keyboard-layout-service.spec.ts +121 -121
- package/src/browser/keyboard/keyboard-layout-service.ts +455 -455
- package/src/browser/keyboard/keys.spec.ts +258 -258
- package/src/browser/keyboard/keys.ts +20 -20
- package/src/browser/keys.ts +21 -21
- package/src/browser/label-parser.spec.ts +165 -165
- package/src/browser/label-parser.ts +108 -108
- package/src/browser/label-provider.spec.ts +62 -62
- package/src/browser/label-provider.ts +385 -385
- package/src/browser/language-icon-provider.ts +55 -55
- package/src/browser/language-service.ts +77 -77
- package/src/browser/logger-frontend-module.ts +65 -65
- package/src/browser/markdown-rendering/markdown-renderer.ts +98 -98
- package/src/browser/menu/browser-context-menu-renderer.ts +48 -48
- package/src/browser/menu/browser-menu-module.ts +28 -28
- package/src/browser/menu/browser-menu-plugin.ts +491 -491
- package/src/browser/menu/context-menu-context.ts +41 -41
- package/src/browser/messaging/connection-source.ts +26 -26
- package/src/browser/messaging/frontend-id-provider.ts +37 -37
- package/src/browser/messaging/index.ts +18 -18
- package/src/browser/messaging/messaging-frontend-module.ts +41 -41
- package/src/browser/messaging/service-connection-provider.ts +140 -140
- package/src/browser/messaging/ws-connection-provider.ts +49 -49
- package/src/browser/messaging/ws-connection-source.ts +230 -230
- package/src/browser/mime-service.ts +30 -30
- package/src/browser/navigatable-types.ts +81 -81
- package/src/browser/navigatable.ts +39 -39
- package/src/browser/open-with-service.ts +140 -140
- package/src/browser/opener-service.spec.ts +49 -49
- package/src/browser/opener-service.ts +169 -169
- package/src/browser/performance/frontend-stopwatch.ts +65 -65
- package/src/browser/performance/index.ts +18 -18
- package/src/browser/performance/measurement-frontend-bindings.ts +31 -31
- package/src/browser/preferences/index.ts +23 -23
- package/src/browser/preferences/injectable-preference-proxy.ts +283 -283
- package/src/browser/preferences/preference-configurations.ts +82 -82
- package/src/browser/preferences/preference-contribution.ts +436 -436
- package/src/browser/preferences/preference-language-override-service.ts +111 -111
- package/src/browser/preferences/preference-provider.spec.ts +36 -36
- package/src/browser/preferences/preference-provider.ts +277 -277
- package/src/browser/preferences/preference-proxy.spec.ts +367 -367
- package/src/browser/preferences/preference-proxy.ts +367 -367
- package/src/browser/preferences/preference-schema-provider.spec.ts +130 -130
- package/src/browser/preferences/preference-scope.ts +18 -18
- package/src/browser/preferences/preference-service.spec.ts +613 -613
- package/src/browser/preferences/preference-service.ts +594 -594
- package/src/browser/preferences/preference-validation-service.spec.ts +334 -334
- package/src/browser/preferences/preference-validation-service.ts +358 -358
- package/src/browser/preferences/test/index.ts +19 -19
- package/src/browser/preferences/test/mock-preference-provider.ts +50 -50
- package/src/browser/preferences/test/mock-preference-proxy.ts +48 -48
- package/src/browser/preferences/test/mock-preference-service.ts +63 -63
- package/src/browser/preload/i18n-preload-contribution.ts +50 -50
- package/src/browser/preload/os-preload-contribution.ts +37 -37
- package/src/browser/preload/preload-module.ts +45 -45
- package/src/browser/preload/preloader.ts +37 -37
- package/src/browser/preload/theme-preload-contribution.ts +31 -31
- package/src/browser/progress-bar-factory.ts +29 -29
- package/src/browser/progress-bar.ts +76 -76
- package/src/browser/progress-client.ts +53 -53
- package/src/browser/progress-location-service.spec.ts +50 -50
- package/src/browser/progress-location-service.ts +96 -96
- package/src/browser/progress-status-bar-item.ts +83 -83
- package/src/browser/quick-input/index.ts +23 -23
- package/src/browser/quick-input/quick-access.ts +75 -75
- package/src/browser/quick-input/quick-command-frontend-contribution.ts +89 -89
- package/src/browser/quick-input/quick-command-service.ts +246 -246
- package/src/browser/quick-input/quick-help-service.ts +87 -87
- package/src/browser/quick-input/quick-input-frontend-contribution.ts +33 -33
- package/src/browser/quick-input/quick-input-service.spec.ts +176 -176
- package/src/browser/quick-input/quick-input-service.ts +17 -17
- package/src/browser/quick-input/quick-pick-service-impl.ts +69 -69
- package/src/browser/quick-input/quick-view-service.ts +83 -83
- package/src/browser/request/browser-request-module.ts +23 -23
- package/src/browser/request/browser-request-service.ts +172 -172
- package/src/browser/resource-context-key.ts +77 -77
- package/src/browser/saveable-service.ts +332 -332
- package/src/browser/saveable.ts +395 -395
- package/src/browser/secondary-window-handler.ts +211 -211
- package/src/browser/shell/additional-views-menu-widget.tsx +71 -71
- package/src/browser/shell/application-shell-mouse-tracker.ts +103 -103
- package/src/browser/shell/application-shell.ts +2271 -2271
- package/src/browser/shell/current-widget-command-adapter.ts +57 -57
- package/src/browser/shell/index.ts +23 -23
- package/src/browser/shell/shell-layout-restorer.ts +399 -399
- package/src/browser/shell/side-panel-handler.ts +794 -794
- package/src/browser/shell/side-panel-toolbar.ts +111 -111
- package/src/browser/shell/sidebar-bottom-menu-widget.tsx +39 -39
- package/src/browser/shell/sidebar-menu-widget.tsx +183 -183
- package/src/browser/shell/sidebar-top-menu-widget.tsx +26 -26
- package/src/browser/shell/split-panels.ts +191 -191
- package/src/browser/shell/tab-bar-decorator.ts +106 -106
- package/src/browser/shell/tab-bar-toolbar/index.ts +19 -19
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.ts +31 -31
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +242 -242
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.ts +149 -149
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.ts +62 -62
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +443 -443
- package/src/browser/shell/tab-bars.spec.ts +63 -63
- package/src/browser/shell/tab-bars.ts +1468 -1468
- package/src/browser/shell/theia-dock-panel.ts +265 -265
- package/src/browser/shell/view-column-service.ts +125 -125
- package/src/browser/shell/view-contribution.ts +178 -178
- package/src/browser/source-tree/index.ts +19 -19
- package/src/browser/source-tree/source-tree-widget.tsx +107 -107
- package/src/browser/source-tree/source-tree.ts +146 -146
- package/src/browser/source-tree/tree-source.ts +73 -73
- package/src/browser/status-bar/index.ts +29 -29
- package/src/browser/status-bar/status-bar-types.ts +97 -97
- package/src/browser/status-bar/status-bar-view-model.ts +209 -209
- package/src/browser/status-bar/status-bar.tsx +189 -189
- package/src/browser/storage-service.spec.ts +76 -76
- package/src/browser/storage-service.ts +129 -129
- package/src/browser/style/about.css +36 -36
- package/src/browser/style/alert-messages.css +62 -62
- package/src/browser/style/ansi.css +88 -88
- package/src/browser/style/breadcrumbs.css +130 -130
- package/src/browser/style/dialog.css +126 -126
- package/src/browser/style/dockpanel.css +76 -76
- package/src/browser/style/hover-service.css +101 -101
- package/src/browser/style/icons.css +61 -61
- package/src/browser/style/index.css +353 -353
- package/src/browser/style/materialcolors.css +278 -278
- package/src/browser/style/menus.css +230 -230
- package/src/browser/style/notification.css +39 -39
- package/src/browser/style/os.css +87 -87
- package/src/browser/style/progress-bar.css +43 -43
- package/src/browser/style/quick-title-bar.css +45 -45
- package/src/browser/style/scrollbars.css +172 -172
- package/src/browser/style/search-box.css +123 -123
- package/src/browser/style/select-component.css +107 -107
- package/src/browser/style/sidepanel.css +367 -367
- package/src/browser/style/split-widget.css +38 -38
- package/src/browser/style/status-bar.css +127 -127
- package/src/browser/style/tabs.css +647 -647
- package/src/browser/style/tooltip.css +28 -28
- package/src/browser/style/tree-decorators.css +81 -81
- package/src/browser/style/tree.css +232 -232
- package/src/browser/style/view-container.css +187 -187
- package/src/browser/style/widget.css +19 -19
- package/src/browser/styling-service.ts +96 -96
- package/src/browser/supported-encodings.ts +262 -262
- package/src/browser/test/jsdom.ts +69 -69
- package/src/browser/test/mock-connection-status-service.ts +33 -33
- package/src/browser/test/mock-env-variables-server.ts +47 -47
- package/src/browser/test/mock-opener-service.ts +34 -34
- package/src/browser/test/mock-storage-service.ts +49 -49
- package/src/browser/theming.ts +206 -206
- package/src/browser/tooltip-service.tsx +96 -96
- package/src/browser/tree/fuzzy-search.spec.ts +99 -99
- package/src/browser/tree/fuzzy-search.ts +136 -136
- package/src/browser/tree/index.ts +29 -29
- package/src/browser/tree/search-box-debounce.ts +96 -96
- package/src/browser/tree/search-box.ts +355 -355
- package/src/browser/tree/test/mock-selectable-tree-model.ts +109 -109
- package/src/browser/tree/test/mock-tree-model.ts +136 -136
- package/src/browser/tree/test/tree-test-container.ts +50 -50
- package/src/browser/tree/tree-compression/compressed-tree-expansion-service.ts +46 -46
- package/src/browser/tree/tree-compression/compressed-tree-model.ts +88 -88
- package/src/browser/tree/tree-compression/compressed-tree-widget.tsx +203 -203
- package/src/browser/tree/tree-compression/index.ts +20 -20
- package/src/browser/tree/tree-compression/tree-compression-service.ts +125 -125
- package/src/browser/tree/tree-compression/tree-compression.css +28 -28
- package/src/browser/tree/tree-consistency.spec.ts +105 -105
- package/src/browser/tree/tree-container.spec.ts +45 -45
- package/src/browser/tree/tree-container.ts +155 -155
- package/src/browser/tree/tree-decorator.spec.ts +162 -162
- package/src/browser/tree/tree-decorator.ts +238 -238
- package/src/browser/tree/tree-expansion.spec.ts +173 -173
- package/src/browser/tree/tree-expansion.ts +165 -165
- package/src/browser/tree/tree-focus-service.ts +55 -55
- package/src/browser/tree/tree-iterator.spec.ts +170 -170
- package/src/browser/tree/tree-iterator.ts +256 -256
- package/src/browser/tree/tree-label-provider.ts +40 -40
- package/src/browser/tree/tree-model.ts +562 -562
- package/src/browser/tree/tree-navigation.ts +58 -58
- package/src/browser/tree/tree-preference.ts +50 -50
- package/src/browser/tree/tree-search.ts +128 -128
- package/src/browser/tree/tree-selectable.spec.ts +152 -152
- package/src/browser/tree/tree-selection-impl.ts +176 -176
- package/src/browser/tree/tree-selection-state.spec.ts +462 -462
- package/src/browser/tree/tree-selection-state.ts +245 -245
- package/src/browser/tree/tree-selection.ts +159 -159
- package/src/browser/tree/tree-view-welcome-widget.tsx +263 -263
- package/src/browser/tree/tree-widget-selection.ts +45 -45
- package/src/browser/tree/tree-widget.tsx +1591 -1591
- package/src/browser/tree/tree.spec.ts +241 -241
- package/src/browser/tree/tree.ts +425 -425
- package/src/browser/undo-redo-handler.ts +85 -85
- package/src/browser/user-working-directory-provider.ts +77 -77
- package/src/browser/view-container.ts +1640 -1640
- package/src/browser/widget-decoration.ts +358 -358
- package/src/browser/widget-manager.spec.ts +102 -102
- package/src/browser/widget-manager.ts +318 -318
- package/src/browser/widget-open-handler.ts +168 -168
- package/src/browser/widgets/alert-message.tsx +56 -56
- package/src/browser/widgets/enhanced-preview-widget.ts +27 -27
- package/src/browser/widgets/extractable-widget.ts +33 -33
- package/src/browser/widgets/index.ts +21 -21
- package/src/browser/widgets/previewable-widget.ts +31 -31
- package/src/browser/widgets/react-renderer.tsx +53 -53
- package/src/browser/widgets/react-widget.tsx +51 -51
- package/src/browser/widgets/select-component.tsx +367 -367
- package/src/browser/widgets/split-widget.ts +163 -163
- package/src/browser/widgets/widget.ts +406 -406
- package/src/browser/window/browser-window-module.ts +32 -32
- package/src/browser/window/default-secondary-window-service.ts +189 -189
- package/src/browser/window/default-window-service.spec.ts +78 -78
- package/src/browser/window/default-window-service.ts +171 -171
- package/src/browser/window/secondary-window-service.ts +39 -39
- package/src/browser/window/test/mock-window-service.ts +29 -29
- package/src/browser/window/window-service.ts +78 -78
- package/src/browser/window/window-title-service.ts +107 -107
- package/src/browser/window/window-title-updater.ts +95 -95
- package/src/browser/window-contribution.ts +64 -64
- package/src/browser-only/frontend-only-application-module.ts +116 -116
- package/src/browser-only/i18n/i18n-frontend-only-module.ts +37 -37
- package/src/browser-only/logger-frontend-only-module.ts +63 -63
- package/src/browser-only/messaging/frontend-only-service-connection-provider.ts +39 -39
- package/src/browser-only/messaging/messaging-frontend-only-module.ts +42 -42
- package/src/browser-only/preload/frontend-only-preload-module.ts +49 -49
- package/src/common/accessibility.ts +33 -33
- package/src/common/application-error.spec.ts +27 -27
- package/src/common/application-error.ts +76 -76
- package/src/common/application-protocol.ts +42 -42
- package/src/common/array-utils.ts +129 -129
- package/src/common/buffer.ts +228 -228
- package/src/common/cancellation.ts +163 -163
- package/src/common/char-code.ts +438 -438
- package/src/common/collections.ts +125 -125
- package/src/common/color.ts +103 -103
- package/src/common/command.spec.ts +208 -208
- package/src/common/command.ts +489 -489
- package/src/common/contribution-filter/contribution-filter-registry.ts +79 -79
- package/src/common/contribution-filter/contribution-filter.ts +64 -64
- package/src/common/contribution-filter/filter.ts +23 -23
- package/src/common/contribution-filter/index.ts +19 -19
- package/src/common/contribution-provider.ts +96 -96
- package/src/common/disposable.spec.ts +94 -94
- package/src/common/disposable.ts +188 -188
- package/src/common/encoding-service.ts +380 -380
- package/src/common/encodings.ts +24 -24
- package/src/common/env-variables/env-variables-protocol.ts +38 -38
- package/src/common/env-variables/index.ts +17 -17
- package/src/common/event.spec.ts +32 -32
- package/src/common/event.ts +493 -493
- package/src/common/file-uri.ts +61 -61
- package/src/common/frontend-application-state.ts +38 -38
- package/src/common/glob.ts +741 -741
- package/src/common/hash.ts +85 -85
- package/src/common/i18n/localization-server.ts +25 -25
- package/src/common/i18n/localization.ts +80 -80
- package/src/common/i18n/nls.metadata.json +34112 -34112
- package/src/common/index.ts +51 -51
- package/src/common/json-schema.ts +108 -108
- package/src/common/key-store.ts +26 -26
- package/src/common/keybinding.ts +152 -152
- package/src/common/keyboard/keyboard-layout-provider.ts +51 -51
- package/src/common/keys.ts +694 -694
- package/src/common/label-protocol.ts +35 -35
- package/src/common/logger-protocol.ts +119 -119
- package/src/common/logger-watcher.ts +48 -48
- package/src/common/logger.spec.ts +46 -46
- package/src/common/logger.ts +389 -389
- package/src/common/lsp-types.ts +34 -34
- package/src/common/markdown-rendering/icon-utilities.ts +30 -30
- package/src/common/markdown-rendering/index.ts +18 -18
- package/src/common/markdown-rendering/markdown-string.ts +152 -152
- package/src/common/menu/action-menu-node.ts +65 -65
- package/src/common/menu/composite-menu-node.spec.ts +67 -67
- package/src/common/menu/composite-menu-node.ts +114 -114
- package/src/common/menu/index.ts +21 -21
- package/src/common/menu/menu-adapter.ts +103 -103
- package/src/common/menu/menu-model-registry.ts +374 -374
- package/src/common/menu/menu-types.ts +220 -220
- package/src/common/menu/menu.spec.ts +101 -101
- package/src/common/message-rpc/channel.spec.ts +88 -88
- package/src/common/message-rpc/channel.ts +300 -300
- package/src/common/message-rpc/index.ts +22 -22
- package/src/common/message-rpc/message-buffer.ts +105 -105
- package/src/common/message-rpc/msg-pack-extension-manager.ts +70 -70
- package/src/common/message-rpc/rpc-message-encoder.spec.ts +65 -65
- package/src/common/message-rpc/rpc-message-encoder.ts +190 -190
- package/src/common/message-rpc/rpc-protocol.ts +255 -255
- package/src/common/message-rpc/uint8-array-message-buffer.spec.ts +41 -41
- package/src/common/message-rpc/uint8-array-message-buffer.ts +213 -213
- package/src/common/message-service-protocol.ts +148 -148
- package/src/common/message-service.ts +226 -226
- package/src/common/messaging/connection-error-handler.ts +73 -73
- package/src/common/messaging/connection-management.ts +43 -43
- package/src/common/messaging/handler.ts +26 -26
- package/src/common/messaging/index.ts +19 -19
- package/src/common/messaging/proxy-factory.spec.ts +108 -108
- package/src/common/messaging/proxy-factory.ts +336 -336
- package/src/common/messaging/socket-write-buffer.ts +52 -52
- package/src/common/messaging/web-socket-channel.ts +76 -76
- package/src/common/nls.ts +151 -151
- package/src/common/numbers.ts +21 -21
- package/src/common/objects.spec.ts +112 -112
- package/src/common/objects.ts +123 -123
- package/src/common/os.ts +82 -82
- package/src/common/path.spec.ts +415 -415
- package/src/common/path.ts +334 -334
- package/src/common/paths.ts +250 -250
- package/src/common/performance/index.ts +19 -19
- package/src/common/performance/measurement-protocol.ts +104 -104
- package/src/common/performance/measurement.ts +130 -130
- package/src/common/performance/stopwatch.ts +183 -183
- package/src/common/preferences/preference-schema.ts +101 -101
- package/src/common/preferences/preference-scope.spec.ts +48 -48
- package/src/common/preferences/preference-scope.ts +68 -68
- package/src/common/prioritizeable.ts +58 -58
- package/src/common/progress-service-protocol.ts +35 -35
- package/src/common/progress-service.ts +82 -82
- package/src/common/promise-util.spec.ts +102 -102
- package/src/common/promise-util.ts +143 -143
- package/src/common/quick-pick-service.ts +353 -353
- package/src/common/reference.spec.ts +145 -145
- package/src/common/reference.ts +230 -230
- package/src/common/resource.ts +430 -430
- package/src/common/selection-command-handler.ts +101 -101
- package/src/common/selection-service.spec.ts +43 -43
- package/src/common/selection-service.ts +49 -49
- package/src/common/selection.ts +50 -50
- package/src/common/severity.ts +111 -111
- package/src/common/stream.ts +718 -718
- package/src/common/strings.ts +231 -231
- package/src/common/telemetry.ts +45 -45
- package/src/common/ternary-search-tree.ts +417 -417
- package/src/common/test/expect.ts +34 -34
- package/src/common/test/mock-logger.ts +118 -118
- package/src/common/test/mock-menu.ts +35 -35
- package/src/common/test/mock-resource-provider.ts +33 -33
- package/src/common/theme.ts +68 -68
- package/src/common/types.spec.ts +86 -86
- package/src/common/types.ts +140 -140
- package/src/common/uri-command-handler.spec.ts +90 -90
- package/src/common/uri-command-handler.ts +148 -148
- package/src/common/uri.spec.ts +278 -278
- package/src/common/uri.ts +279 -279
- package/src/common/uuid.ts +45 -45
- package/src/common/version.ts +17 -17
- package/src/common/view-column.ts +33 -33
- package/src/common/window.ts +34 -34
- package/src/electron-browser/electron-clipboard-service.ts +32 -32
- package/src/electron-browser/electron-uri-handler.ts +42 -42
- package/src/electron-browser/keyboard/electron-keyboard-layout-change-notifier.ts +39 -39
- package/src/electron-browser/keyboard/electron-keyboard-module.ts +28 -28
- package/src/electron-browser/menu/electron-context-menu-renderer.ts +122 -122
- package/src/electron-browser/menu/electron-main-menu-factory.ts +339 -339
- package/src/electron-browser/menu/electron-menu-contribution.ts +506 -506
- package/src/electron-browser/menu/electron-menu-module.ts +40 -40
- package/src/electron-browser/menu/electron-menu-style.css +110 -110
- package/src/electron-browser/messaging/electron-frontend-id-provider.ts +25 -25
- package/src/electron-browser/messaging/electron-ipc-connection-source.ts +65 -65
- package/src/electron-browser/messaging/electron-local-ws-connection-source.ts +45 -45
- package/src/electron-browser/messaging/electron-messaging-frontend-module.ts +78 -78
- package/src/electron-browser/messaging/electron-ws-connection-source.ts +38 -38
- package/src/electron-browser/preload.ts +264 -264
- package/src/electron-browser/request/electron-browser-request-module.ts +26 -26
- package/src/electron-browser/token/electron-token-frontend-module.ts +22 -22
- package/src/electron-browser/window/electron-frontend-application-state.ts +26 -26
- package/src/electron-browser/window/electron-secondary-window-service.ts +35 -35
- package/src/electron-browser/window/electron-window-module.ts +48 -48
- package/src/electron-browser/window/electron-window-preferences.ts +76 -76
- package/src/electron-browser/window/electron-window-service.ts +109 -109
- package/src/electron-browser/window/external-app-open-handler.ts +42 -42
- package/src/electron-common/electron-api.ts +157 -157
- package/src/electron-common/electron-main-window-service.ts +24 -24
- package/src/electron-common/electron-token.ts +27 -27
- package/src/electron-main/electron-api-main.ts +373 -373
- package/src/electron-main/electron-main-application-module.ts +65 -65
- package/src/electron-main/electron-main-application.ts +860 -860
- package/src/electron-main/electron-main-constants.ts +23 -23
- package/src/electron-main/electron-main-window-service-impl.ts +44 -44
- package/src/electron-main/electron-security-token-service.ts +36 -36
- package/src/electron-main/event-utils.ts +36 -36
- package/src/electron-main/messaging/electron-connection-handler.ts +21 -21
- package/src/electron-main/messaging/electron-messaging-contribution.ts +143 -143
- package/src/electron-main/messaging/electron-messaging-service.ts +35 -35
- package/src/electron-main/theia-electron-window.ts +219 -219
- package/src/electron-node/cli/electron-backend-cli-module.ts +24 -24
- package/src/electron-node/cli/electron-cli-contribution.ts +35 -35
- package/src/electron-node/hosting/electron-backend-hosting-module.ts +24 -24
- package/src/electron-node/hosting/electron-ws-origin-validator.ts +37 -37
- package/src/electron-node/keyboard/electron-backend-keyboard-module.ts +30 -30
- package/src/electron-node/keyboard/electron-keyboard-layout-provider.ts +35 -35
- package/src/electron-node/request/electron-backend-request-module.ts +23 -23
- package/src/electron-node/request/electron-backend-request-service.ts +78 -78
- package/src/electron-node/token/electron-token-backend-contribution.ts +48 -48
- package/src/electron-node/token/electron-token-backend-module.ts +28 -28
- package/src/electron-node/token/electron-token-validator.ts +93 -93
- package/src/node/application-server.ts +59 -59
- package/src/node/backend-application-config-provider.spec.ts +29 -29
- package/src/node/backend-application-config-provider.ts +48 -48
- package/src/node/backend-application-module.ts +139 -139
- package/src/node/backend-application.ts +374 -374
- package/src/node/cli.spec.ts +94 -94
- package/src/node/cli.ts +63 -63
- package/src/node/console-logger-server.spec.ts +59 -59
- package/src/node/console-logger-server.ts +76 -76
- package/src/node/debug.ts +30 -30
- package/src/node/dynamic-require.ts +56 -56
- package/src/node/env-variables/env-variables-server.ts +123 -123
- package/src/node/env-variables/index.ts +17 -17
- package/src/node/environment-utils.spec.ts +92 -92
- package/src/node/environment-utils.ts +66 -66
- package/src/node/file-uri.spec.ts +76 -76
- package/src/node/filesystem-locking.ts +77 -77
- package/src/node/hosting/backend-application-hosts.ts +60 -60
- package/src/node/hosting/backend-hosting-module.ts +26 -26
- package/src/node/hosting/ws-origin-validator.ts +36 -36
- package/src/node/i18n/i18n-backend-module.ts +42 -42
- package/src/node/i18n/localization-contribution.ts +112 -112
- package/src/node/i18n/localization-provider.ts +125 -125
- package/src/node/i18n/localization-server.ts +52 -52
- package/src/node/i18n/theia-localization-contribution.ts +40 -40
- package/src/node/index.ts +22 -22
- package/src/node/key-store-server.ts +162 -162
- package/src/node/logger-backend-module.ts +88 -88
- package/src/node/logger-cli-contribution.spec.ts +245 -245
- package/src/node/logger-cli-contribution.ts +168 -168
- package/src/node/main.ts +33 -33
- package/src/node/messaging/binary-message-pipe.ts +168 -168
- package/src/node/messaging/connection-container-module.ts +96 -96
- package/src/node/messaging/default-messaging-service.ts +129 -129
- package/src/node/messaging/frontend-connection-service.ts +24 -24
- package/src/node/messaging/index.ts +19 -19
- package/src/node/messaging/ipc-bootstrap.ts +27 -27
- package/src/node/messaging/ipc-channel.ts +77 -77
- package/src/node/messaging/ipc-connection-provider.ts +107 -107
- package/src/node/messaging/ipc-protocol.ts +76 -76
- package/src/node/messaging/messaging-backend-module.ts +52 -52
- package/src/node/messaging/messaging-listeners.ts +52 -52
- package/src/node/messaging/messaging-service.ts +46 -46
- package/src/node/messaging/test/test-web-socket-channel.ts +61 -61
- package/src/node/messaging/websocket-endpoint.ts +79 -79
- package/src/node/messaging/websocket-frontend-connection-service.ts +186 -186
- package/src/node/os-backend-provider.ts +25 -25
- package/src/node/performance/index.ts +18 -18
- package/src/node/performance/measurement-backend-bindings.ts +35 -35
- package/src/node/performance/node-stopwatch.ts +40 -40
- package/src/node/process-utils.spec.ts +48 -48
- package/src/node/process-utils.ts +102 -102
- package/src/node/remote/backend-remote-service.ts +25 -25
- package/src/node/remote/remote-cli-contribution.ts +34 -34
- package/src/node/remote/remote-copy-contribution.ts +45 -45
- package/src/node/request/backend-request-facade.ts +39 -39
- package/src/node/request/backend-request-module.ts +25 -25
- package/src/node/request/proxy-cli-contribution.ts +65 -65
- package/src/node/ws-request-validators.ts +56 -56
- package/src/typings/native-keymap.d.ts +108 -108
|
@@ -1,469 +1,469 @@
|
|
|
1
|
-
// *****************************************************************************
|
|
2
|
-
// Copyright (C) 2019 TypeFox and others.
|
|
3
|
-
//
|
|
4
|
-
// This program and the accompanying materials are made available under the
|
|
5
|
-
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
-
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
-
//
|
|
8
|
-
// This Source Code may also be made available under the following Secondary
|
|
9
|
-
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
-
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
-
// with the GNU Classpath Exception which is available at
|
|
12
|
-
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
-
//
|
|
14
|
-
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
-
// *****************************************************************************
|
|
16
|
-
|
|
17
|
-
import { injectable, postConstruct, inject } from 'inversify';
|
|
18
|
-
import { isOSX } from '../../common/os';
|
|
19
|
-
import { Emitter, Event } from '../../common/event';
|
|
20
|
-
import { ILogger } from '../../common/logger';
|
|
21
|
-
import { Deferred } from '../../common/promise-util';
|
|
22
|
-
import {
|
|
23
|
-
NativeKeyboardLayout, KeyboardLayoutProvider, KeyboardLayoutChangeNotifier, KeyValidator, KeyValidationInput
|
|
24
|
-
} from '../../common/keyboard/keyboard-layout-provider';
|
|
25
|
-
import { LocalStorageService } from '../storage-service';
|
|
26
|
-
|
|
27
|
-
export type KeyboardLayoutSource = 'navigator.keyboard' | 'user-choice' | 'pressed-keys';
|
|
28
|
-
|
|
29
|
-
@injectable()
|
|
30
|
-
export class BrowserKeyboardLayoutProvider implements KeyboardLayoutProvider, KeyboardLayoutChangeNotifier, KeyValidator {
|
|
31
|
-
|
|
32
|
-
@inject(ILogger)
|
|
33
|
-
protected readonly logger: ILogger;
|
|
34
|
-
|
|
35
|
-
@inject(LocalStorageService)
|
|
36
|
-
protected readonly storageService: LocalStorageService;
|
|
37
|
-
|
|
38
|
-
protected readonly initialized = new Deferred();
|
|
39
|
-
protected readonly nativeLayoutChanged = new Emitter<NativeKeyboardLayout>();
|
|
40
|
-
|
|
41
|
-
get onDidChangeNativeLayout(): Event<NativeKeyboardLayout> {
|
|
42
|
-
return this.nativeLayoutChanged.event;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
protected readonly tester = new KeyboardTester(loadAllLayouts());
|
|
46
|
-
protected source: KeyboardLayoutSource = 'pressed-keys';
|
|
47
|
-
protected currentLayout: KeyboardLayoutData = DEFAULT_LAYOUT_DATA;
|
|
48
|
-
|
|
49
|
-
get allLayoutData(): KeyboardLayoutData[] {
|
|
50
|
-
return this.tester.candidates.slice();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get currentLayoutData(): KeyboardLayoutData {
|
|
54
|
-
return this.currentLayout;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get currentLayoutSource(): KeyboardLayoutSource {
|
|
58
|
-
return this.source;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
@postConstruct()
|
|
62
|
-
protected init(): void {
|
|
63
|
-
this.doInit();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
protected async doInit(): Promise<void> {
|
|
67
|
-
await this.loadState();
|
|
68
|
-
const keyboard = (navigator as NavigatorExtension).keyboard;
|
|
69
|
-
if (keyboard && keyboard.addEventListener) {
|
|
70
|
-
keyboard.addEventListener('layoutchange', async () => {
|
|
71
|
-
const newLayout = await this.getNativeLayout();
|
|
72
|
-
this.nativeLayoutChanged.fire(newLayout);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
this.initialized.resolve();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async getNativeLayout(): Promise<NativeKeyboardLayout> {
|
|
79
|
-
await this.initialized.promise;
|
|
80
|
-
if (this.source === 'user-choice') {
|
|
81
|
-
return this.currentLayout.raw;
|
|
82
|
-
}
|
|
83
|
-
const [layout, source] = await this.autodetect();
|
|
84
|
-
this.setCurrent(layout, source);
|
|
85
|
-
return layout.raw;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Set user-chosen keyboard layout data.
|
|
90
|
-
*/
|
|
91
|
-
async setLayoutData(layout: KeyboardLayoutData | 'autodetect'): Promise<KeyboardLayoutData> {
|
|
92
|
-
if (layout === 'autodetect') {
|
|
93
|
-
if (this.source === 'user-choice') {
|
|
94
|
-
const [newLayout, source] = await this.autodetect();
|
|
95
|
-
this.setCurrent(newLayout, source);
|
|
96
|
-
this.nativeLayoutChanged.fire(newLayout.raw);
|
|
97
|
-
return newLayout;
|
|
98
|
-
}
|
|
99
|
-
return this.currentLayout;
|
|
100
|
-
} else {
|
|
101
|
-
if (this.source !== 'user-choice' || layout !== this.currentLayout) {
|
|
102
|
-
this.setCurrent(layout, 'user-choice');
|
|
103
|
-
this.nativeLayoutChanged.fire(layout.raw);
|
|
104
|
-
}
|
|
105
|
-
return layout;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Test all known keyboard layouts with the given combination of pressed key and
|
|
111
|
-
* produced character. Matching layouts have their score increased (see class
|
|
112
|
-
* KeyboardTester). If this leads to a change of the top-scoring layout, a layout
|
|
113
|
-
* change event is fired.
|
|
114
|
-
*/
|
|
115
|
-
validateKey(keyCode: KeyValidationInput): void {
|
|
116
|
-
if (this.source !== 'pressed-keys') {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const accepted = this.tester.updateScores(keyCode);
|
|
120
|
-
if (!accepted) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const layout = this.selectLayout();
|
|
124
|
-
if (layout !== this.currentLayout && layout !== DEFAULT_LAYOUT_DATA) {
|
|
125
|
-
this.setCurrent(layout, 'pressed-keys');
|
|
126
|
-
this.nativeLayoutChanged.fire(layout.raw);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
protected setCurrent(layout: KeyboardLayoutData, source: KeyboardLayoutSource): void {
|
|
131
|
-
this.currentLayout = layout;
|
|
132
|
-
this.source = source;
|
|
133
|
-
this.saveState();
|
|
134
|
-
if (this.tester.inputCount && (source === 'pressed-keys' || source === 'navigator.keyboard')) {
|
|
135
|
-
const from = source === 'pressed-keys' ? 'pressed keys' : 'browser API';
|
|
136
|
-
const hardware = layout.hardware === 'mac' ? 'Mac' : 'PC';
|
|
137
|
-
this.logger.info(`Detected keyboard layout from ${from}: ${layout.name} (${hardware})`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
protected async autodetect(): Promise<[KeyboardLayoutData, KeyboardLayoutSource]> {
|
|
142
|
-
const keyboard = (navigator as NavigatorExtension).keyboard;
|
|
143
|
-
if (keyboard && keyboard.getLayoutMap) {
|
|
144
|
-
try {
|
|
145
|
-
const layoutMap = await keyboard.getLayoutMap();
|
|
146
|
-
this.testLayoutMap(layoutMap);
|
|
147
|
-
return [this.selectLayout(), 'navigator.keyboard'];
|
|
148
|
-
} catch (error) {
|
|
149
|
-
this.logger.warn('Failed to obtain keyboard layout map.', error);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return [this.selectLayout(), 'pressed-keys'];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* @param layoutMap a keyboard layout map according to https://wicg.github.io/keyboard-map/
|
|
157
|
-
*/
|
|
158
|
-
protected testLayoutMap(layoutMap: KeyboardLayoutMap): void {
|
|
159
|
-
this.tester.reset();
|
|
160
|
-
for (const [code, key] of layoutMap.entries()) {
|
|
161
|
-
this.tester.updateScores({ code, character: key });
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Select a layout based on the current tester state and the operating system
|
|
167
|
-
* and language detected from the browser.
|
|
168
|
-
*/
|
|
169
|
-
protected selectLayout(): KeyboardLayoutData {
|
|
170
|
-
const candidates = this.tester.candidates;
|
|
171
|
-
const scores = this.tester.scores;
|
|
172
|
-
const topScore = this.tester.topScore;
|
|
173
|
-
const language = navigator.language;
|
|
174
|
-
let matchingOScount = 0;
|
|
175
|
-
let topScoringCount = 0;
|
|
176
|
-
for (let i = 0; i < candidates.length; i++) {
|
|
177
|
-
if (scores[i] === topScore) {
|
|
178
|
-
const candidate = candidates[i];
|
|
179
|
-
if (osMatches(candidate.hardware)) {
|
|
180
|
-
if (language && language.startsWith(candidate.language)) {
|
|
181
|
-
return candidate;
|
|
182
|
-
}
|
|
183
|
-
matchingOScount++;
|
|
184
|
-
}
|
|
185
|
-
topScoringCount++;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
if (matchingOScount >= 1) {
|
|
189
|
-
return candidates.find((c, i) => scores[i] === topScore && osMatches(c.hardware))!;
|
|
190
|
-
}
|
|
191
|
-
if (topScoringCount >= 1) {
|
|
192
|
-
return candidates.find((_, i) => scores[i] === topScore)!;
|
|
193
|
-
}
|
|
194
|
-
return DEFAULT_LAYOUT_DATA;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
protected saveState(): Promise<void> {
|
|
198
|
-
const data: LayoutProviderState = {
|
|
199
|
-
tester: this.tester.getState(),
|
|
200
|
-
source: this.source,
|
|
201
|
-
currentLayout: this.currentLayout !== DEFAULT_LAYOUT_DATA ? getLayoutId(this.currentLayout) : undefined
|
|
202
|
-
};
|
|
203
|
-
return this.storageService.setData('keyboard', data);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
protected async loadState(): Promise<void> {
|
|
207
|
-
const data = await this.storageService.getData<LayoutProviderState>('keyboard');
|
|
208
|
-
if (data) {
|
|
209
|
-
this.tester.setState(data.tester || {});
|
|
210
|
-
this.source = data.source || 'pressed-keys';
|
|
211
|
-
if (data.currentLayout) {
|
|
212
|
-
const layout = this.tester.candidates.find(c => getLayoutId(c) === data.currentLayout);
|
|
213
|
-
if (layout) {
|
|
214
|
-
this.currentLayout = layout;
|
|
215
|
-
}
|
|
216
|
-
} else {
|
|
217
|
-
this.currentLayout = DEFAULT_LAYOUT_DATA;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export interface KeyboardLayoutData {
|
|
225
|
-
name: string;
|
|
226
|
-
hardware: 'pc' | 'mac';
|
|
227
|
-
language: string;
|
|
228
|
-
raw: NativeKeyboardLayout;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function osMatches(hardware: 'pc' | 'mac'): boolean {
|
|
232
|
-
return isOSX ? hardware === 'mac' : hardware === 'pc';
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* This is the fallback keyboard layout selected when nothing else matches.
|
|
237
|
-
* It has an empty mapping, so user inputs are handled like with a standard US keyboard.
|
|
238
|
-
*/
|
|
239
|
-
export const DEFAULT_LAYOUT_DATA: KeyboardLayoutData = {
|
|
240
|
-
name: 'US',
|
|
241
|
-
hardware: isOSX ? 'mac' : 'pc',
|
|
242
|
-
language: 'en',
|
|
243
|
-
raw: {
|
|
244
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
245
|
-
info: {} as any,
|
|
246
|
-
mapping: {}
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
export interface LayoutProviderState {
|
|
251
|
-
tester?: KeyboardTesterState;
|
|
252
|
-
source?: KeyboardLayoutSource;
|
|
253
|
-
currentLayout?: string;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export interface KeyboardTesterState {
|
|
257
|
-
scores?: { [id: string]: number };
|
|
258
|
-
topScore?: number;
|
|
259
|
-
testedInputs?: { [key: string]: string }
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Holds score values for all known keyboard layouts. Scores are updated
|
|
264
|
-
* by comparing key codes with the corresponding character produced by
|
|
265
|
-
* the user's keyboard.
|
|
266
|
-
*/
|
|
267
|
-
export class KeyboardTester {
|
|
268
|
-
|
|
269
|
-
readonly scores: number[];
|
|
270
|
-
topScore: number = 0;
|
|
271
|
-
|
|
272
|
-
private readonly testedInputs = new Map<string, string>();
|
|
273
|
-
|
|
274
|
-
get inputCount(): number {
|
|
275
|
-
return this.testedInputs.size;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
constructor(readonly candidates: KeyboardLayoutData[]) {
|
|
279
|
-
this.scores = this.candidates.map(() => 0);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
reset(): void {
|
|
283
|
-
for (let i = 0; i < this.scores.length; i++) {
|
|
284
|
-
this.scores[i] = 0;
|
|
285
|
-
}
|
|
286
|
-
this.topScore = 0;
|
|
287
|
-
this.testedInputs.clear();
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
updateScores(input: KeyValidationInput): boolean {
|
|
291
|
-
let property: 'value' | 'withShift' | 'withAltGr' | 'withShiftAltGr';
|
|
292
|
-
if (input.shiftKey && input.altKey) {
|
|
293
|
-
property = 'withShiftAltGr';
|
|
294
|
-
} else if (input.shiftKey) {
|
|
295
|
-
property = 'withShift';
|
|
296
|
-
} else if (input.altKey) {
|
|
297
|
-
property = 'withAltGr';
|
|
298
|
-
} else {
|
|
299
|
-
property = 'value';
|
|
300
|
-
}
|
|
301
|
-
const inputKey = `${input.code}.${property}`;
|
|
302
|
-
if (this.testedInputs.has(inputKey)) {
|
|
303
|
-
if (this.testedInputs.get(inputKey) === input.character) {
|
|
304
|
-
return false;
|
|
305
|
-
} else {
|
|
306
|
-
// The same input keystroke leads to a different character:
|
|
307
|
-
// probably a keyboard layout change, so forget all previous scores
|
|
308
|
-
this.reset();
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const scores = this.scores;
|
|
313
|
-
for (let i = 0; i < this.candidates.length; i++) {
|
|
314
|
-
scores[i] += this.testCandidate(this.candidates[i], input, property);
|
|
315
|
-
if (scores[i] > this.topScore) {
|
|
316
|
-
this.topScore = scores[i];
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
this.testedInputs.set(inputKey, input.character);
|
|
320
|
-
return true;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
protected testCandidate(candidate: KeyboardLayoutData, input: KeyValidationInput,
|
|
324
|
-
property: 'value' | 'withShift' | 'withAltGr' | 'withShiftAltGr'): number {
|
|
325
|
-
const keyMapping = candidate.raw.mapping[input.code];
|
|
326
|
-
if (keyMapping && keyMapping[property]) {
|
|
327
|
-
return keyMapping[property] === input.character ? 1 : 0;
|
|
328
|
-
} else {
|
|
329
|
-
return 0;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
getState(): KeyboardTesterState {
|
|
334
|
-
const scores: { [id: string]: number } = {};
|
|
335
|
-
for (let i = 0; i < this.scores.length; i++) {
|
|
336
|
-
scores[getLayoutId(this.candidates[i])] = this.scores[i];
|
|
337
|
-
}
|
|
338
|
-
const testedInputs: { [key: string]: string } = {};
|
|
339
|
-
for (const [key, character] of this.testedInputs.entries()) {
|
|
340
|
-
testedInputs[key] = character;
|
|
341
|
-
}
|
|
342
|
-
return {
|
|
343
|
-
scores,
|
|
344
|
-
topScore: this.topScore,
|
|
345
|
-
testedInputs
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
setState(state: KeyboardTesterState): void {
|
|
350
|
-
this.reset();
|
|
351
|
-
if (state.scores) {
|
|
352
|
-
const layoutIds = this.candidates.map(getLayoutId);
|
|
353
|
-
for (const id in state.scores) {
|
|
354
|
-
if (state.scores.hasOwnProperty(id)) {
|
|
355
|
-
const index = layoutIds.indexOf(id);
|
|
356
|
-
if (index > 0) {
|
|
357
|
-
this.scores[index] = state.scores[id];
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
if (state.topScore) {
|
|
363
|
-
this.topScore = state.topScore;
|
|
364
|
-
}
|
|
365
|
-
if (state.testedInputs) {
|
|
366
|
-
for (const key in state.testedInputs) {
|
|
367
|
-
if (state.testedInputs.hasOwnProperty(key)) {
|
|
368
|
-
this.testedInputs.set(key, state.testedInputs[key]);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* API specified by https://wicg.github.io/keyboard-map/
|
|
378
|
-
*/
|
|
379
|
-
interface NavigatorExtension extends Navigator {
|
|
380
|
-
keyboard: Keyboard;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
interface Keyboard {
|
|
384
|
-
getLayoutMap(): Promise<KeyboardLayoutMap>;
|
|
385
|
-
addEventListener(type: 'layoutchange', listener: EventListenerOrEventListenerObject): void;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
type KeyboardLayoutMap = Map<string, string>;
|
|
389
|
-
|
|
390
|
-
function getLayoutId(layout: KeyboardLayoutData): string {
|
|
391
|
-
return `${layout.language}-${layout.name.replace(' ', '_')}-${layout.hardware}`;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Keyboard layout files are expected to have the following name scheme:
|
|
396
|
-
* `language-name-hardware.json`
|
|
397
|
-
*
|
|
398
|
-
* - `language`: A language subtag according to IETF BCP 47
|
|
399
|
-
* - `name`: Display name of the keyboard layout (without dashes)
|
|
400
|
-
* - `hardware`: `pc` or `mac`
|
|
401
|
-
*/
|
|
402
|
-
function loadLayout(fileName: string): KeyboardLayoutData {
|
|
403
|
-
const [language, name, hardware] = fileName.split('-');
|
|
404
|
-
return {
|
|
405
|
-
name: name.replace('_', ' '),
|
|
406
|
-
hardware: hardware as 'pc' | 'mac',
|
|
407
|
-
language,
|
|
408
|
-
// Webpack knows what to do here and it should bundle all files under `../../../src/common/keyboard/layouts/`
|
|
409
|
-
// eslint-disable-next-line import/no-dynamic-require
|
|
410
|
-
raw: require('../../../src/common/keyboard/layouts/' + fileName + '.json')
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function loadAllLayouts(): KeyboardLayoutData[] {
|
|
415
|
-
// The order of keyboard layouts is relevant for autodetection. Layouts with
|
|
416
|
-
// lower index have a higher chance of being selected.
|
|
417
|
-
// The current ordering approach is to sort by estimated number of developers
|
|
418
|
-
// in the respective country (taken from the Stack Overflow Developer Survey),
|
|
419
|
-
// but keeping all layouts of the same language together.
|
|
420
|
-
return [
|
|
421
|
-
'en-US-pc',
|
|
422
|
-
'en-US-mac',
|
|
423
|
-
'en-Dvorak-pc',
|
|
424
|
-
'en-Dvorak-mac',
|
|
425
|
-
'en-Dvorak_Lefthanded-pc',
|
|
426
|
-
'en-Dvorak_Lefthanded-mac',
|
|
427
|
-
'en-Dvorak_Righthanded-pc',
|
|
428
|
-
'en-Dvorak_Righthanded-mac',
|
|
429
|
-
'en-Colemak-mac',
|
|
430
|
-
'en-British-pc',
|
|
431
|
-
'en-British-mac',
|
|
432
|
-
'de-German-pc',
|
|
433
|
-
'de-German-mac',
|
|
434
|
-
'de-Swiss_German-pc',
|
|
435
|
-
'de-Swiss_German-mac',
|
|
436
|
-
'fr-French-pc',
|
|
437
|
-
'fr-French-mac',
|
|
438
|
-
'fr-Canadian_French-pc',
|
|
439
|
-
'fr-Canadian_French-mac',
|
|
440
|
-
'fr-Swiss_French-pc',
|
|
441
|
-
'fr-Swiss_French-mac',
|
|
442
|
-
'fr-Bepo-pc',
|
|
443
|
-
'pt-Portuguese-pc',
|
|
444
|
-
'pt-Portuguese-mac',
|
|
445
|
-
'pt-Brazilian-mac',
|
|
446
|
-
'pl-Polish-pc',
|
|
447
|
-
'pl-Polish-mac',
|
|
448
|
-
'nl-Dutch-pc',
|
|
449
|
-
'nl-Dutch-mac',
|
|
450
|
-
'es-Spanish-pc',
|
|
451
|
-
'es-Spanish-mac',
|
|
452
|
-
'it-Italian-pc',
|
|
453
|
-
'it-Italian-mac',
|
|
454
|
-
'sv-Swedish-pc',
|
|
455
|
-
'sv-Swedish-mac',
|
|
456
|
-
'tr-Turkish_Q-pc',
|
|
457
|
-
'tr-Turkish_Q-mac',
|
|
458
|
-
'cs-Czech-pc',
|
|
459
|
-
'cs-Czech-mac',
|
|
460
|
-
'ro-Romanian-pc',
|
|
461
|
-
'ro-Romanian-mac',
|
|
462
|
-
'da-Danish-pc',
|
|
463
|
-
'da-Danish-mac',
|
|
464
|
-
'nb-Norwegian-pc',
|
|
465
|
-
'nb-Norwegian-mac',
|
|
466
|
-
'hu-Hungarian-pc',
|
|
467
|
-
'hu-Hungarian-mac'
|
|
468
|
-
].map(loadLayout);
|
|
469
|
-
}
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2019 TypeFox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { injectable, postConstruct, inject } from 'inversify';
|
|
18
|
+
import { isOSX } from '../../common/os';
|
|
19
|
+
import { Emitter, Event } from '../../common/event';
|
|
20
|
+
import { ILogger } from '../../common/logger';
|
|
21
|
+
import { Deferred } from '../../common/promise-util';
|
|
22
|
+
import {
|
|
23
|
+
NativeKeyboardLayout, KeyboardLayoutProvider, KeyboardLayoutChangeNotifier, KeyValidator, KeyValidationInput
|
|
24
|
+
} from '../../common/keyboard/keyboard-layout-provider';
|
|
25
|
+
import { LocalStorageService } from '../storage-service';
|
|
26
|
+
|
|
27
|
+
export type KeyboardLayoutSource = 'navigator.keyboard' | 'user-choice' | 'pressed-keys';
|
|
28
|
+
|
|
29
|
+
@injectable()
|
|
30
|
+
export class BrowserKeyboardLayoutProvider implements KeyboardLayoutProvider, KeyboardLayoutChangeNotifier, KeyValidator {
|
|
31
|
+
|
|
32
|
+
@inject(ILogger)
|
|
33
|
+
protected readonly logger: ILogger;
|
|
34
|
+
|
|
35
|
+
@inject(LocalStorageService)
|
|
36
|
+
protected readonly storageService: LocalStorageService;
|
|
37
|
+
|
|
38
|
+
protected readonly initialized = new Deferred();
|
|
39
|
+
protected readonly nativeLayoutChanged = new Emitter<NativeKeyboardLayout>();
|
|
40
|
+
|
|
41
|
+
get onDidChangeNativeLayout(): Event<NativeKeyboardLayout> {
|
|
42
|
+
return this.nativeLayoutChanged.event;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected readonly tester = new KeyboardTester(loadAllLayouts());
|
|
46
|
+
protected source: KeyboardLayoutSource = 'pressed-keys';
|
|
47
|
+
protected currentLayout: KeyboardLayoutData = DEFAULT_LAYOUT_DATA;
|
|
48
|
+
|
|
49
|
+
get allLayoutData(): KeyboardLayoutData[] {
|
|
50
|
+
return this.tester.candidates.slice();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get currentLayoutData(): KeyboardLayoutData {
|
|
54
|
+
return this.currentLayout;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get currentLayoutSource(): KeyboardLayoutSource {
|
|
58
|
+
return this.source;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@postConstruct()
|
|
62
|
+
protected init(): void {
|
|
63
|
+
this.doInit();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected async doInit(): Promise<void> {
|
|
67
|
+
await this.loadState();
|
|
68
|
+
const keyboard = (navigator as NavigatorExtension).keyboard;
|
|
69
|
+
if (keyboard && keyboard.addEventListener) {
|
|
70
|
+
keyboard.addEventListener('layoutchange', async () => {
|
|
71
|
+
const newLayout = await this.getNativeLayout();
|
|
72
|
+
this.nativeLayoutChanged.fire(newLayout);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
this.initialized.resolve();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async getNativeLayout(): Promise<NativeKeyboardLayout> {
|
|
79
|
+
await this.initialized.promise;
|
|
80
|
+
if (this.source === 'user-choice') {
|
|
81
|
+
return this.currentLayout.raw;
|
|
82
|
+
}
|
|
83
|
+
const [layout, source] = await this.autodetect();
|
|
84
|
+
this.setCurrent(layout, source);
|
|
85
|
+
return layout.raw;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Set user-chosen keyboard layout data.
|
|
90
|
+
*/
|
|
91
|
+
async setLayoutData(layout: KeyboardLayoutData | 'autodetect'): Promise<KeyboardLayoutData> {
|
|
92
|
+
if (layout === 'autodetect') {
|
|
93
|
+
if (this.source === 'user-choice') {
|
|
94
|
+
const [newLayout, source] = await this.autodetect();
|
|
95
|
+
this.setCurrent(newLayout, source);
|
|
96
|
+
this.nativeLayoutChanged.fire(newLayout.raw);
|
|
97
|
+
return newLayout;
|
|
98
|
+
}
|
|
99
|
+
return this.currentLayout;
|
|
100
|
+
} else {
|
|
101
|
+
if (this.source !== 'user-choice' || layout !== this.currentLayout) {
|
|
102
|
+
this.setCurrent(layout, 'user-choice');
|
|
103
|
+
this.nativeLayoutChanged.fire(layout.raw);
|
|
104
|
+
}
|
|
105
|
+
return layout;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Test all known keyboard layouts with the given combination of pressed key and
|
|
111
|
+
* produced character. Matching layouts have their score increased (see class
|
|
112
|
+
* KeyboardTester). If this leads to a change of the top-scoring layout, a layout
|
|
113
|
+
* change event is fired.
|
|
114
|
+
*/
|
|
115
|
+
validateKey(keyCode: KeyValidationInput): void {
|
|
116
|
+
if (this.source !== 'pressed-keys') {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const accepted = this.tester.updateScores(keyCode);
|
|
120
|
+
if (!accepted) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const layout = this.selectLayout();
|
|
124
|
+
if (layout !== this.currentLayout && layout !== DEFAULT_LAYOUT_DATA) {
|
|
125
|
+
this.setCurrent(layout, 'pressed-keys');
|
|
126
|
+
this.nativeLayoutChanged.fire(layout.raw);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
protected setCurrent(layout: KeyboardLayoutData, source: KeyboardLayoutSource): void {
|
|
131
|
+
this.currentLayout = layout;
|
|
132
|
+
this.source = source;
|
|
133
|
+
this.saveState();
|
|
134
|
+
if (this.tester.inputCount && (source === 'pressed-keys' || source === 'navigator.keyboard')) {
|
|
135
|
+
const from = source === 'pressed-keys' ? 'pressed keys' : 'browser API';
|
|
136
|
+
const hardware = layout.hardware === 'mac' ? 'Mac' : 'PC';
|
|
137
|
+
this.logger.info(`Detected keyboard layout from ${from}: ${layout.name} (${hardware})`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected async autodetect(): Promise<[KeyboardLayoutData, KeyboardLayoutSource]> {
|
|
142
|
+
const keyboard = (navigator as NavigatorExtension).keyboard;
|
|
143
|
+
if (keyboard && keyboard.getLayoutMap) {
|
|
144
|
+
try {
|
|
145
|
+
const layoutMap = await keyboard.getLayoutMap();
|
|
146
|
+
this.testLayoutMap(layoutMap);
|
|
147
|
+
return [this.selectLayout(), 'navigator.keyboard'];
|
|
148
|
+
} catch (error) {
|
|
149
|
+
this.logger.warn('Failed to obtain keyboard layout map.', error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return [this.selectLayout(), 'pressed-keys'];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param layoutMap a keyboard layout map according to https://wicg.github.io/keyboard-map/
|
|
157
|
+
*/
|
|
158
|
+
protected testLayoutMap(layoutMap: KeyboardLayoutMap): void {
|
|
159
|
+
this.tester.reset();
|
|
160
|
+
for (const [code, key] of layoutMap.entries()) {
|
|
161
|
+
this.tester.updateScores({ code, character: key });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Select a layout based on the current tester state and the operating system
|
|
167
|
+
* and language detected from the browser.
|
|
168
|
+
*/
|
|
169
|
+
protected selectLayout(): KeyboardLayoutData {
|
|
170
|
+
const candidates = this.tester.candidates;
|
|
171
|
+
const scores = this.tester.scores;
|
|
172
|
+
const topScore = this.tester.topScore;
|
|
173
|
+
const language = navigator.language;
|
|
174
|
+
let matchingOScount = 0;
|
|
175
|
+
let topScoringCount = 0;
|
|
176
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
177
|
+
if (scores[i] === topScore) {
|
|
178
|
+
const candidate = candidates[i];
|
|
179
|
+
if (osMatches(candidate.hardware)) {
|
|
180
|
+
if (language && language.startsWith(candidate.language)) {
|
|
181
|
+
return candidate;
|
|
182
|
+
}
|
|
183
|
+
matchingOScount++;
|
|
184
|
+
}
|
|
185
|
+
topScoringCount++;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (matchingOScount >= 1) {
|
|
189
|
+
return candidates.find((c, i) => scores[i] === topScore && osMatches(c.hardware))!;
|
|
190
|
+
}
|
|
191
|
+
if (topScoringCount >= 1) {
|
|
192
|
+
return candidates.find((_, i) => scores[i] === topScore)!;
|
|
193
|
+
}
|
|
194
|
+
return DEFAULT_LAYOUT_DATA;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
protected saveState(): Promise<void> {
|
|
198
|
+
const data: LayoutProviderState = {
|
|
199
|
+
tester: this.tester.getState(),
|
|
200
|
+
source: this.source,
|
|
201
|
+
currentLayout: this.currentLayout !== DEFAULT_LAYOUT_DATA ? getLayoutId(this.currentLayout) : undefined
|
|
202
|
+
};
|
|
203
|
+
return this.storageService.setData('keyboard', data);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
protected async loadState(): Promise<void> {
|
|
207
|
+
const data = await this.storageService.getData<LayoutProviderState>('keyboard');
|
|
208
|
+
if (data) {
|
|
209
|
+
this.tester.setState(data.tester || {});
|
|
210
|
+
this.source = data.source || 'pressed-keys';
|
|
211
|
+
if (data.currentLayout) {
|
|
212
|
+
const layout = this.tester.candidates.find(c => getLayoutId(c) === data.currentLayout);
|
|
213
|
+
if (layout) {
|
|
214
|
+
this.currentLayout = layout;
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
this.currentLayout = DEFAULT_LAYOUT_DATA;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface KeyboardLayoutData {
|
|
225
|
+
name: string;
|
|
226
|
+
hardware: 'pc' | 'mac';
|
|
227
|
+
language: string;
|
|
228
|
+
raw: NativeKeyboardLayout;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function osMatches(hardware: 'pc' | 'mac'): boolean {
|
|
232
|
+
return isOSX ? hardware === 'mac' : hardware === 'pc';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* This is the fallback keyboard layout selected when nothing else matches.
|
|
237
|
+
* It has an empty mapping, so user inputs are handled like with a standard US keyboard.
|
|
238
|
+
*/
|
|
239
|
+
export const DEFAULT_LAYOUT_DATA: KeyboardLayoutData = {
|
|
240
|
+
name: 'US',
|
|
241
|
+
hardware: isOSX ? 'mac' : 'pc',
|
|
242
|
+
language: 'en',
|
|
243
|
+
raw: {
|
|
244
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
245
|
+
info: {} as any,
|
|
246
|
+
mapping: {}
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export interface LayoutProviderState {
|
|
251
|
+
tester?: KeyboardTesterState;
|
|
252
|
+
source?: KeyboardLayoutSource;
|
|
253
|
+
currentLayout?: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface KeyboardTesterState {
|
|
257
|
+
scores?: { [id: string]: number };
|
|
258
|
+
topScore?: number;
|
|
259
|
+
testedInputs?: { [key: string]: string }
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Holds score values for all known keyboard layouts. Scores are updated
|
|
264
|
+
* by comparing key codes with the corresponding character produced by
|
|
265
|
+
* the user's keyboard.
|
|
266
|
+
*/
|
|
267
|
+
export class KeyboardTester {
|
|
268
|
+
|
|
269
|
+
readonly scores: number[];
|
|
270
|
+
topScore: number = 0;
|
|
271
|
+
|
|
272
|
+
private readonly testedInputs = new Map<string, string>();
|
|
273
|
+
|
|
274
|
+
get inputCount(): number {
|
|
275
|
+
return this.testedInputs.size;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
constructor(readonly candidates: KeyboardLayoutData[]) {
|
|
279
|
+
this.scores = this.candidates.map(() => 0);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
reset(): void {
|
|
283
|
+
for (let i = 0; i < this.scores.length; i++) {
|
|
284
|
+
this.scores[i] = 0;
|
|
285
|
+
}
|
|
286
|
+
this.topScore = 0;
|
|
287
|
+
this.testedInputs.clear();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
updateScores(input: KeyValidationInput): boolean {
|
|
291
|
+
let property: 'value' | 'withShift' | 'withAltGr' | 'withShiftAltGr';
|
|
292
|
+
if (input.shiftKey && input.altKey) {
|
|
293
|
+
property = 'withShiftAltGr';
|
|
294
|
+
} else if (input.shiftKey) {
|
|
295
|
+
property = 'withShift';
|
|
296
|
+
} else if (input.altKey) {
|
|
297
|
+
property = 'withAltGr';
|
|
298
|
+
} else {
|
|
299
|
+
property = 'value';
|
|
300
|
+
}
|
|
301
|
+
const inputKey = `${input.code}.${property}`;
|
|
302
|
+
if (this.testedInputs.has(inputKey)) {
|
|
303
|
+
if (this.testedInputs.get(inputKey) === input.character) {
|
|
304
|
+
return false;
|
|
305
|
+
} else {
|
|
306
|
+
// The same input keystroke leads to a different character:
|
|
307
|
+
// probably a keyboard layout change, so forget all previous scores
|
|
308
|
+
this.reset();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const scores = this.scores;
|
|
313
|
+
for (let i = 0; i < this.candidates.length; i++) {
|
|
314
|
+
scores[i] += this.testCandidate(this.candidates[i], input, property);
|
|
315
|
+
if (scores[i] > this.topScore) {
|
|
316
|
+
this.topScore = scores[i];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
this.testedInputs.set(inputKey, input.character);
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
protected testCandidate(candidate: KeyboardLayoutData, input: KeyValidationInput,
|
|
324
|
+
property: 'value' | 'withShift' | 'withAltGr' | 'withShiftAltGr'): number {
|
|
325
|
+
const keyMapping = candidate.raw.mapping[input.code];
|
|
326
|
+
if (keyMapping && keyMapping[property]) {
|
|
327
|
+
return keyMapping[property] === input.character ? 1 : 0;
|
|
328
|
+
} else {
|
|
329
|
+
return 0;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
getState(): KeyboardTesterState {
|
|
334
|
+
const scores: { [id: string]: number } = {};
|
|
335
|
+
for (let i = 0; i < this.scores.length; i++) {
|
|
336
|
+
scores[getLayoutId(this.candidates[i])] = this.scores[i];
|
|
337
|
+
}
|
|
338
|
+
const testedInputs: { [key: string]: string } = {};
|
|
339
|
+
for (const [key, character] of this.testedInputs.entries()) {
|
|
340
|
+
testedInputs[key] = character;
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
scores,
|
|
344
|
+
topScore: this.topScore,
|
|
345
|
+
testedInputs
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
setState(state: KeyboardTesterState): void {
|
|
350
|
+
this.reset();
|
|
351
|
+
if (state.scores) {
|
|
352
|
+
const layoutIds = this.candidates.map(getLayoutId);
|
|
353
|
+
for (const id in state.scores) {
|
|
354
|
+
if (state.scores.hasOwnProperty(id)) {
|
|
355
|
+
const index = layoutIds.indexOf(id);
|
|
356
|
+
if (index > 0) {
|
|
357
|
+
this.scores[index] = state.scores[id];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (state.topScore) {
|
|
363
|
+
this.topScore = state.topScore;
|
|
364
|
+
}
|
|
365
|
+
if (state.testedInputs) {
|
|
366
|
+
for (const key in state.testedInputs) {
|
|
367
|
+
if (state.testedInputs.hasOwnProperty(key)) {
|
|
368
|
+
this.testedInputs.set(key, state.testedInputs[key]);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* API specified by https://wicg.github.io/keyboard-map/
|
|
378
|
+
*/
|
|
379
|
+
interface NavigatorExtension extends Navigator {
|
|
380
|
+
keyboard: Keyboard;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
interface Keyboard {
|
|
384
|
+
getLayoutMap(): Promise<KeyboardLayoutMap>;
|
|
385
|
+
addEventListener(type: 'layoutchange', listener: EventListenerOrEventListenerObject): void;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
type KeyboardLayoutMap = Map<string, string>;
|
|
389
|
+
|
|
390
|
+
function getLayoutId(layout: KeyboardLayoutData): string {
|
|
391
|
+
return `${layout.language}-${layout.name.replace(' ', '_')}-${layout.hardware}`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Keyboard layout files are expected to have the following name scheme:
|
|
396
|
+
* `language-name-hardware.json`
|
|
397
|
+
*
|
|
398
|
+
* - `language`: A language subtag according to IETF BCP 47
|
|
399
|
+
* - `name`: Display name of the keyboard layout (without dashes)
|
|
400
|
+
* - `hardware`: `pc` or `mac`
|
|
401
|
+
*/
|
|
402
|
+
function loadLayout(fileName: string): KeyboardLayoutData {
|
|
403
|
+
const [language, name, hardware] = fileName.split('-');
|
|
404
|
+
return {
|
|
405
|
+
name: name.replace('_', ' '),
|
|
406
|
+
hardware: hardware as 'pc' | 'mac',
|
|
407
|
+
language,
|
|
408
|
+
// Webpack knows what to do here and it should bundle all files under `../../../src/common/keyboard/layouts/`
|
|
409
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
410
|
+
raw: require('../../../src/common/keyboard/layouts/' + fileName + '.json')
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function loadAllLayouts(): KeyboardLayoutData[] {
|
|
415
|
+
// The order of keyboard layouts is relevant for autodetection. Layouts with
|
|
416
|
+
// lower index have a higher chance of being selected.
|
|
417
|
+
// The current ordering approach is to sort by estimated number of developers
|
|
418
|
+
// in the respective country (taken from the Stack Overflow Developer Survey),
|
|
419
|
+
// but keeping all layouts of the same language together.
|
|
420
|
+
return [
|
|
421
|
+
'en-US-pc',
|
|
422
|
+
'en-US-mac',
|
|
423
|
+
'en-Dvorak-pc',
|
|
424
|
+
'en-Dvorak-mac',
|
|
425
|
+
'en-Dvorak_Lefthanded-pc',
|
|
426
|
+
'en-Dvorak_Lefthanded-mac',
|
|
427
|
+
'en-Dvorak_Righthanded-pc',
|
|
428
|
+
'en-Dvorak_Righthanded-mac',
|
|
429
|
+
'en-Colemak-mac',
|
|
430
|
+
'en-British-pc',
|
|
431
|
+
'en-British-mac',
|
|
432
|
+
'de-German-pc',
|
|
433
|
+
'de-German-mac',
|
|
434
|
+
'de-Swiss_German-pc',
|
|
435
|
+
'de-Swiss_German-mac',
|
|
436
|
+
'fr-French-pc',
|
|
437
|
+
'fr-French-mac',
|
|
438
|
+
'fr-Canadian_French-pc',
|
|
439
|
+
'fr-Canadian_French-mac',
|
|
440
|
+
'fr-Swiss_French-pc',
|
|
441
|
+
'fr-Swiss_French-mac',
|
|
442
|
+
'fr-Bepo-pc',
|
|
443
|
+
'pt-Portuguese-pc',
|
|
444
|
+
'pt-Portuguese-mac',
|
|
445
|
+
'pt-Brazilian-mac',
|
|
446
|
+
'pl-Polish-pc',
|
|
447
|
+
'pl-Polish-mac',
|
|
448
|
+
'nl-Dutch-pc',
|
|
449
|
+
'nl-Dutch-mac',
|
|
450
|
+
'es-Spanish-pc',
|
|
451
|
+
'es-Spanish-mac',
|
|
452
|
+
'it-Italian-pc',
|
|
453
|
+
'it-Italian-mac',
|
|
454
|
+
'sv-Swedish-pc',
|
|
455
|
+
'sv-Swedish-mac',
|
|
456
|
+
'tr-Turkish_Q-pc',
|
|
457
|
+
'tr-Turkish_Q-mac',
|
|
458
|
+
'cs-Czech-pc',
|
|
459
|
+
'cs-Czech-mac',
|
|
460
|
+
'ro-Romanian-pc',
|
|
461
|
+
'ro-Romanian-mac',
|
|
462
|
+
'da-Danish-pc',
|
|
463
|
+
'da-Danish-mac',
|
|
464
|
+
'nb-Norwegian-pc',
|
|
465
|
+
'nb-Norwegian-mac',
|
|
466
|
+
'hu-Hungarian-pc',
|
|
467
|
+
'hu-Hungarian-mac'
|
|
468
|
+
].map(loadLayout);
|
|
469
|
+
}
|