从零开始的electron开发-菜单与快捷键

菜单与快捷键

虽然咱们在平时使用桌面软件时,大多数状况下都是用鼠标进行操做,一些软件提供了菜单与键盘快捷键进行操做,mac系统上比较常见一些。若是在使用软件时有对应的快捷键操做或者菜单,会让用户的使用体验更加顺畅和方便一点。本章主要对注册快捷键的几种方式进行说明以及菜单的系统差别化处理。vue

Menu菜单

菜单这个东西呢,通常常见于mac系统上,win的话国内比较少见,算是一种约定俗成吧。实际上快捷键和菜单方面能够说是一体的,咱们能够在菜单上注册对应的键盘按键,故mac系统可使用这个方式把快捷键一块儿处理了。
优势:最简洁的快捷键处理,简单方便。
缺点:只能在应用程序被聚焦时触发(焦点在程序上,不仅是显示),因为win通常不使用菜单,故只能用于mac上。git

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: ['肯定']
  })
}

菜单的快捷键注册是用accelerator添加的,固然你也能够根据系统的不一样进行差别化处理,role的话是electron内置的行为,好比copy - 复制paste - 粘贴等等,能够参考官方文档 github

在windows下咱们把菜单隐藏掉,mac的话正常显示:web

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

主进程监听快捷键

globalShortcut

globalShortcut模块能够在操做系统中注册/注销全局快捷键,可是我的不推荐用这种方式来注册快捷键:
优势:响应级别最高,只要软件在运行中,不管软件处于什么状态(没聚焦甚至隐藏),都会响应。
缺点:若是快捷键已经被其余应用程序注册掉,那么会注册失败。注册成功后,因为其响应级别最高,因此会影响其余软件快捷键的使用,在启动软件后,其余软件的快捷键相同的话其余软件的快捷键没法生效。vue-cli

// 主进程,渲染进程可使用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

第三方的npm包,api和globalShortcut基本一致,相对而言没那么激进,是针对于窗口注册的,故需传入窗口进行注册,当窗口没聚焦时,不会相应。
优势:针对于窗口的监听,响应需处于聚焦状态,基本上能知足大多数场景。
缺点:须要引入第三方包,页面有webview,且焦点在webview上时没法触发。npm

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)

渲染进程监听快捷键

本身页面监听

实际上就是网页keyup的监听,能够用通讯把键盘按键的信息传送到主进程。
固然你也能够在主进程中使用before-input-event,渲染进程中调度页面中的keydown和keyup事件以前,会发出before-input-event事件,能够在主进程捕获按键信息。
优势:针对于页面的监听,经常使用于某个页面的特殊按键监听。
缺点:页面有iframe或webview,且焦点在iframe或webview上时,没法触发(iframe能够触发before-input-event)。windows

渲染进程:
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()
  }
})

组合按键:固然通常来讲快捷键都是组合按键的,咱们能够借助第三方按键库来处理。api

npm i mousetrap

渲染进程:

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

Mousetrap.unbind('ctrl+k')

webview或iframe嵌入网页监听

若是咱们的页面中有webview或iframe,且焦点在webview或iframe上时,会致使咱们的快捷键失效。app

  1. Menu菜单和globalShortcut不会失效。
  2. electron-localshortcut:webview无效,iframe有效
  3. keyup:webview无效,iframe无效,before-input-event:iframe有效。

这样看下来在应用webview的时候比较难处理,只有Menu菜单和globalShortcut对其生效,那么还有其余方式吗?
咱们能够经过向webview注入preload.js来进行键盘按键的监听,而后将键盘信息回传给咱们的渲染进程dom

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

简单梳理一下,咱们把webviewPreload.js注入webview,经过这个js进行键盘的keyup监听,而后经过sendToHost把信息回传给渲染进程,渲染进程中获取回传的信息。
渲染进程是看不到咱们注入js以及webview的打印,可使用webview.openDevTools(),打开webview的控制台查看。
本例子就没说明组合键了,想用组合键请自行注入mousetrap进行操做。

本系列更新只有利用周末和下班时间整理,比较多的内容的话更新会比较慢,但愿能对你有所帮助,请多多star或点赞收藏支持一下

本文地址:连接
本文github地址:连接

相关文章
相关标签/搜索