I packaged a webapp (a softphone) into an electron app to benefit from few automatisms I can code into the app with electron.
I'm using electrons globalShortcut to register a global shortcut to bring the app into the front and focus on the search bar of the web app.
However, because my colleagues started to use the app as well, I want to make the used global shortcut configurable.
As I do not have the possibility to alter the web app itself (it's hosted by a third party), I'm clueless on how to create a menu where a user may setup the shortcut.
I know there is the menu and menuItem objects but I don't know how to ask the user for a key or key bination to set up as globalShortcut using that.
How do I do that?
Edit:
To clarify what I expect: As I already explained, I'm looking for any solution that would make it possible to offer a menu where you can configure a shortcut. That menu may live in the menubar/toolbar or may be put inside the web document through javascript DOM manipulation - maybe using an iframe as last resort?
Any Idea on how to save the setting over restarts of the app are also appreciated.
I packaged a webapp (a softphone) into an electron app to benefit from few automatisms I can code into the app with electron.
I'm using electrons globalShortcut to register a global shortcut to bring the app into the front and focus on the search bar of the web app.
However, because my colleagues started to use the app as well, I want to make the used global shortcut configurable.
As I do not have the possibility to alter the web app itself (it's hosted by a third party), I'm clueless on how to create a menu where a user may setup the shortcut.
I know there is the menu and menuItem objects but I don't know how to ask the user for a key or key bination to set up as globalShortcut using that.
How do I do that?
Edit:
To clarify what I expect: As I already explained, I'm looking for any solution that would make it possible to offer a menu where you can configure a shortcut. That menu may live in the menubar/toolbar or may be put inside the web document through javascript DOM manipulation - maybe using an iframe as last resort?
Any Idea on how to save the setting over restarts of the app are also appreciated.
2 Answers
Reset to default 4 +200After seeing this question I did a small research on your topic. First thing came to mind is does electron give access to listen to key events, but according to this thread electron devs are stopping electron being a keylogger. So I have following method for this issue. I don't know whether these are the best ones for this scenario, but this is the way how I see it can be done. This is basically build around electron-store where it can be used to persist user's defined key bination. So app can retrieve the defined key bination from the store (if there is no binations configured it uses default key bination provided on the schema) and register an globalshortcut
using it. I have provided steps how to implement it
- Install and configure a default key value using electron-store. Like follows
main.js
const Store = require('electron-store');
const schema = {
defaultKeyCombination: {
type: 'string',
default: 'CommandOrControl+Y'
}
}
const store = new Store({schema});
- Importing this
defaultKeyCombination
you can register a global-shortcut when the app is ready. (dont forget to remove the globalshortcut when the app is destroyed)
app.on('ready', () => {
// Register a defaultKeyCombination shortcut listener.
globalShortcut.register(store.get('defaultKeyCombination'), () => {
// Do stuff when Y and either Command/Control is pressed.
})
})
Create and open a another browserWindow from a menu-click (menubar> options> configure) and let users to create/enter an accelerator modifiers in to input box using the available modifiers and key codes (its better to show these on the new window below the input box); For example: User can can enter a MODIFIER+KEY_CODE like
CmdOrCtrl
+
A
in to input on the browswer.Once the user press
submit
button send the entered key bination using IPCRenderer to the main process and set the storedefaultKeyCombination
value by the received value.Trigger the IPC to send reply saying to the user "Please Restart the app" and display it on alert or anything.
renderer process
let args = "CmdOrCtrl+A"
ipcRenderer.send('set::keybine',args)
ipcRenderer.on('done::keybine', (event, arg) => {
// display message to restart the app
})
main process
ipcMain.on('set::keybine', (event, arg) => {
console.log(arg) // prints "keybine"
//setting the new value
store.set('defaultKeyCombination', arg)
// sending reply to renderer work is done
event.reply('done::keybine')
})
Once the app is restarted store will load out the new configured key bination and register an shortcut event using it.
This is what I got in to mind while doing this small research. Here I found a key event listener called iohook ,but this only available for electron 2.XX . In the above process there can be bugs and flow issues, I just posted with some code to get an idea.
Edit 1:
This is my samples. On my index.html I defined an button to call set() function. You can integrate inputbox so you can enter the mands. Once the key is set with the store, it always loading with this new key-value unless user changes it. You can read more about electron-store from here Hope this will give you an idea :)
Main.js
const {app, BrowserWindow, ipcMain } = require('electron')
const Store = require('electron-store');
const schema = {
defaultKeyCombination: {
type: 'string',
default: 'CommandOrControl+Y'
}
}
const store = new Store({schema});
console.log(store.get("defaultKeyCombination"))
function createWindow () {
const window = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
window.loadFile('./index.html')
// window.loadURL("https://www.zap.co.il")
window.webContents.openDevTools()
}
ipcMain.on('set::keybine', (event, arg) => {
console.log(arg) // prints "keybine"
//setting the new value
store.set('defaultKeyCombination', arg)
// sending reply to renderer work is done with new key
event.reply('done::keybine', store.get('defaultKeyCombination'))
})
app.wheReady().then(createWindow)
//app.on('ready', createWindow)
app.on('window-all-closed', () => {
// On macOS it is mon for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
Renderer.js
const { ipcRenderer } = require('electron')
function set() {
console.log("clicked")
let args = "CmdOrCtrl+A"
ipcRenderer.send('set::keybine',args)
}
ipcRenderer.on('done::keybine', (event, arg) => {
console.log("DONEEEEEEEEEE", arg)
})
Let's say hotkeySettings.html
<!DOCTYPE html>
<html lang="en">
<head> </head>
<body>
<input id="hotkey" onkeyup="keyUp(event)" />
<button id="save" onclick="saveHotkey()">save</button>
<script>
const storage = require("electron-json-storage");
async function loadHotkey() {
storage.get("hotkey", function (error, key) {
document.getElementById("hotkey").value = key;
});
}
async function saveHotkey() {
const { globalShortcut } = require("electron").remote;
const hotkey = document.getElementById("hotkey").value;
await storage.set("hotkey", hotkey);
globalShortcut.register(hotkey, () => {
console.log(hotkey, "key pressed");
});
}
function keyUp(event) {
const keyCode = event.keyCode;
const key = event.key;
const charCode = event.code;
if ((keyCode >= 16 && keyCode <= 18) || keyCode === 91) return;
const value = [];
event.ctrlKey ? value.push("Control") : null;
event.shiftKey ? value.push("Shift") : null;
event.isAlt ? value.push("Alt") : null;
value.push(key.toUpperCase());
document.getElementById("hotkey").value = value.join("+");
}
loadHotkey();
</script>
</body>
</html>
loadHotkey
function: will load the prev registered hotkey. hotkey is in appData
.
saveHotKey
function: will register new Hotkey based on your input and save this value to appData
so this will be persist.
At main.js
...
// Open this browserWindow when you click menuItem to see the registered hotkey
// And to update the hotkey
const hotkeySettingsWindow = new BrowserWindow({
height: 600,
width: 600,
webPreferences: {
nodeIntegration: true
}
})
hotkeySettingsWindow.loadFile('hotkeySettings.html')