From 5d9d96996e1b80ecca94023e20476e5e2f85bbff Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 16 Jan 2021 23:07:21 -0500 Subject: [PATCH] Optimize hotkey handler to not hook any events if cannot do anything (#1260) --- ext/mixed/js/hotkey-handler.js | 47 ++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/ext/mixed/js/hotkey-handler.js b/ext/mixed/js/hotkey-handler.js index ef04ea0d..0a9ec81f 100644 --- a/ext/mixed/js/hotkey-handler.js +++ b/ext/mixed/js/hotkey-handler.js @@ -33,6 +33,8 @@ class HotkeyHandler extends EventDispatcher { this._hotkeys = new Map(); this._actions = new Map(); this._eventListeners = new EventListenerCollection(); + this._isPrepared = false; + this._hasEventListeners = false; } /** @@ -53,14 +55,16 @@ class HotkeyHandler extends EventDispatcher { * Begins listening to key press events in order to detect hotkeys. */ prepare() { - this._eventListeners.addEventListener(document, 'keydown', this._onKeyDown.bind(this), false); + this._isPrepared = true; + this._updateEventHandlers(); } /** * Stops listening to key press events. */ cleanup() { - this._eventListeners.removeAllEventListeners(); + this._isPrepared = false; + this._updateEventHandlers(); } /** @@ -93,6 +97,7 @@ class HotkeyHandler extends EventDispatcher { this._registerHotkey(key, modifiers, action); } } + this._updateEventHandlers(); } /** @@ -102,6 +107,31 @@ class HotkeyHandler extends EventDispatcher { this._hotkeys.clear(); } + /** + * Adds a single event listener to a specific event. + * @param eventName The string representing the event's name. + * @param callback The event listener callback to add. + */ + on(eventName, callback) { + const result = super.on(eventName, callback); + this._updateHasEventListeners(); + this._updateEventHandlers(); + return result; + } + + /** + * Removes a single event listener from a specific event. + * @param eventName The string representing the event's name. + * @param callback The event listener callback to add. + * @returns `true` if the callback was removed, `false` otherwise. + */ + off(eventName, callback) { + const result = super.off(eventName, callback); + this._updateHasEventListeners(); + this._updateEventHandlers(); + return result; + } + // Private _onKeyDown(e) { @@ -144,4 +174,17 @@ class HotkeyHandler extends EventDispatcher { } return true; } + + _updateHasEventListeners() { + this._hasEventListeners = this.hasListeners('keydownNonHotkey'); + } + + _updateEventHandlers() { + if (this._isPrepared && (this._hotkeys.size > 0 || this._hasEventListeners)) { + if (this._eventListeners.size !== 0) { return; } + this._eventListeners.addEventListener(document, 'keydown', this._onKeyDown.bind(this), false); + } else { + this._eventListeners.removeAllEventListeners(); + } + } }