6
头图

Electron menu and shortcut keys

Although we usually use desktop software to operate with the mouse in most cases, some software provides menus and keyboard shortcuts for operation, which are more common on mac systems. If there is a corresponding shortcut key operation or menu when using the software, the user experience will be smoother and more convenient. This chapter mainly describes several ways of registering shortcut keys and the system differentiation processing of the menu.

Menu menu

The menu item is generally common on mac systems, and it is relatively rare in China for win. It is a kind of convention. In fact, the shortcut keys and the menu can be said to be integrated, we can register the corresponding keyboard keys on the menu, so the mac system can use this method to process the shortcut keys together.
Advantages: The most concise shortcut key processing, simple and convenient.
Disadvantages: It can only be triggered when the application is focused (the focus is on the program, not just the display). Since win generally does not use the menu, it can only be used on the mac.

import { app, dialog, Menu } from 'electron'
import config from './index'
import global from './global'
const os = require('os')
const isMac = process.platform === 'darwin'

const menuConfig = [{
  label: app.name,
  submenu: [{
    label: '关于',
    accelerator: isMac ? 'Alt+Cmd+I' : 'Alt+Shift+I',
    click: function () {
      info()
    }
  }]
}, {
  label: '设置',
  submenu: [{
    label: '快速重启',
    accelerator: 'CmdOrCtrl+F5',
    role: 'reload'
  }, {
    label: '退出',
    accelerator: 'CmdOrCtrl+Q',
    role: 'quit'
  }]
}, {
  label: '开发者设置',
  submenu: [{
    label: '切换到开发者模式',
    accelerator: 'CmdOrCtrl+I',
    role: 'toggledevtools'
  }]
}]

function info() {
  dialog.showMessageBox({
    title: '关于',
    type: 'info',
    message: 'vue-cli-electron',
    // detail: `版本信息:\nelectron版本:${process.versions.electron}\n当前系统:${os.type()} ${os.arch()} ${os.release()}\n当前版本:${process.env.VUE_APP_ENV},${process.env.VUE_APP_VERSION}`,
    detail: `版本信息:\nelectron版本:${process.versions.electron}\n当前系统:${os.type()} ${os.arch()} ${os.release()}\n当前版本:${global.envConfig.VUE_APP_ENV},${global.envConfig.VUE_APP_VERSION}`,
    noLink: true,
    buttons: ['确定']
  })
}

The shortcut key registration of the menu is accelerator . Of course, you can also differentiate according to the system. role is the built-in behavior of electron, such as copy-copy, paste-paste, etc., please refer to official document

We hide the menu under windows, and display it normally on mac:

function setMenu(win) {
  let menu
  if (config.devToolsShow) {
    menu = Menu.buildFromTemplate(menuConfig)
    Menu.setApplicationMenu(menu)
    win.webContents.openDevTools({ mode: 'detach' })
  } else {
    if (isMac) {
      menu = Menu.buildFromTemplate(menuConfig)
      Menu.setApplicationMenu(menu)
    } else {
      Menu.setApplicationMenu(null)
    }
    win.webContents.openDevTools({ mode: 'detach' })
    // win.webContents.closeDevTools()
  }
}

The main process monitor shortcut keys

globalShortcut

globalShortcut module can register/deregister global shortcut keys in the operating system, but I don’t recommend using this method to register shortcut keys:
Advantages: The highest response level, as long as the software is running, no matter what state the software is in (not focused or even hidden), it will respond.
Disadvantage: If the shortcut key has been registered by other applications, the registration will fail. After successful registration, because its response level is the highest, it will affect the use of shortcut keys of other software. After starting the software, if the shortcut keys of other software are the same, the shortcut keys of other software will not take effect.

// 主进程,渲染进程可以使用remote来注册:
const { app, globalShortcut } = require('electron')

app.whenReady().then(() => {
  const ret = globalShortcut.register('CommandOrControl+X', () => {
    console.log('CommandOrControl+X is pressed')
  })
  if (!ret) {
    console.log('registration failed')
  }
  // 检查快捷键是否注册成功
  console.log(globalShortcut.isRegistered('CommandOrControl+X'))
})

app.on('will-quit', () => {
  // 注销快捷键
  globalShortcut.unregister('CommandOrControl+X')

  // 注销所有快捷键
  globalShortcut.unregisterAll()
})

electron-localshortcut

The third-party npm package, api and globalShortcut basically the same. Relatively speaking, it is not so radical. It is for window registration, so it needs to be passed in to the window for registration. When the window is not focused, it will not respond.
Advantages: For window monitoring, the response needs to be in focus, which can basically meet most scenes.
Disadvantages: You need to introduce a third-party package, the page has a webview, and it cannot be triggered when the focus is on the webview.

npm install --save electron-localshortcut

const electronLocalshortcut = require('electron-localshortcut')
const win = new BrowserWindow()
win.loadUrl('https://github.com')
win.show()

electronLocalshortcut.register(win, 'Ctrl+A', () => {
  console.log('You pressed ctrl & A')
})
// 检查快捷键是否注册成功
console.log(electronLocalshortcut.isRegistered(win, 'Ctrl+A'))
// 注销快捷键
electronLocalshortcut.unregister(win, 'Ctrl+A')
electronLocalshortcut.unregisterAll(win)

Render process monitoring shortcut keys

Monitor on your own page

In fact, it is the monitoring of the web page keyup, and the information of the keyboard keys can be transmitted to the main process by communication.
Of course, you can also use before-input-event in the main process. Before the keydown and keyup events in the page are dispatched in the rendering process, the before-input-event event will be sent out, and the key information can be captured in the main process.
Advantages: For the monitoring of the page, it is often used for special button monitoring of a certain page.
Disadvantages: When the page has an iframe or webview, and the focus is on the iframe or webview, it cannot be triggered (iframe can trigger before-input-event).

渲染进程:
window.addEventListener('keyup', handleKeyPress, true)
function handleKeyPress(event) {
  $message.success(`keyup 监听${event.key}`)
  console.log(`You pressed ${event.key}`)
}
window.removeEventListener('keyup', handleKeyPress, true)


主进程:
win.webContents.on('before-input-event', (event, input) => {
  if (input.control && input.key.toLowerCase() === 'i') {
    console.log('Pressed Control+I')
    event.preventDefault()
  }
})

Combination keys: Of course, in general, shortcut keys are key combinations, and we can use a third-party key library to handle them.

npm i mousetrap

渲染进程:

Mousetrap.bind('ctrl+k', function() { 
  $message.success(`Mousetrap ctrl+k`)
})

Mousetrap.unbind('ctrl+k')

Webview or iframe embedded webpage monitoring

If our page has a webview or iframe, and the focus is on the webview or iframe, it will cause our shortcut keys to fail.

  1. The Menu menu and globalShortcut will not be invalidated.
  2. electron-localshortcut: webview is invalid, iframe is valid
  3. keyup: webview is invalid, iframe is invalid, before-input-event: iframe is valid.

It webview that it is more difficult to handle when 060df07950bab0 is applied. Only the Menu menu and globalShortcut are effective for it, so is there any other way?
We can webview , and then return the keyboard information to our rendering process

vue.config.js中electronBuilder修改为:
preload: { preload: 'src/renderer/preload/ipcRenderer.js', webviewPreload: 'src/renderer/preload/webview.js' }

webviewPreload是我们向webview注入的js,当然你得新建对应文件,注意一下我们建立的文件是webview.js,编译后为webviewPreload.js,故我们注入的为webviewPreload.js。
注:webview 启动及Node integration启用须在主进程窗口webPreferences进行配置。
webview.js:
const { ipcRenderer } = require('electron')
window.addEventListener('keyup', handleKeyPress, true)
function handleKeyPress(event) {
    console.log(event.key)
    ipcRenderer.sendToHost('ipc-message', {
        data: event.key
    })
}

渲染进程:
<webview ref="webviewRef" class="webview" src="https://www.baidu.com" :preload="state.preload" ></webview>
const { remote } = require('electron')
const path = require('path')

const webview = webviewRef.value
state.preload = path.resolve(remote.app.getAppPath(), './webviewPreload.js')
webview.addEventListener('ipc-message', webMessage)
webview.addEventListener('dom-ready', () => {
  webview.openDevTools()
})
function webMessage(event) {
  console.log('在此监听事件中接收webview嵌套页面所响应的事件', event)
  $message.success(`webview:${event.args[0].data}`)
}

To briefly sort out, we inject webviewPreload.js into the webview, monitor the keyboard keyup through this js, and then pass the information back to the rendering process through sendToHost, and get the returned information during the rendering process.
In the rendering process, we can't see the printing of our injected js and webview. You can use webview.openDevTools() to open the webview console to view.
This example does not explain the key combination. If you want to use the key combination, please inject mousetrap yourself.

This series of updates can only be organized during weekends and after get off work. If there are more content, the update will be slower. I hope it can be helpful to you. Please support it by star or like favorites.

The address of this article: https://xuxin123.com/electron/menu-shortcut
This github address: link


陌路凡歌
7.9k 声望258 粉丝

人笨,多听,多写,多看书