electron 监听键盘事件

项目需要 electron 监听键盘事件,进行页面逻辑操作,上下键进行列表数据切换,左右键实现列表数据翻页

1. electron 键盘事件监听

electron 中可以使用globalShortcut监听键盘事件,具体可以查看 electron 官方文档,有详细的介绍

  • 注册事件:globalShortcut.register
  • 判断是否注册成功:globalShortcut.isRegistered
  • 注销注册事件:globalShortcut.unregisterAll

main.js 主进程文件中进行注册操作,具体代码如下所示:

js 复制代码
const { globalShortcut } = require("electron");

const createWindow = () => {
  const win = new BrowserWindow({});
  // 在创建窗口时,注册键盘事件
  handleRegister();
};

const handleRegister = () => {
  // 注册一个'Up'监听器
  globalShortcut.register("Up", () => {
    // 发送消息通知
    win.webContents.send("move-up");
  });
  // 检查'Up'是否注册成功
  console.log("键盘上注册成功", globalShortcut.isRegistered("Up"));

  globalShortcut.register("Down", () => {
    // 发送消息通知
    win.webContents.send("move-down");
  });
  // 检查'down'是否注册成功
  console.log("键盘下注册成功", globalShortcut.isRegistered("Down"));
};

app.whenReady().then(() => {
  // 调用该函数来打开窗口
  createWindow();

  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on("will-quit", () => {
  // 在应用即将退出时,注销所有快捷键,以避免内存泄漏
  globalShortcut.unregisterAll();
});

2. react 接受事件通知

electron 键盘事件注册后,需要在 react 页面中进行监听,如下创建了一个 useKeyboardController.tsx 进行统一处理

将键盘控制逻辑封装在了自定义的 hooks 中

它接受两个参数:handleMoveUp 和 handleMoveDown

然后在 useEffect 钩子中注册了监听器来接收来自主进程的事件

并在组件卸载时删除了这些监听器

js 复制代码
import { useEffect } from "react";
// 使用了 ipcRenderer 来监听来自主进程的事件
const { ipcRenderer } = window.require("electron");

const useKeyboardController = (
  handleMoveUp: Function,
  handleMoveDown: Function
) => {
  useEffect(() => {
    if (ipcRenderer && handleMoveUp && handleMoveDown) {
      // 处理上键逻辑
      const handleMoveUpWrapper = () => handleMoveUp();
      // 处理下键逻辑
      const handleMoveDownWrapper = () => handleMoveDown();

      // 事件监听
      ipcRenderer.on("move-up", handleMoveUpWrapper);
      ipcRenderer.on("move-down", handleMoveDownWrapper);
      return () => {
        // 取消事件监听
        ipcRenderer.removeListener("move-up", handleMoveUpWrapper);
        ipcRenderer.removeListener("move-down", handleMoveDownWrapper);
      };
    }
  }, [handleMoveUp, handleMoveDown]);
};

export default useKeyboardController;

3. 上下键选中切换

为了实现键盘上下键进行列表数据切换

可以使用 activeIndex 的状态来跟踪当前选中的项,并结合键盘上下键事件处理

以下是相应的完整代码:

js 复制代码
import useKeyboardController from "./useKeyboardController";

const [activeIndex, setActiveIndex] = useState(0);

const handleMoveUp = () => {
  // 处理向下键逻辑 序号减1
  setActiveIndex(activeIndex - 1);
};

const handleMoveDown = () => {
  // 处理向下键逻辑 序号加1
  setActiveIndex(activeIndex + 1);
};

useKeyboardController(
  handleMoveUp,
  handleMoveDown,
  handleMoveLeft,
  handleMoveRight
);

4. 左右键页面切换

为了实现键盘左右键实现翻页功能

可以使用 currentPage 的状态来跟踪当前页数,并结合键盘左右键事件处理。

其他逻辑和左右键基本一样,此处就不重复写了。

js 复制代码
// 左右键盘事件注册
globalShortcut.register("Left");
globalShortcut.register("Right");

const handleMoveLeft = () => {
  // 键盘向左执行,页码减1
  setCurrentPage(currentPage - 1);
};
const handleMoveRight = () => {
  // 键盘向右执行,页码加1
  setCurrentPage(currentPage + 1);
};

5. ipcRenderer 引用报错

使用const { ipcRenderer } = window.require('electron');代码报错

报错信息如下所示:

window.require is not a function

TypeError: window.require is not a function

解决办法:加一层判断,存在时,才能调用。这样就可以避免在浏览器环境下直接调用 Electron 模块,导致运行异常。

修改 useKeyboardController.tsx 页面逻辑,以下是修改后的代码:

js 复制代码
let ipcRenderer;
if (window.require) {
  const electron = window.require("electron");
  ipcRenderer = electron.ipcRenderer;
}

6. electron 关闭后打开报错

electron 窗口关闭后再打开,上述代码会导致报错,报错信息如下所示:

A JavaScript error occurred in the main process

UnhandledPromiseRejectionWarning: TypeError: Object has been destroyed at Function. (main.js:88:9) at Object.showErrorBox (node:electron/js2c/browser_init:49:5725) at node:electron/js2c/browser_init:189:763

问题分析:这是因为在窗口关闭后,对快捷键进行了注册,但在重新打开窗口时未进行注册。为避免这种问题,可以在应用关闭时取消注册快捷键监听器,并在应用再次激活时重新注册相同的监听器。

问题解决:窗口重新激活时,重新注册快捷键监听器

以下是修改后的代码:

js 复制代码
app.on("activate", () => {
  // 如果窗口重新激活时,重新注册快捷键监听器
  handleRegister();
});

app.on("before-quit", () => {
  // 在应用关闭前取消注册的快捷键监听器
  globalShortcut.unregisterAll();
});
相关推荐
马可家的菠萝22 分钟前
自动保存已经有了,为什么笔记软件还需要“历史版本”?
前端·后端·架构
半个落月37 分钟前
从 "use client" 到 Route Handler:用 Todos 理解 Next.js 水合与全栈请求
前端·react.js·next.js
qq_4523962340 分钟前
第七篇:《大型前端项目的模块化与目录结构设计》
前端
你脑门上的脚印1 小时前
Vue 项目从零实现语音转文字、文字转语音功能(完整可用 + 踩坑指南)
前端·vue.js
paopaokaka_luck1 小时前
基于springboot3+vue3的车间生产管理系统(Echarts图形化分析、BI报表)
java·前端·spring boot·学习·echarts
程序员鱼皮1 小时前
3 大 DeepSeek Harness 进阶玩法,招多个大肥鱼帮我干活!
前端·后端·ai编程
KoPa1 小时前
HeySmart:大模型开源网关基座-请求生命周期与钩子引擎
前端·后端
七牛开发者2 小时前
Coding Agent 如何跑稳长任务?从上下文管理到运行时状态
前端·javascript·后端
半个落月2 小时前
从 CSR 到 Server Component:吃透 Next.js 16 App Router 路由、布局与 SEO
前端·next.js
七牛开发者2 小时前
拆解 DeepSeek Harness:Profile 与 Bundle 如何装配运行时
前端·javascript·后端