@launchmenu/core
Version:
An environment for visual keyboard controlled applets
338 lines • 28.1 kB
JavaScript
"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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