UNPKG

@launchmenu/core

Version:

An environment for visual keyboard controlled applets

338 lines 28.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GlobalKeyHandler = void 0; const electron_1 = require("electron"); const electronAcceleratorKeyMapping_1 = require("./electronAcceleratorKeyMapping"); const primaryGlobalShortcutKeys_1 = require("./primaryGlobalShortcutKeys"); const node_global_key_listener_1 = require("node-global-key-listener"); const nodeGlobalKeyListenerMapping_1 = require("./nodeGlobalKeyListenerMapping"); const keys_1 = require("../keyIdentifiers/keys"); const model_react_1 = require("model-react"); /** A class that can be used for registering keyboard shortcuts. Should be used as a singleton obtained from LaunchMenu */ class GlobalKeyHandler { /** * Creates a new instance of the global key handler * @param useElectronListener A data retriever to determine whether to force use electron's listener */ constructor(useElectronListener = () => true) { this.keyListeners = []; this.electronListeners = {}; this.currentUseElectronListener = false; this.shortcutListeners = []; console.log("Shit"); try { this.advancedManager = new node_global_key_listener_1.GlobalKeyboardListener(); } catch (e) { console.error(e); } this.useElectronListener = useElectronListener; this.useElectronListenerObserver = this.setupShortcutMethodObserver(); } /** * Adds a global key listeners that listens to all events * @param callback The key press callback * @returns A function that can be invoked to remove the listener */ addListener(callback) { var _a; if (!this.advancedManager) throw new Error("Global key listeners are not supported on this platform"); this.keyListeners.push(callback); // If this is the first listener, add it to key hook if (this.keyListeners.length == 1) { this.invokeListeners = (event, held) => { if (this.currentUseElectronListener) return; const ev = this.convertKeyEvent(event, held); if (!ev) return; let stopPropagation = false; let stopImmediatePropagation = false; for (let listener of this.keyListeners) { const res = listener(ev); if (typeof res == "object") { if (res.stopPropagation) stopPropagation = true; if (res.stopImmediatePropagation) { stopImmediatePropagation = true; break; } } else if (res) stopPropagation = true; } return { stopImmediatePropagation, stopPropagation, }; }; (_a = this.advancedManager) === null || _a === void 0 ? void 0 : _a.addListener(this.invokeListeners); } // Return a function to remove the listener return () => { var _a; const index = this.keyListeners.indexOf(callback); if (index != -1) this.keyListeners.splice(index, 1); // Remove the key hook listener if no listeners remain if (this.keyListeners.length == 0) { (_a = this.advancedManager) === null || _a === void 0 ? void 0 : _a.removeListener(this.invokeListeners); } }; } /** * Converts a global key event to the format as used by LM * @param event The event to convert * @param held The keys that are currently held * @returns The LM event */ convertKeyEvent(event, held) { const key = nodeGlobalKeyListenerMapping_1.nodeGlobalKeyListenerMapping[event.name]; if (!key) return undefined; return { key, rawcode: event.name, type: event.state == "UP" ? "keyup" : "keydown", altKey: held["LEFT ALT"] ? "left" : held["RIGHT ALT"] ? "right" : undefined, ctrlKey: held["LEFT CTRL"] ? "left" : held["RIGHT CTRL"] ? "right" : undefined, metaKey: held["LEFT META"] ? "left" : held["RIGHT META"] ? "right" : undefined, shiftKey: held["LEFT SHIFT"] ? "left" : held["RIGHT SHIFT"] ? "right" : undefined, }; } /** * Checks whether global key listeners are supported on the current OS/environment * @param hook The hook to subscribe to changes * @returns Whether listeners are supported */ areListenersSupported(hook) { return !this.useElectronListener(hook) && !!this.advancedManager; } /** * Sets up an observer that takes care of moving the shortcut listeners if the setting changed */ setupShortcutMethodObserver() { console.log("Detect"); return new model_react_1.Observer(h => !this.areListenersSupported(h)).listen(useElectron => { console.log(useElectron); if (this.currentUseElectronListener != useElectron) { this.currentUseElectronListener = useElectron; // Dispose all the old listeners const allListeners = this.shortcutListeners; this.shortcutListeners = []; allListeners.forEach(({ dispose }) => dispose()); // Reregister all listeners allListeners.forEach(bundle => { const newDispose = this.addShortcut(bundle.shortcut, bundle.callback); // Make sure that the original dispose method can still be used (since this was returned from the original addShortcut callback) bundle.dispose = newDispose; }); } }, true); } /** * Adds a global shortcut * @param shortcut The keypattern to listen for * @param callback The callback to trigger when the event is fired * @returns A function that can be invoked to remove the shortcut */ addShortcut(shortcut, callback) { const invalid = this.isShortcutInvalid(shortcut); if (invalid) throw invalid[0].error; // Use one of the two shortcut methods let dispose; if (!this.advancedManager) dispose = this.addElectronShortcut(shortcut, callback); else dispose = this.addCustomShortcut(shortcut, callback); // Setup a callback to dispose all data associated to a shortcut const fullDispose = () => { const index = this.shortcutListeners.findIndex(({ dispose: d }) => d == dispose); if (index != -1) this.shortcutListeners.splice(index, 1); dispose(); }; const bundle = { shortcut, callback, dispose: fullDispose }; this.shortcutListeners.push(bundle); // Note that bundle's fullDispose method can be changed throughout its lifetime, the bundle object mutates (to support dynamic `useElectronListener`) return () => bundle.dispose(); } /** * Checks whether the given keypattern is valid as a global shortcut or not * @param shortcut The key pattern to check * @returns False if the pattern is valid, or the patterns and errors if invalid */ isShortcutInvalid(shortcut) { const invalid = this.getElectronAccelerators(shortcut) .map((res, index) => ({ pattern: shortcut.patterns[index], error: res })) .filter((res) => typeof res.error != "string"); return invalid.length > 0 ? invalid : false; } /** * Adds a global shortcut using the node-global-key-listener package * @param shortcut The key pattern to listen for * @param callback The callback to trigger when the event is fired * @returns A function that can be invoked to remove the shortcut */ addCustomShortcut(shortcut, callback) { // Create a format that's faster to compare with const keys = {}; shortcut.patterns.forEach(({ pattern }, i) => { const primaryKey = pattern.find(key => ![ "altLeft", "altRight", "controlLeft", "controlRight", "shiftLeft", "shiftRight", "metaLeft", "metaRight", "alt", "ctrl", "shift", "meta", ].includes(key)); function getState(pattern, left, right, either) { const includesLeft = pattern.includes(left); const includesRight = pattern.includes(right); const includesEither = pattern.includes(either); return [ ...(includesLeft || includesEither ? ["left"] : []), ...(includesRight || includesEither ? ["right"] : []), ...(!includesLeft && !includesRight && !includesEither ? [undefined] : []), ]; } if (primaryKey) { Object.entries(keys_1.keyIdMapping) .filter(([id, name]) => id == primaryKey || name == primaryKey) .forEach(([id]) => { var _a; if (!keys[id]) keys[id] = []; (_a = keys[id]) === null || _a === void 0 ? void 0 : _a.push({ altKey: getState(pattern, "altLeft", "altRight", "alt"), ctrlKey: getState(pattern, "controlLeft", "controlRight", "ctrl"), shiftKey: getState(pattern, "shiftLeft", "shiftRight", "shift"), metaKey: getState(pattern, "metaLeft", "metaRight", "meta"), }); }); } }); // Create the listener const listener = event => { if (event.type == "keyup") return; const modifiers = keys[event.key]; if (modifiers != undefined) { const matches = modifiers.some(modifiers => modifiers.altKey.includes(event.altKey) && modifiers.ctrlKey.includes(event.ctrlKey) && modifiers.shiftKey.includes(event.shiftKey) && modifiers.metaKey.includes(event.metaKey)); if (matches) { callback(); return true; } } }; return this.addListener(listener); } /** * Adds a global shortcut using electron's shortcut system * @param shortcut The key pattern to listen for * @param callback The callback to trigger when the event is fired * @returns A function that can be invoked to remove the shortcut */ addElectronShortcut(shortcut, callback) { const accelerators = this.getElectronAccelerators(shortcut).filter((n) => typeof n == "string"); // Register each accelerator accelerators.forEach(accelerator => { if (!this.electronListeners[accelerator]) { const listeners = []; this.electronListeners[accelerator] = listeners; const invoker = () => listeners.forEach(listener => listener()); electron_1.remote.globalShortcut.register(accelerator, invoker); } this.electronListeners[accelerator].push(callback); }); // Return a function to remove the listeners return () => { accelerators.forEach(accelerator => { const listeners = this.electronListeners[accelerator]; if (!listeners) return; const index = listeners.indexOf(callback); if (index != -1) { listeners.splice(index, 1); if (listeners.length == 0) { electron_1.remote.globalShortcut.unregister(accelerator); delete this.electronListeners[accelerator]; } } }); }; } /** * Retrieves the electron accelerator string if valid, or an error object otherwise * @param shortcut The key pattern shortcut * @returns The accelerator string or error object */ getElectronAccelerators(shortcut) { return shortcut.patterns.map(({ allowExtra, pattern, type }) => { var _a; // Check the extra pattern event data if ((_a = allowExtra === null || allowExtra === void 0 ? void 0 : allowExtra.length) !== null && _a !== void 0 ? _a : 0 > 0) return new Error("Global shortcuts can't have extra keys"); if (type != "down") return new Error("Global shortcuts can only listen for key up events"); // Check the pattern itself const { error } = pattern.reduce(({ error, charCount }, key) => { if (error) return { error, charCount }; if (primaryGlobalShortcutKeys_1.primaryGlobalShortcutKeys.includes(key)) { charCount += 1; if (charCount > 1) error = new Error("Global shortcuts can only contain 1 primary key"); } return { error, charCount }; }, { error: null, charCount: 0 }); if (error) return error; // Obtain the shortcut return pattern .map(key => { var _a; return (_a = electronAcceleratorKeyMapping_1.electronAcceleratorKeyMapping[key]) !== null && _a !== void 0 ? _a : key; }) .join("+"); }); } /** * Disposes all listeners */ destroy() { this.useElectronListenerObserver.destroy(); if (this.advancedManager && this.invokeListeners) { this.advancedManager.removeListener(this.invokeListeners); this.keyListeners = []; this.advancedManager.kill(); } for (let shortcut in this.electronListeners) electron_1.remote.globalShortcut.unregister(shortcut); this.electronListeners = {}; } } exports.GlobalKeyHandler = GlobalKeyHandler; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU0dsb2JhbEtleUhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMva2V5SGFuZGxlci9nbG9iYWxLZXlIYW5kbGVyL1NHbG9iYWxLZXlIYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHVDQUFnQztBQUdoQyxtRkFBOEU7QUFDOUUsMkVBQXNFO0FBQ3RFLHVFQUtrQztBQUVsQyxpRkFBNEU7QUFHNUUsaURBQWlFO0FBRWpFLDZDQUFnRTtBQUVoRSwwSEFBMEg7QUFDMUgsTUFBYSxnQkFBZ0I7SUFpQnpCOzs7T0FHRztJQUNILFlBQW1CLHNCQUErQyxHQUFHLEVBQUUsQ0FBQyxJQUFJO1FBakJsRSxpQkFBWSxHQUF5QixFQUFFLENBQUM7UUFDeEMsc0JBQWlCLEdBQW1DLEVBQUUsQ0FBQztRQUt2RCwrQkFBMEIsR0FBWSxLQUFLLENBQUM7UUFDNUMsc0JBQWlCLEdBSXJCLEVBQUUsQ0FBQztRQU9MLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDcEIsSUFBSTtZQUNBLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxpREFBc0IsRUFBRSxDQUFDO1NBQ3ZEO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDUixPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ3BCO1FBQ0QsSUFBSSxDQUFDLG1CQUFtQixHQUFHLG1CQUFtQixDQUFDO1FBQy9DLElBQUksQ0FBQywyQkFBMkIsR0FBRyxJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztJQUMxRSxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLFdBQVcsQ0FBQyxRQUE0Qjs7UUFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlO1lBQ3JCLE1BQU0sSUFBSSxLQUFLLENBQUMseURBQXlELENBQUMsQ0FBQztRQUUvRSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUVqQyxvREFBb0Q7UUFD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