Skip to content

Commit

Permalink
feat: Add global shortcuts to trigger action (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
skarab42 authored Feb 19, 2021
1 parent 16a1fa0 commit 7346786
Show file tree
Hide file tree
Showing 17 changed files with 309 additions and 26 deletions.
42 changes: 35 additions & 7 deletions app/main/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
"use strict";

const { app } = require("electron");
const { app, globalShortcut } = require("electron");
const server = require("./server");

let mainWindow;

async function onServerReady() {
function registerGlobalShortcut(accelerator, id = null) {
const result = globalShortcut.register(accelerator, () => {
server.send({ type: "shortcut", accelerator });
});
server.send({ type: "registerGlobalShortcut", data: { id, result } });
return result;
}

function registerGlobalShortcuts(shortcuts) {
shortcuts.forEach(registerGlobalShortcut);
}

function onRegisterShortcut({ accelerator, id }) {
return registerGlobalShortcut(accelerator, id);
}

function onUnregisterShortcut({ shortcuts }) {
globalShortcut.unregisterAll();
registerGlobalShortcuts(shortcuts);
}

async function onServerReady(serverState) {
const tray = require("./tray");
mainWindow = require("./window/mainWindow");
const settings = require("../server/libs/settings");
mainWindow({ showOnLoad: await settings.get("app.openOnStartup") });
registerGlobalShortcuts(serverState.shortcuts);
tray();
}

Expand All @@ -19,14 +41,20 @@ function init() {
});

app.whenReady().then(() => {
server.start(onServerReady);
server.start({ onServerReady, onRegisterShortcut, onUnregisterShortcut });
});
}

function onQuit() {
globalShortcut.unregisterAll();
server.stop();
}

app.requestSingleInstanceLock() ? init() : app.quit();

app.on("second-instance", () => mainWindow());
app.on("quit", onQuit);

app.on("quit", () => server.stop());
process.on("SIGINT", () => server.stop());
process.on("SIGTERM", () => server.stop());
process.on("SIGKILL", () => server.stop());
process.on("SIGINT", onQuit);
process.on("SIGTERM", onQuit);
process.on("SIGKILL", onQuit);
23 changes: 18 additions & 5 deletions app/main/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const rootPath = path.resolve(__dirname, "../..");
const serverPath = path.join(__dirname, "../server");
const serverBin = path.join(serverPath, "index.js");

let events = {};
let server = null;

function bufferToString(buffer) {
Expand All @@ -25,9 +26,11 @@ function stderr(buffer) {
console.error(colors.redBright("[server]"), bufferToString(buffer));
}

function start(onStared = null) {
function start(settings = {}) {
if (server) return server;

events = { ...events, ...settings };

const argv = process.argv.slice(2);
server = fork(serverBin, argv, { stdio: ["pipe", "pipe", "pipe", "ipc"] });

Expand All @@ -39,10 +42,19 @@ function start(onStared = null) {
code === 42 && quit();
});

onStared &&
server.on("message", (message) => {
if (message === "started") onStared();
});
server.on("message", (event) => {
if (event.type === "registerShortcut") {
events.onRegisterShortcut(event.data);
} else if (event.type === "unregisterShortcut") {
events.onUnregisterShortcut(event.data);
} else if (event.type === "start") {
events.onServerReady(event.data);
}
});
}

function send(message) {
server && server.send(message);
}

function restart() {
Expand Down Expand Up @@ -75,5 +87,6 @@ if (watch) {
module.exports = {
start,
stop,
send,
restart,
};
9 changes: 9 additions & 0 deletions app/server/api/panels.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,13 @@ module.exports = {
this.notify(`panels.${payload.event}`, payload.panel);
return payload;
},
getShortcuts() {
return panels.getShortcuts();
},
registerShortcut(accelerator) {
return panels.registerShortcut(accelerator);
},
unregisterShortcut(accelerator) {
return panels.unregisterShortcut(accelerator);
},
};
2 changes: 1 addition & 1 deletion app/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function uriDecode(req, res, next) {

function onStarted() {
if (typeof process.send === "function") {
process.send("started");
require("./onStart");
}
}

Expand Down
1 change: 1 addition & 0 deletions app/server/libs/loggers.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function createLogger({ group, console = false } = {}) {
dirname: logsPath,
maxSize: "42m",
maxFiles: "7d",
level: "debug",
}),
],
});
Expand Down
51 changes: 51 additions & 0 deletions app/server/libs/panels.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ function remove(panel) {
return true;
});
store.set("panels", panels);
unregisterShortcut(null);
return pos;
}

Expand Down Expand Up @@ -310,6 +311,53 @@ function importArchive(panel, archive) {
return { error: "Unsupported file format" };
}

function getShortcuts() {
const shortcuts = [];

panels.forEach(({ widgets }) => {
widgets.forEach((widget) => {
if (widget.shortcutName && !shortcuts.includes(widget.shortcutName)) {
shortcuts.push(widget.shortcutName);
}
});
});

return shortcuts;
}

let registerShortcutId = null;
let registerShortcutResolve = null;

process.on("message", ({ type, data }) => {
if (type === "registerGlobalShortcut" && registerShortcutId === data.id) {
registerShortcutResolve(data);
}
});

function registerShortcut(accelerator) {
registerShortcutId = uuid();
const shortcuts = getShortcuts();
if (shortcuts.includes(accelerator)) {
return { id: registerShortcutId, result: true };
}
return new Promise((resolve) => {
registerShortcutResolve = resolve;
process.send({
type: "registerShortcut",
data: { id: registerShortcutId, accelerator },
});
});
}

function unregisterShortcut(accelerator) {
registerShortcutId = uuid();
process.send({
type: "unregisterShortcut",
data: { id: registerShortcutId, accelerator, shortcuts: getShortcuts() },
});
return { id: registerShortcutId, result: true };
}

module.exports = {
add,
set,
Expand All @@ -321,8 +369,11 @@ module.exports = {
removeWidget,
importArchive,
exportWidget,
getShortcuts,
getWidgetFiles,
duplicateWidget,
moveWidgetToPanel,
removeWidgetComponent,
registerShortcut,
unregisterShortcut,
};
1 change: 1 addition & 0 deletions app/server/libs/twitch/events.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[
{ "name": "onShortcut", "tags": [] },
{ "name": "onAction", "tags": ["user", "message", "date"] },
{ "name": "onBan", "tags": ["user"] },
{ "name": "onBits", "tags": ["user", "message", "amount", "total"] },
Expand Down
16 changes: 14 additions & 2 deletions app/server/libs/twitch/pushActions.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
const stores = require("../../../stores");
const { push } = require("../actions");
const loggers = require("../loggers");

const logger = loggers.get("server");

const types = {
AnimeTimeline: "anime",
SceneList: "obs",
ToggleScene: "obs",
GoToScene: "obs",
ToggleScene: "obs",
AnimeTimeline: "anime",
};

function isInvalidShortcut(widget, eventProps) {
return (
eventProps.accelerator && widget.shortcutName !== eventProps.accelerator
);
}

function isInvalidCommand(widget, eventProps) {
return eventProps.command && widget.commandName !== eventProps.command.name;
}
Expand All @@ -17,6 +26,8 @@ function isInvalidReward(widget, eventProps) {
}

module.exports = function pushActions(eventName, eventProps) {
logger.debug("pushActions", { eventName, eventProps });

stores.panels.get("panels").forEach(({ widgets }) => {
widgets.forEach((widget) => {
if (!widget.component) return;
Expand All @@ -27,6 +38,7 @@ module.exports = function pushActions(eventName, eventProps) {
if (widget.eventName !== eventName) return;
if (isInvalidReward(widget, eventProps)) return;
if (isInvalidCommand(widget, eventProps)) return;
if (isInvalidShortcut(widget, eventProps)) return;

push({ type, widget, eventProps });
});
Expand Down
10 changes: 10 additions & 0 deletions app/server/onStart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const pushActions = require("./libs/twitch/pushActions");
const { getShortcuts } = require("./libs/panels");

process.send({ type: "start", data: { shortcuts: getShortcuts() } });

process.on("message", (event) => {
if (event.type === "shortcut") {
pushActions("onShortcut", event);
}
});
10 changes: 7 additions & 3 deletions app/static/locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
"file-use-count": "File used by {{count}} widget",
"file-use-count_plural": "File used by {{count}} widgets",
"ask-purge": "Delete {{count}} files not in use?",
"ask-remove-asset": "Remove \"{{filename}}\" from the timeline?"
"ask-remove-asset": "Remove \"{{filename}}\" from the timeline?",
"global-shortcut-reserved": "This shortcut is reserved by the system!",
"type-shortcut-here": "Type shortcut here..."
},
"words": {
"settings": "settings",
Expand Down Expand Up @@ -151,7 +153,8 @@
"close": "close",
"confirm": "confirm",
"export": "export",
"import": "import"
"import": "import",
"shortcut": "shortcut"
},
"obs": {
"scene-list": "OBS | Scene list",
Expand Down Expand Up @@ -206,7 +209,8 @@
"onSubGift": "Sub gift",
"onCommand": "Command",
"onRedemption": "Redemption",
"onBits": "Bits"
"onBits": "Bits",
"onShortcut": "Shortcut"
}
},
"labels": {
Expand Down
10 changes: 7 additions & 3 deletions app/static/locales/es/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
"file-use-count": "Archivo utilizado por {{count}} widget",
"file-use-count_plural": "Archivo utilizado por {{count}} widgets",
"ask-purge": "¿Borrar {{count}} archivos no utilizados?",
"ask-remove-asset": "¿Eliminar \"{{filename}}\" de la línea de tiempo?"
"ask-remove-asset": "¿Eliminar \"{{filename}}\" de la línea de tiempo?",
"global-shortcut-reserved": "Este acceso directo está reservado por el sistema!",
"type-shortcut-here": "Escriba el acceso directo aquí..."
},
"words": {
"settings": "opciones",
Expand Down Expand Up @@ -150,7 +152,8 @@
"close": "cerrar",
"confirm": "confirmar",
"export": "exportar",
"import": "importar"
"import": "importar",
"shortcut": "shortcut"
},
"obs": {
"scene-list": "OBS | Lista de escenas",
Expand Down Expand Up @@ -205,7 +208,8 @@
"onSubGift": "Sub gift",
"onCommand": "Comando",
"onRedemption": "Redemption",
"onBits": "Bits"
"onBits": "Bits",
"onShortcut": "Shortcut"
}
},
"labels": {
Expand Down
10 changes: 7 additions & 3 deletions app/static/locales/fr/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
"file-use-count": "Fichier utilisé par {{count}} widget",
"file-use-count_plural": "Fichier utilisé par {{count}} widgets",
"ask-purge": "Supprimer {{count}} fichiers non utiliser ?",
"ask-remove-asset": "Supprimer \"{{filename}}\" de la timeline ?"
"ask-remove-asset": "Supprimer \"{{filename}}\" de la timeline ?",
"global-shortcut-reserved": "Ce raccourci est réservé par le système!",
"type-shortcut-here": "Tapez le raccourci ici..."
},
"words": {
"settings": "options",
Expand Down Expand Up @@ -151,7 +153,8 @@
"close": "fermer",
"confirm": "confirmer",
"export": "exporter",
"import": "importer"
"import": "importer",
"shortcut": "shortcut"
},
"obs": {
"scene-list": "OBS | Liste des scènes",
Expand Down Expand Up @@ -206,7 +209,8 @@
"onSubGift": "Sub gift",
"onCommand": "Command",
"onRedemption": "Redemption",
"onBits": "Bits"
"onBits": "Bits",
"onShortcut": "Shortcut"
}
},
"labels": {
Expand Down
5 changes: 5 additions & 0 deletions front-src/client/api/panels.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ export default {
exportWidget: (panel, widget) => emit("panels.exportWidget", panel, widget),
exportPanel: (panel) => emit("panels.exportPanel", panel),
importArchive: (panel, widget) => emit("panels.importArchive", panel, widget),
getShortcuts: () => emit("panels.getShortcuts"),
registerShortcut: (accelerator) =>
emit("panels.registerShortcut", accelerator),
unregisterShortcut: (accelerator) =>
emit("panels.unregisterShortcut", accelerator),
};
Loading

0 comments on commit 7346786

Please sign in to comment.