diff --git a/electron_app/package.json b/electron_app/package.json index aefe8dde39f..f9076db096f 100644 --- a/electron_app/package.json +++ b/electron_app/package.json @@ -8,7 +8,27 @@ "dependencies": { "auto-launch": "^5.0.1", "electron-window-state": "^4.1.0", + "iohook": "^0.2.4", "minimist": "^1.2.0", "png-to-ico": "^1.0.2" + }, + "iohook": { + "targets": [ + "node-64", + "electron-64" + ], + "platforms": [ + "win32", + "darwin", + "linux" + ], + "arches": [ + "x64", + "ia32" + ] + }, + "cmake-js": { + "runtime": "electron", + "runtimeVersion": "3.0.5" } } diff --git a/electron_app/src/electron-main.js b/electron_app/src/electron-main.js index 85955392aaa..02fe98b4aa5 100644 --- a/electron_app/src/electron-main.js +++ b/electron_app/src/electron-main.js @@ -25,6 +25,7 @@ if (checkSquirrelHooks()) return; const argv = require('minimist')(process.argv); const {app, ipcMain, powerSaveBlocker, BrowserWindow, Menu} = require('electron'); const AutoLaunch = require('auto-launch'); +const ioHook = require('iohook'); const tray = require('./tray'); const vectorMenu = require('./vectormenu'); @@ -238,6 +239,13 @@ app.on('ready', () => { return false; } }); + mainWindow.on('blur', () => { + // Stop recording keypresses if Riot loses focus + // Used for Push-To-Talk, keypress recording only triggered when setting + // a global shortcut in Settings + mainWindow.webContents.send('window-blurred'); + stopListeningKeys(); + }); if (process.platform === 'win32') { // Handle forward/backward mouse buttons in Windows @@ -268,6 +276,92 @@ app.on('before-quit', () => { } }); +// Counter for keybindings we have registered +let ioHookTasks = 0; + +// Limit for amount of keybindings that can be +// registered at once. +const keybindingRegistrationLimit = 1; + +// Fires when a global keybinding is being registered +ipcMain.on('register-keybinding', function(ev, keybinding) { + // Prevent registering more than the defined limit + if (ioHookTasks >= keybindingRegistrationLimit) { + ioHookTasks = keybindingRegistrationLimit; + return; + } + + // Start listening for global keyboard shortcuts + if (ioHookTasks <= 0) { + ioHookTasks = 0; + ioHook.start(); + } + ioHookTasks++; + + ioHook.registerShortcut(keybinding.code, () => { + ev.sender.send('keybinding-pressed', keybinding.name); + }, () => { + ev.sender.send('keybinding-released', keybinding.name); + }); +}); + +// Fires when a global keybinding is being unregistered +ipcMain.on('unregister-keybinding', function(ev, keybindingCode) { + // Stop listening for global keyboard shortcuts if we're + // unregistering the last one + if (ioHookTasks <= 1) { + ioHook.stop(); + } + ioHookTasks--; + + ioHook.unregisterShortcutByKeys(keybindingCode); +}); + +// Tell renderer process what key was pressed +// iohook has its own encoding for keys, so we can't just use a +// listener in the renderer process to register iohook shortcuts +let renderProcessID = null; +const reportKeyEvent = function(keyEvent) { + // "this" is the renderer process because we call this method with .bind() + renderProcessID.sender.send('keypress', { + keydown: keyEvent.type == 'keydown', + keycode: keyEvent.keycode, + }); +}; + +// Fires when listening on all keys +// !!Security note: Ensure iohook is only allowed to listen to keybindings +// when the browser window is in focus, else an XSS could lead to keylogging +// Currently, this is achieved by leveraging browserWindow to act on focus loss +ipcMain.on('start-listening-keys', function(ev, keybindingCode) { + // Start recording keypresses + if (ioHookTasks <= 0) { + ioHookTasks = 0; + ioHook.start(); + } + ioHookTasks++; + + renderProcessID = ev; + ioHook.on('keydown', reportKeyEvent); + ioHook.on('keyup', reportKeyEvent); +}); + +const stopListeningKeys = () => { + // Stop recording keypresses + ioHook.off('keydown', reportKeyEvent); + ioHook.off('keyup', reportKeyEvent); +}; + +ipcMain.on('stop-listening-keys', () => { + if (ioHookTasks <= 1) { + ioHookTasks = 1; + ioHook.stop(); + } + ioHookTasks--; + + stopListeningKeys(); +}); + // Set the App User Model ID to match what the squirrel // installer uses for the shortcut icon. // This makes notifications work on windows 8.1 (and is diff --git a/package-lock.json b/package-lock.json index d21cf33fb43..738238d30f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "riot-web", - "version": "0.17.3", + "version": "0.17.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1237,7 +1237,7 @@ }, "babel-plugin-add-module-exports": { "version": "0.2.1", - "resolved": "http://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz", "integrity": "sha1-mumh9KjcZ/DN7E9K7aHkOl/2XiU=", "dev": true }, @@ -1252,55 +1252,55 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", "dev": true }, "babel-plugin-syntax-async-generators": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", "dev": true }, "babel-plugin-syntax-class-properties": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", "dev": true }, "babel-plugin-syntax-decorators": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", "dev": true }, "babel-plugin-syntax-dynamic-import": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", "dev": true }, "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", "dev": true }, "babel-plugin-syntax-flow": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", "dev": true }, "babel-plugin-syntax-jsx": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", "dev": true }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "dev": true }, @@ -2060,7 +2060,7 @@ }, "blob": { "version": "0.0.4", - "resolved": "http://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", "dev": true }, @@ -3886,7 +3886,7 @@ }, "css-select": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { @@ -4227,7 +4227,7 @@ "dependencies": { "domelementtype": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" } } @@ -4240,7 +4240,7 @@ }, "domelementtype": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" }, "domhandler": { @@ -4293,7 +4293,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, @@ -4830,7 +4830,7 @@ }, "emojione": { "version": "2.2.7", - "resolved": "http://registry.npmjs.org/emojione/-/emojione-2.2.7.tgz", + "resolved": "https://registry.npmjs.org/emojione/-/emojione-2.2.7.tgz", "integrity": "sha1-RkV89rmy+NoTroouTlR94G7hXpY=" }, "emojis-list": { @@ -5118,7 +5118,7 @@ }, "eslint-config-google": { "version": "0.7.1", - "resolved": "http://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.7.1.tgz", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.7.1.tgz", "integrity": "sha1-VZj4SY6eB4Qg80uASVuNlZ9lH7I=", "dev": true }, @@ -5248,7 +5248,7 @@ }, "events": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", "dev": true }, @@ -5358,7 +5358,7 @@ }, "expect": { "version": "1.20.2", - "resolved": "http://registry.npmjs.org/expect/-/expect-1.20.2.tgz", + "resolved": "https://registry.npmjs.org/expect/-/expect-1.20.2.tgz", "integrity": "sha1-1Fj+TFYAQDa64yMkFqP2Nh8E+WU=", "dev": true, "requires": { @@ -5520,11 +5520,6 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, - "fast-extend": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fast-extend/-/fast-extend-0.0.2.tgz", - "integrity": "sha1-9exCz0C5Rg9SGmOH37Ut7u1nHb0=" - }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -5763,7 +5758,7 @@ "dependencies": { "core-js": { "version": "1.2.7", - "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" }, "fbjs": { @@ -5965,11 +5960,6 @@ } } }, - "fs-monkey": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-0.3.3.tgz", - "integrity": "sha512-FNUvuTAJ3CqCQb5ELn+qCbGR/Zllhf2HtwsdAtBi59s1WeCjKMT81fHcSu7dwIskqGVK+MmOrb7VOBlq3/SItw==" - }, "fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -6052,12 +6042,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6072,17 +6064,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -6199,7 +6194,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -6211,6 +6207,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6225,6 +6222,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6232,12 +6230,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -6256,6 +6256,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -6336,7 +6337,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -6348,6 +6350,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -6469,6 +6472,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6573,7 +6577,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -7428,7 +7432,7 @@ }, "immutable": { "version": "3.7.6", - "resolved": "http://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" }, "import-cwd": { @@ -7717,7 +7721,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { "builtin-modules": "^1.0.0" @@ -7899,7 +7903,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -8166,7 +8170,7 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { @@ -8286,13 +8290,13 @@ "dependencies": { "lodash": { "version": "3.10.1", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true }, "xmlbuilder": { "version": "3.1.0", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-3.1.0.tgz", "integrity": "sha1-LIaIjy1OrehQ+jjKf3Ij9yCVFuE=", "dev": true, "requires": { @@ -8486,7 +8490,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -8707,7 +8711,6 @@ "browser-request": "^0.3.3", "content-type": "^1.0.2", "loglevel": "1.6.1", - "memfs": "^2.10.1", "qs": "^6.5.2", "request": "^2.88.0" } @@ -8747,7 +8750,6 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "memfs": "^2.10.1", "optimist": "^0.6.1", "pako": "^1.0.5", "prop-types": "^15.5.8", @@ -8844,7 +8846,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, @@ -8859,15 +8861,6 @@ "p-is-promise": "^1.1.0" } }, - "memfs": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-2.10.1.tgz", - "integrity": "sha512-CXfNuf6TeF4ByYJ/cAxVcR2y58Q511soYd6JhXAJVPYp+9kIbkJZ+FZUw8fQCcNn5+XUNJ38CdjX0gpeUt5ITA==", - "requires": { - "fast-extend": "0.0.2", - "fs-monkey": "^0.3.3" - } - }, "memoize-one": { "version": "3.1.1", "resolved": "http://registry.npmjs.org/memoize-one/-/memoize-one-3.1.1.tgz", @@ -8990,7 +8983,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mississippi": { @@ -9034,7 +9027,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -9042,7 +9035,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } @@ -9574,7 +9567,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" } } @@ -9624,7 +9617,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { "lcid": "^1.0.0" @@ -9908,7 +9901,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { @@ -10097,7 +10090,7 @@ }, "postcss-import": { "version": "11.1.0", - "resolved": "http://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", "dev": true, "requires": { @@ -11498,7 +11491,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -12540,7 +12533,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -12747,7 +12740,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -13048,7 +13041,7 @@ }, "underscore.string": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=" }, "union-value": { @@ -14332,7 +14325,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9641f0dd71c..e123db2bbd2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -35,5 +35,6 @@ "Contributing code to Matrix and Riot": "Contributing code to Matrix and Riot", "Dev chat for the Riot/Web dev team": "Dev chat for the Riot/Web dev team", "Dev chat for the Dendrite dev team": "Dev chat for the Dendrite dev team", - "Co-ordination for Riot translators": "Co-ordination for Riot translators" + "Co-ordination for Riot translators": "Co-ordination for Riot translators", + "Push-to-Talk": "Push-to-Talk" } diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index 5ced2a2ad06..1f261c25157 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -26,6 +26,8 @@ import rageshake from 'matrix-react-sdk/lib/rageshake/rageshake'; remote.autoUpdater.on('update-downloaded', onUpdateDownloaded); +var globalKeybindings = {}; + // try to flush the rageshake logs to indexeddb before quit. ipcRenderer.on('before-quit', function () { console.log('riot-desktop closing'); @@ -105,6 +107,25 @@ export default class ElectronPlatform extends VectorBasePlatform { this.startUpdateCheck = this.startUpdateCheck.bind(this); this.stopUpdateCheck = this.stopUpdateCheck.bind(this); + + ipcRenderer.on('keybinding-pressed', (event, keybindName) => { + // Prevent holding down a shortcut meaning multiple presses + if (globalKeybindings[keybindName].pressed) { + return; + } + globalKeybindings[keybindName].pressed = true; + + // Run the callback + globalKeybindings[keybindName].callback(); + }); + + ipcRenderer.on('keybinding-released', (event, keybindName) => { + // Keybinding is no longer pressed + globalKeybindings[keybindName].pressed = false; + + // Run the callback + globalKeybindings[keybindName].releaseCallback(); + }); } getHumanReadableName(): string { @@ -182,6 +203,26 @@ export default class ElectronPlatform extends VectorBasePlatform { ipcRenderer.send('check_updates'); } + addGlobalKeybinding(keybindName: string, keybindCode: string, callback: () => void, releaseCallback: () => void) { + // Add a keybinding that works even when the app is minimized + const keybinding = {name: keybindName, code: keybindCode}; + + ipcRenderer.send('register-keybinding', keybinding); + globalKeybindings[keybindName] = {callback, releaseCallback}; + + console.warn("Adding global keybinding:", keybindName, "with code:", keybindCode); + } + + removeGlobalKeybinding(keybindName: string, keybindCode: string) { + // Unbind a global keybinding + ipcRenderer.send('unregister-keybinding', keybindCode); + + // Remove the callback + delete globalKeybindings[keybindName]; + + console.warn("Removing global keybinding:", keybindName); + } + installUpdate() { // IPC to the main process to install the update, since quitAndInstall // doesn't fire the before-quit event so the main process needs to know