如何在Electron全屏应用中限制鼠标活动范围?
解决Electron双屏全屏游戏鼠标限制问题
嘿,刚好我之前做Electron游戏时碰到过一模一样的需求——双屏环境下要把鼠标锁在游戏窗口里,还得保留光标显示,不能像canvas.requestPointerLock()那样把光标藏起来。给你两个靠谱的方案:
方案一:用Electron原生光标锁定API(优先推荐)
Electron的BrowserWindow其实自带了光标锁定的方法,既能把光标限制在窗口内,又能保持光标可见,完美解决你的痛点。
实现代码(主进程)
const { app, BrowserWindow, screen } = require('electron'); let mainWindow; function createGameWindow() { // 获取当前屏幕的尺寸(双屏场景下确保窗口绑定到激活的屏幕) const activeDisplay = screen.getDisplayNearestPoint(screen.getCursorScreenPoint()); const { width, height } = activeDisplay.workAreaSize; mainWindow = new BrowserWindow({ width: width, height: height, fullscreen: true, frame: false, // 游戏常用无边框配置,可选 webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true } }); // 加载你的游戏页面 mainWindow.loadFile('game.html'); // 窗口就绪后锁定光标 mainWindow.on('ready-to-show', () => { // 把光标锁定在窗口范围内 mainWindow.setCursorGrab(true); // 强制保持光标可见 mainWindow.setCursorVisible(true); // 防止窗口被意外拖动(全屏下可能不需要,但双屏场景建议加上) mainWindow.setMovable(false); }); // 窗口关闭时释放光标锁定 mainWindow.on('closed', () => { mainWindow.setCursorGrab(false); mainWindow = null; }); } app.whenReady().then(createGameWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createGameWindow(); });
注意事项
- 跨平台兼容性:Windows上直接生效;macOS需要用户授权(第一次运行会弹出权限请求,用户允许后就正常了);Linux部分桌面环境可能需要额外配置,但大部分主流环境没问题。
- 这个方法比web的
requestPointerLock()更适合双屏全屏场景,因为它是直接绑定到Electron窗口的,不会出现光标跑到其他屏幕的情况。
方案二:手动监听鼠标移动,强制拉回光标(兜底方案)
如果原生API在某些特殊平台或场景下不好用,可以用这个手动兜底的方法,通过监听鼠标位置,一旦超出窗口边界就强制把光标拉回来。
实现代码(渲染进程)
const { remote } = require('electron'); const currentWindow = remote.getCurrentWindow(); let windowBounds = currentWindow.getBounds(); // 监听窗口尺寸变化,更新边界值 currentWindow.on('resize', () => { windowBounds = currentWindow.getBounds(); }); // 监听鼠标移动事件 document.addEventListener('mousemove', (e) => { const { screenX: mouseX, screenY: mouseY } = e; let newX = mouseX; let newY = mouseY; // 检查是否超出窗口边界 if (mouseX < windowBounds.x) newX = windowBounds.x + 1; if (mouseX > windowBounds.x + windowBounds.width) newX = windowBounds.x + windowBounds.width - 1; if (mouseY < windowBounds.y) newY = windowBounds.y + 1; if (mouseY > windowBounds.y + windowBounds.height) newY = windowBounds.y + windowBounds.height - 1; // 超出的话强制设置光标位置 if (newX !== mouseX || newY !== mouseY) { remote.screen.setCursorPosition(newX, newY); } });
注意事项
- 这个方法兼容性极强,但鼠标移动到边界时会有轻微的“拉扯感”,体验不如原生API流畅。
- 全屏模式下要确保
windowBounds是当前屏幕的完整尺寸,双屏时记得绑定到游戏所在的屏幕。
总结
优先用方案一的原生API,流畅度和兼容性都更好;如果碰到特殊平台的适配问题,再用方案二兜底。记得在双屏环境下多测试,比如把游戏窗口拖到第二个屏幕,确认光标不会跑到第一个屏幕里。
内容的提问来源于stack exchange,提问作者Mark Taylor




