javascript - Hacer que el atajo global sea configurable en la aplicación electron
Empaqueté una aplicación web (un softphone) en una aplicación Electron para beneficiarme de algunos automatismos que puedo programar en la aplicación con Electron.
Estoy usando globalShortcut de Electron para registrar un acceso directo global que traiga la aplicación al frente y enfoque la barra de búsqueda de la aplicación web.
Sin embargo, debido a que mis colegas también empezaron a usar la aplicación, quiero hacer que el atajo global utilizado sea configurable.
Como no tengo la posibilidad de alterar la propia aplicación web (está alojada por un tercero), no tengo idea de cómo crear un menú donde un usuario pueda configurar el atajo.
Sé que existen los objetos menu y menuItem, pero no sé cómo pedirle al usuario una tecla o combinación de teclas para configurar como globalShortcut usando eso.
¿Cómo hago eso?
Editar:
Para aclarar lo que espero: Como ya expliqué, estoy buscando cualquier solución que haga posible ofrecer un menú donde se pueda configurar un atajo. Ese menú puede estar en la barra de menús/barra de herramientas o puede colocarse dentro del documento web mediante manipulación del DOM de JavaScript, ¿quizás usando un iframe como último recurso?
También se agradecería cualquier idea sobre cómo guardar la configuración tras reinicios de la aplicación.
Respuesta #1
Después de ver esta pregunta hice una pequeña investigación sobre tu tema. Lo primero que vino a mi mente es si Electron permite acceder para escuchar eventos de teclas, pero según este hilo los desarrolladores de Electron están impidiendo que Electron sea un keylogger. Así que tengo el siguiente método para este problema. No sé si estos son los mejores para este escenario, pero esta es la manera en que veo que se puede hacer. Esto se basa básicamente en electron-store, donde se puede usar para persistir la combinación de teclas definida por el usuario. Así, la aplicación puede recuperar la combinación de teclas definida desde el store (si no hay combinaciones configuradas, se usa la combinación de teclas predeterminada proporcionada en el esquema) y registrar un globalshortcut usándola. He proporcionado los pasos sobre cómo implementarlo
- Instala y configura un valor clave por defecto usando electron-store. Como sigue
principal.js
const Store = require('electron-store');
const schema = {
defaultKeyCombination: {
type: 'string',
default: 'CommandOrControl+Y'
}
}
const store = new Store({schema});
- Importando este
defaultKeyCombinationpuedes registrar un atajo global cuando la aplicación esté lista. (no olvides eliminar el globalshortcut cuando la aplicación sea destruida)
app.on('ready', () => {
// Register a defaultKeyCombination shortcut listener.
globalShortcut.register(store.get('defaultKeyCombination'), () => {
// Do stuff when Y and either Command/Control is pressed.
})
})
Cree y abra otra ventana del navegador desde un clic en el menú (barra de menús > opciones > configurar) y permita a los usuarios crear/ingresar un modificador de acelerador en el cuadro de entrada usando los modificadores y códigos de tecla disponibles (es mejor mostrar estos en la nueva ventana debajo del cuadro de entrada); Por ejemplo: El usuario puede ingresar un MODIFICADOR+CÓDIGO_DE_TECLA como
CmdOrCtrl+Aen el cuadro de entrada del navegador.Una vez que el usuario presione el botón
submit, envíe la combinación de teclas ingresada usando IPCRenderer al proceso principal y establezca el valor de la tiendadefaultKeyCombinationcon el valor recibido.Dispara el IPC para enviar una respuesta al usuario diciendo "Por favor, reinicia la aplicación" y muéstralo en una alerta o algo similar.
proceso de renderizado
let args = "CmdOrCtrl+A"
ipcRenderer.send('set::keycombine',args)
ipcRenderer.on('done::keycombine', (event, arg) => {
// display message to restart the app
})
proceso principal
ipcMain.on('set::keycombine', (event, arg) => {
console.log(arg) // prints "keycombine"
//setting the new value
store.set('defaultKeyCombination', arg)
// sending reply to renderer work is done
event.reply('done::keycombine')
})
Una vez que la aplicación se reinicie, la tienda cargará la nueva combinación de teclas configurada y registrará un evento de acceso directo usándola.
Esto es lo que se me ocurrió mientras hacía esta pequeña investigación. Aquí encontré un listener de teclas llamado iohook, pero esto solo está disponible para electron 2.XX. En el proceso anterior puede haber errores y problemas de flujo, solo publiqué con un poco de código para tener una idea.
Edición 1:
Estos son mis ejemplos. En mi index.html definí un botón para llamar a la función set(). Puedes integrar un cuadro de entrada para que puedas ingresar los comandos. Una vez que la clave se establece con el almacén, siempre se carga con este nuevo par clave-valor a menos que el usuario lo cambie. Puedes leer más sobre electron-store aquí. Espero que esto te dé una 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::keycombine', (event, arg) => {
console.log(arg) // prints "keycombine"
//setting the new value
store.set('defaultKeyCombination', arg)
// sending reply to renderer work is done with new key
event.reply('done::keycombine', store.get('defaultKeyCombination'))
})
app.wheReady().then(createWindow)
//app.on('ready', createWindow)
app.on('window-all-closed', () => {
// On macOS it is common 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::keycombine',args)
}
ipcRenderer.on('done::keycombine', (event, arg) => {
console.log("DONEEEEEEEEEE", arg)
})
Respuesta #2
Digamos 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>
Función loadHotkey: cargará la tecla de acceso rápido registrada previamente. La tecla de acceso rápido está en appData.
Función saveHotKey: registrará un nuevo Hotkey basado en tu entrada y guardará este valor en appData, por lo que persistirá.
En 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')
