diff --git a/packages/microeditor-envelope/src/EditorEnvelopeController.tsx b/packages/microeditor-envelope/src/EditorEnvelopeController.tsx index 0a8df47d544..1ab25e3c049 100644 --- a/packages/microeditor-envelope/src/EditorEnvelopeController.tsx +++ b/packages/microeditor-envelope/src/EditorEnvelopeController.tsx @@ -44,7 +44,8 @@ export class EditorEnvelopeController { specialDomElements: SpecialDomElements, stateControl: StateControl, renderer: Renderer, - resourceContentEditorCoordinator: ResourceContentEditorCoordinator + resourceContentEditorCoordinator: ResourceContentEditorCoordinator, + keyboardShortcutsApi: KeyboardShortcutsApi ) { this.renderer = renderer; this.editorFactory = editorFactory; @@ -59,7 +60,10 @@ export class EditorEnvelopeController { this.editorEnvelopeView!.setLoading(); editor .setContent(contentPath, editorContent.content) - .finally(() => this.editorEnvelopeView!.setLoadingFinished()) + .finally(() => { + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); + this.editorEnvelopeView!.setLoadingFinished() + }) .then(() => self.notify_ready()); } }, diff --git a/packages/microeditor-envelope/src/__tests__/EditorEnvelopeController.test.tsx b/packages/microeditor-envelope/src/__tests__/EditorEnvelopeController.test.tsx index 370bbcd0df8..c7064b202fe 100644 --- a/packages/microeditor-envelope/src/__tests__/EditorEnvelopeController.test.tsx +++ b/packages/microeditor-envelope/src/__tests__/EditorEnvelopeController.test.tsx @@ -81,7 +81,8 @@ beforeEach(() => { callback(); } }, - new ResourceContentEditorCoordinator() + new ResourceContentEditorCoordinator(), + new DefaultKeyboardShortcutsService( { channel: ChannelType.VSCODE, operatingSystem: OperatingSystem.WINDOWS }) ); }); diff --git a/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeController.test.tsx.snap b/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeController.test.tsx.snap index 3a342c42846..4a41c303cca 100644 --- a/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeController.test.tsx.snap +++ b/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeController.test.tsx.snap @@ -11,6 +11,7 @@ exports[`EditorEnvelopeController after received content 1`] = ` exposing={[Function]} keyboardShortcuts={ DefaultKeyboardShortcutsService { + "delayedKeyBindings": Array [], "editorContext": Object { "channel": "VSCODE", "operatingSystem": "WINDOWS", @@ -94,6 +95,7 @@ exports[`EditorEnvelopeController after received content 1`] = ` } keyboardShortcuts={ DefaultKeyboardShortcutsService { + "delayedKeyBindings": Array [], "editorContext": Object { "channel": "VSCODE", "operatingSystem": "WINDOWS", @@ -393,6 +395,7 @@ exports[`EditorEnvelopeController opens 1`] = ` exposing={[Function]} keyboardShortcuts={ DefaultKeyboardShortcutsService { + "delayedKeyBindings": Array [], "editorContext": Object { "channel": "VSCODE", "operatingSystem": "WINDOWS", @@ -590,6 +593,7 @@ exports[`EditorEnvelopeController receives init request 1`] = ` exposing={[Function]} keyboardShortcuts={ DefaultKeyboardShortcutsService { + "delayedKeyBindings": Array [], "editorContext": Object { "channel": "VSCODE", "operatingSystem": "WINDOWS", diff --git a/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeView.test.tsx.snap b/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeView.test.tsx.snap index 921ec677bdc..3b6474b207a 100644 --- a/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeView.test.tsx.snap +++ b/packages/microeditor-envelope/src/__tests__/__snapshots__/EditorEnvelopeView.test.tsx.snap @@ -11,6 +11,7 @@ exports[`EditorEnvelopeView after loading stops 1`] = ` } keyboardShortcuts={ DefaultKeyboardShortcutsService { + "delayedKeyBindings": Array [], "editorContext": Object { "channel": "VSCODE", "operatingSystem": "WINDOWS", @@ -41,6 +42,7 @@ exports[`EditorEnvelopeView after loading stops and editor is set 1`] = ` } keyboardShortcuts={ DefaultKeyboardShortcutsService { + "delayedKeyBindings": Array [], "editorContext": Object { "channel": "VSCODE", "operatingSystem": "WINDOWS", diff --git a/packages/microeditor-envelope/src/__tests__/keyboardShortcuts/DefaultKeyboardShortcutsService.test.ts b/packages/microeditor-envelope/src/__tests__/keyboardShortcuts/DefaultKeyboardShortcutsService.test.ts index 298c4f1d753..c768a7f7ceb 100644 --- a/packages/microeditor-envelope/src/__tests__/keyboardShortcuts/DefaultKeyboardShortcutsService.test.ts +++ b/packages/microeditor-envelope/src/__tests__/keyboardShortcuts/DefaultKeyboardShortcutsService.test.ts @@ -26,6 +26,7 @@ describe("DefaultKeyboardShortcutsService", () => { }); const [wasFired] = resolveWhenKeyPressed("ctrl+a", keyboardShortcutsApi); + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); expect(keyboardShortcutsApi.registered().length).toStrictEqual(1); fire("keydown", { ctrlKey: true, code: "KeyA" }); @@ -40,6 +41,7 @@ describe("DefaultKeyboardShortcutsService", () => { }); const [wasFired] = resolveWhenKeyPressed("ctrl+a", keyboardShortcutsApi); + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); expect(keyboardShortcutsApi.registered().length).toStrictEqual(1); fire("keydown", { metaKey: true, code: "KeyA" }); await wasFired; @@ -54,6 +56,7 @@ describe("DefaultKeyboardShortcutsService", () => { }); const [wasFiredDownA, wasFiredUpA] = resolveWhenKeyDownThenUp("ctrl+a", keyboardShortcutsApi); + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); expect(keyboardShortcutsApi.registered().length).toStrictEqual(1); fire("keydown", { ctrlKey: true, code: "KeyA" }); await wasFiredDownA; @@ -66,6 +69,7 @@ describe("DefaultKeyboardShortcutsService", () => { // const [wasFiredDownB, wasFiredUpB] = resolveWhenKeyDownThenUp("ctrl+b", keyboardShortcutsApi); + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); expect(keyboardShortcutsApi.registered().length).toStrictEqual(2); fire("keydown", { ctrlKey: true, code: "KeyB" }); await wasFiredDownB; @@ -83,6 +87,7 @@ describe("DefaultKeyboardShortcutsService", () => { }); const [wasFired] = resolveWhenKeyPressedOnce("ctrl+c", keyboardShortcutsApi); + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); expect(keyboardShortcutsApi.registered().length).toStrictEqual(1); fire("keydown", { ctrlKey: true, code: "KeyC" }); @@ -98,6 +103,7 @@ describe("DefaultKeyboardShortcutsService", () => { }); const [wasFired, id] = resolveWhenKeyPressed("ctrl+c", keyboardShortcutsApi); + keyboardShortcutsApi.executeDelayedShortcutsRegistration(); expect(keyboardShortcutsApi.registered().length).toStrictEqual(1); fire("keydown", { ctrlKey: true, code: "KeyC" }); diff --git a/packages/microeditor-envelope/src/api/keyboardShortcuts/DefaultKeyboardShortcutsService.ts b/packages/microeditor-envelope/src/api/keyboardShortcuts/DefaultKeyboardShortcutsService.ts index 7c2ed0b0b15..cac2733cf87 100644 --- a/packages/microeditor-envelope/src/api/keyboardShortcuts/DefaultKeyboardShortcutsService.ts +++ b/packages/microeditor-envelope/src/api/keyboardShortcuts/DefaultKeyboardShortcutsService.ts @@ -80,11 +80,22 @@ const KEY_CODES = new Map([ ["z", "KeyZ"] ]); +enum ShortCutsType { + KeyDownThenUp, + KeyDown +} + +export interface DelayedRegisterKeyBinding{ + type: ShortCutsType; + binding: KeyBinding; +} + export class DefaultKeyboardShortcutsService implements KeyboardShortcutsApi { private readonly editorContext: EditorContext; private eventIdentifiers = 1; private readonly keyBindings = new Map(); + private delayedKeyBindings = new Array(); constructor(editorContext: EditorContext) { this.editorContext = editorContext; @@ -130,12 +141,25 @@ export class DefaultKeyboardShortcutsService implements KeyboardShortcutsApi { this.keyBindings.set(this.eventIdentifiers, keyBinding); - this.keyBindingElement(keyBinding).addEventListener("keydown", keyBinding.listener); - this.keyBindingElement(keyBinding).addEventListener("keyup", keyBinding.listener); - + if (keyBinding?.opts?.element || document.querySelector(".session-container")) { + this.keyBindingElement(keyBinding).addEventListener("keydown", keyBinding.listener); + this.keyBindingElement(keyBinding).addEventListener("keyup", keyBinding.listener); + } + else { + const delayedShorcut = { + type: ShortCutsType.KeyDownThenUp, + binding: keyBinding, + }; + this.delayedKeyBindings.push(delayedShorcut); + } return this.eventIdentifiers++; } + private keyBindingElement(keyBinding?: KeyBinding) { + return keyBinding?.opts?.element ?? document.querySelector(".session-container") ?? window; + } + + public registerKeyPress( combination: string, label: string, @@ -156,17 +180,41 @@ export class DefaultKeyboardShortcutsService implements KeyboardShortcutsApi { console.debug(`Fired (press) [${combination}]!`); onKeyPress(e.target); } - return true; }, opts }; this.keyBindings.set(this.eventIdentifiers, keyBinding); - this.keyBindingElement(keyBinding).addEventListener("keydown", keyBinding.listener); + + if (keyBinding?.opts?.element || document.querySelector(".session-container")) { + this.keyBindingElement(keyBinding).addEventListener("keydown", keyBinding.listener); + } + else { + const delayedShorcut = { + type: ShortCutsType.KeyDown, + binding: keyBinding, + }; + this.delayedKeyBindings.push(delayedShorcut); + } + return this.eventIdentifiers++; } + public executeDelayedShortcutsRegistration() { + this.delayedKeyBindings.forEach(delayedKeyBindings => { + + if (delayedKeyBindings.type === ShortCutsType.KeyDown) { + this.keyBindingElement(delayedKeyBindings.binding).addEventListener("keydown", delayedKeyBindings.binding.listener); + } + else { + this.keyBindingElement(delayedKeyBindings.binding).addEventListener("keydown", delayedKeyBindings.binding.listener); + this.keyBindingElement(delayedKeyBindings.binding).addEventListener("keyup", delayedKeyBindings.binding.listener); + } + }); + this.delayedKeyBindings = []; + } + public registerKeyPressOnce( combination: string, onKeyPress: (target: EventTarget | null) => Thenable, @@ -185,10 +233,6 @@ export class DefaultKeyboardShortcutsService implements KeyboardShortcutsApi { return id; } - private keyBindingElement(keyBinding?: KeyBinding) { - return keyBinding?.opts?.element ?? document.querySelector(".session-container") ?? window; - } - public deregister(id: number): void { const keyBinding = this.keyBindings.get(id); this.keyBindingElement(keyBinding).removeEventListener("keypress", keyBinding?.listener!); diff --git a/packages/microeditor-envelope/src/api/keyboardShortcuts/KeyboardShorcutsApi.ts b/packages/microeditor-envelope/src/api/keyboardShortcuts/KeyboardShorcutsApi.ts index 2b63c3563f4..1c67ab6c25c 100644 --- a/packages/microeditor-envelope/src/api/keyboardShortcuts/KeyboardShorcutsApi.ts +++ b/packages/microeditor-envelope/src/api/keyboardShortcuts/KeyboardShorcutsApi.ts @@ -73,11 +73,15 @@ export interface KeyboardShortcutsApi { */ registerKeyPressOnce(combination: string, action: () => Thenable, opts?: KeyBindingServiceOpts): number; - /** * Returns a list of all the registered Keyboard Shortcuts. */ registered(): KeyBinding[]; + + /** + * Execute delayed shortcuts after envelope load. + */ + executeDelayedShortcutsRegistration(): void; } /** diff --git a/packages/microeditor-envelope/src/index.ts b/packages/microeditor-envelope/src/index.ts index 16a4c9c0eb8..a2f582bdb03 100644 --- a/packages/microeditor-envelope/src/index.ts +++ b/packages/microeditor-envelope/src/index.ts @@ -76,7 +76,8 @@ export function init(args: { specialDomElements, stateControl, renderer, - resourceContentEditorCoordinator + resourceContentEditorCoordinator, + keyboardShortcutsService ); return editorEnvelopeController