globalShortcut 全局快捷键怎么用?注册失败/冲突怎么处理?
考察点
- globalShortcut API 的生命周期管理
- 冲突处理与平台权限差异
参考答案
1. 基本用法
const { globalShortcut, app } = require('electron');
app.whenReady().then(() => {
// 必须在 ready 之后注册
const ok = globalShortcut.register('CommandOrControl+Shift+A', () => {
toggleMainWindow(); // 唤起/隐藏主窗口
});
if (!ok) {
// 注册失败:组合键被系统或其他应用占用
logger.warn('全局快捷键注册失败');
}
// 检查是否注册成功
console.log(globalShortcut.isRegistered('CommandOrControl+Shift+A'));
});
app.on('will-quit', () => {
globalShortcut.unregisterAll(); // 退出时必须注销
});
2. 核心机制理解
- 注册的是系统级钩子:应用退到后台、最小化、甚至无窗口时都能收到
- 先到先得:同一组合键被别的应用先注册,你的 register 就返回 false(不会抢占)
- 只在主进程可用
3. 冲突处理策略
(1)注册失败检测 + 用户引导
function registerHotkey(accelerator) {
const ok = globalShortcut.register(accelerator, onHotkey);
if (!ok) {
// 通知渲染进程弹出提示:快捷键被占用,请修改
mainWindow?.webContents.send('hotkey:register-failed', accelerator);
return false;
}
return true;
}
(2)支持用户自定义快捷键
- 设置页让用户录制快捷键(监听 keydown 组合成 accelerator 字符串)
- 修改流程:先
unregister旧的 →register新的 → 失败则回滚旧的并提示 - accelerator 语法:
CommandOrControl(跨平台映射 Cmd/Ctrl)、Alt、Shift、Super,功能键F1-F24,方向键Up/Down等
(3)多快捷键管理 用 Map 维护 accelerator → callback 的映射,统一注册/注销,避免散落各处忘记释放。
4. 平台差异与权限
- macOS:普通全局快捷键(注册型)不需要权限;但如果你是监听型(监听全局键盘输入,如实现全局划词),需要 CGEventTap,要辅助功能权限——这是两种完全不同的技术路线,面试要分清
- Windows:
Ctrl+Alt+Del、Win+L等系统保留组合无法注册;媒体键部分支持 - Wayland(Linux):全局快捷键支持残缺,X11 正常——Linux 下要做降级
5. 常见坑
- ready 之前注册会静默失败
- 忘记 will-quit 注销:虽然进程退出系统会清理,但热重载开发时会残留
- accelerator 字符串格式错(如
Ctrl+后面没键名)注册返回 false 而不是抛错,要检查返回值 - 与应用内快捷键混淆:应用内快捷键用菜单的
accelerator或渲染进程的 keydown,只有需要"全局"才用 globalShortcut
面试话术
注册型全局快捷键用 globalShortcut,核心处理是注册失败回滚与用户自定义。要注意它和"全局键盘监听"是两条路线:前者系统分发无需权限,后者(CGEventTap/HOOK)需要辅助功能权限,场景不同不能混用。
常见追问
- 应用内快捷键冲突怎么办? 优先用 Menu 的 accelerator(与系统菜单集成好),渲染进程的 keydown 处理注意输入框聚焦时不触发。
- 如何实现"按住说话"这类按下/抬起都感知? globalShortcut 只触发按下,抬起需要用低级钩子(iohook 之类的原生模块)或 CGEventTap。