From 8d25697e98b51d66c30ebbac23f3ac5b591d60f7 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 24 Mar 2021 17:47:45 +0100 Subject: [PATCH] Improved the keyboad hook listener --- shared/js/PPTListener.ts | 120 ++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 53 deletions(-) diff --git a/shared/js/PPTListener.ts b/shared/js/PPTListener.ts index 2c8306c2..364b952c 100644 --- a/shared/js/PPTListener.ts +++ b/shared/js/PPTListener.ts @@ -148,16 +148,20 @@ export interface KeyEvent extends KeyDescriptor { readonly key: string; } -export interface KeyHook extends KeyDescriptor { +export interface KeyHook extends Partial { callbackPress: () => any; callbackRelease: () => any; } +interface RegisteredKeyHook extends KeyHook { + triggered: boolean +} + export interface KeyBoardBackend { registerListener(listener: (event: KeyEvent) => void); unregisterListener(listener: (event: KeyEvent) => void); - registerHook(hook: KeyHook); + registerHook(hook: KeyHook) : () => void; unregisterHook(hook: KeyHook); isKeyPressed(key: string | SpecialKey) : boolean; @@ -168,8 +172,7 @@ export class AbstractKeyBoard implements KeyBoardBackend { protected readonly activeSpecialKeys: { [key: number] : boolean }; protected readonly activeKeys; - protected registeredKeyHooks: KeyHook[] = []; - protected activeKeyHooks: KeyHook[] = []; + protected registeredKeyHooks: RegisteredKeyHook[] = []; constructor() { this.activeSpecialKeys = {}; @@ -188,12 +191,26 @@ export class AbstractKeyBoard implements KeyBoardBackend { } registerHook(hook: KeyHook) { - this.registeredKeyHooks.push(hook); + const registeredHook: RegisteredKeyHook = { + triggered: false, + ...hook + }; + + this.registeredKeyHooks.push(registeredHook); + if(this.shouldHookBeActive(registeredHook)) { + registeredHook.triggered = true; + registeredHook.callbackPress(); + } + + return () => this.unregisterHook(hook); } unregisterHook(hook: KeyHook) { + if(!("triggered" in hook)) { + return; + } + this.registeredKeyHooks.remove(hook); - this.activeKeyHooks.remove(hook); } registerListener(listener: (event: KeyEvent) => void) { @@ -204,6 +221,26 @@ export class AbstractKeyBoard implements KeyBoardBackend { this.registeredListener.remove(listener); } + private shouldHookBeActive(hook: KeyHook) { + if(typeof hook.keyAlt !== "undefined" && hook.keyAlt != this.activeSpecialKeys[SpecialKey.ALT]) { + return false; + } + + if(typeof hook.keyCtrl !== "undefined" && hook.keyCtrl != this.activeSpecialKeys[SpecialKey.CTRL]) { + return false; + } + + if(typeof hook.keyShift !== "undefined" && hook.keyShift != this.activeSpecialKeys[SpecialKey.SHIFT]) { + return false; + } + + if(typeof hook.keyWindows !== "undefined" && hook.keyWindows != this.activeSpecialKeys[SpecialKey.WINDOWS]) { + return false; + } + + return typeof hook.keyCode === "undefined" || typeof this.activeKeys[hook.keyCode] !== "undefined"; + } + protected fireKeyEvent(event: KeyEvent) { //console.debug("Trigger key event %o", key_event); for(const listener of this.registeredListener) { @@ -214,61 +251,34 @@ export class AbstractKeyBoard implements KeyBoardBackend { return; } - let oldHooks = [...this.activeKeyHooks]; - let newHooks = []; - this.activeSpecialKeys[SpecialKey.ALT] = event.keyAlt; this.activeSpecialKeys[SpecialKey.CTRL] = event.keyCtrl; this.activeSpecialKeys[SpecialKey.SHIFT] = event.keyShift; this.activeSpecialKeys[SpecialKey.WINDOWS] = event.keyWindows; - - delete this.activeKeys[event.keyCode]; if(event.type == EventType.KEY_PRESS) { this.activeKeys[event.keyCode] = event; - - for(const hook of this.registeredKeyHooks) { - if(hook.keyCode !== event.keyCode) { - continue; - } - - if(hook.keyAlt != event.keyAlt) { - continue; - } - - if(hook.keyCtrl != event.keyCtrl) { - continue; - } - - if(hook.keyShift != event.keyShift) { - continue; - } - - if(hook.keyWindows != event.keyWindows) { - continue; - } - - newHooks.push(hook); - if(!oldHooks.remove(hook) && hook.callbackPress) { - hook.callbackPress(); - logTrace(LogCategory.GENERAL, tr("Trigger key press for %o!"), hook); - } - } + } else { + delete this.activeKeys[event.keyCode]; } - //We have a new situation - for(const hook of oldHooks) { - //Do not test for meta key states because they could differ in a key release event - if(hook.keyCode === event.keyCode) { - if(hook.callbackRelease) { - hook.callbackRelease(); - logTrace(LogCategory.GENERAL, tr("Trigger key release for %o!"), hook); + + for(const hook of this.registeredKeyHooks) { + const hookActive = this.shouldHookBeActive(hook); + if(hookActive === hook.triggered) { + continue; + } + + hook.triggered = hookActive; + if(hookActive) { + if(hook.callbackPress) { + hook.callbackPress(); } } else { - newHooks.push(hook); + if(hook.callbackRelease) { + hook.callbackRelease(); + } } } - - this.activeKeyHooks = newHooks; } protected resetKeyboardState() { @@ -281,11 +291,15 @@ export class AbstractKeyBoard implements KeyBoardBackend { delete this.activeKeys[code]; } - for(const hook of this.activeKeyHooks) { - hook.callbackRelease(); - } + for(const hook of this.registeredKeyHooks) { + if(hook.triggered) { + if(hook.callbackRelease) { + hook.callbackRelease(); + } - this.activeKeyHooks = []; + hook.triggered = false; + } + } } }