在Electron应用程序中使全局快捷键可配置

3
我将一个Web应用程序(一个软电话)打包成Electron应用程序,以便利用我可以在应用程序中编码的一些自动化功能。
我正在使用Electron的globalShortcut来注册全局快捷键,以将应用程序置于前台并聚焦于Web应用程序的搜索栏。
然而,由于我的同事也开始使用该应用程序,因此我希望使使用的全局快捷键可配置。
由于我无法更改Web应用程序本身(它由第三方托管),因此我不知道如何创建一个菜单,在其中用户可以设置快捷方式。
我知道有menumenuItem对象,但我不知道如何要求用户使用它来设置全局快捷键。
我该怎么做?

编辑:
为了澄清我的期望:正如我已经解释的那样,我正在寻找任何解决方案,使得可以提供一个菜单,您可以在其中配置快捷方式。该菜单可以位于菜单栏/工具栏中,也可以通过javascript DOM操作放置在Web文档中-作为最后的选择可能使用iframe?
任何关于如何保存应用程序重启后设置的想法也将不胜感激。

2个回答

3
在看到这个问题后,我对您的主题进行了小型研究。首先想到的是 electron 是否可以提供访问按键事件的权限,但根据此 thread,electron 开发人员正在停止 electron 成为一个键盘记录器。因此,我有以下方法解决此问题。我不知道这是否是针对这种情况的最佳方法,但这是我认为可以完成的方式。基本上是围绕 electron-store 构建的,它可用于持久化用户定义的密钥组合。因此,应用程序可以从存储中检索定义的密钥组合(如果没有配置组合,则使用模式提供的默认密钥组合),并使用它注册一个全局快捷键。我提供了如何实现它的步骤。
  1. 使用 electron-store 安装和配置默认密钥值。如下所示

main.js

const Store = require('electron-store'); 
const schema = {
    defaultKeyCombination: {
        type: 'string',
        default: 'CommandOrControl+Y'
    }
}
const store = new Store({schema});
  1. 导入此defaultKeyCombination,您可以在应用准备就绪时注册全局快捷键。(不要忘记在应用程序销毁时删除全局快捷键)
app.on('ready', () => {
    // Register a defaultKeyCombination shortcut listener.
    globalShortcut.register(store.get('defaultKeyCombination'), () => {
    // Do stuff when Y and either Command/Control is pressed.
    })
})

  1. 从菜单点击(菜单栏>选项>配置)创建并打开另一个browserWindow,让用户使用可用的修饰符按键代码在输入框中创建/输入加速键组合;最好在输入框下方的新窗口中显示这些内容; 例如:用户可以在浏览器上输入修饰符+按键代码,如CmdOrCtrl + A

  2. 一旦用户按下提交按钮,使用IPCRenderer将输入的键组合发送到主进程,并将存储器defaultKeyCombination的值设置为接收到的值。

  3. 触发IPC以发送回复告诉用户“请重新启动应用程序”,并在警报或其他地方显示它。

渲染进程
let args = "CmdOrCtrl+A"
ipcRenderer.send('set::keycombine',args)
    
ipcRenderer.on('done::keycombine', (event, arg) => {
// display message to restart the app
})

主进程
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')
})

一旦应用程序重新启动,存储将加载新配置的键组合并使用它注册快捷事件。
这是我在进行这个小研究时想到的。在这里,我发现了一个名为iohook的按键事件监听器,但这仅适用于electron 2.XX。在上述过程中可能会出现错误和流程问题,我只是贴了一些代码来获得一个想法。
编辑1:
这是我的样本。在我的index.html中,我定义了一个按钮来调用set()函数。您可以集成inputbox,以便输入命令。一旦使用存储设置了密钥,它就始终使用此新键值进行加载,除非用户更改它。您可以从electron-store这里了解更多信息。希望这能给您一个想法:)

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)
})


我认为你的解决方案正是我所需要的。我只有一个问题:我应该在哪里加载Renderer.js? - wullxz
我已经找到了:Renderer.js的内容需要放入我加载以显示和编辑设置的html页面中。它很有效! :) 只有一个问题(我只是将其注释掉):event.reply方法似乎不存在。出现了异常。 - wullxz

1
假设 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函数:将加载先前注册的热键。热键在appData中。

saveHotKey函数:将根据您的输入注册新的热键,并将此值保存到appData,以便持久化。

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')

谢谢,您的解决方案也起作用了,并向我展示了如何打开另一个设置窗口。 - wullxz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接