You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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

火山引擎 最新活动