首页
/ Electron 深入解析 MouseInputEvent:用 webContents.sendInputEvent 模拟鼠标输入事件

Electron 深入解析 MouseInputEvent:用 webContents.sendInputEvent 模拟鼠标输入事件

2026-09-06 13:56:52作者:房伟宁

MouseInputEvent 是 Electron 中用于描述鼠标输入事件的 API 结构体,它是 webContents.sendInputEvent() 方法可接受的输入类型之一。在 UI 自动化、端到端测试、远程操控桌面应用等场景中,通过主进程向渲染进程页面"注入"鼠标事件是核心能力。读完本文,你将掌握 MouseInputEvent 的完整字段定义、继承体系、事件类型与修饰键组合方式,并能基于 Electron 源码理解一条鼠标事件从主进程 JS 对象到 Blink WebMouseEvent 再到渲染进程页面的完整投递链路。

MouseInputEvent 对象定义

MouseInputEvent 对象继承自 InputEvent,定义见 mouse-input-event.md,完整字段如下:

字段 类型 必填 说明
type string 事件类型,可取 mouseDownmouseUpmouseEntermouseLeavecontextMenumouseWheelmouseMove
x Integer 事件在页面(视口)中的 X 坐标
y Integer 事件在页面(视口)中的 Y 坐标
button string 按下的鼠标按钮,可取 leftmiddleright
globalX Integer 全局坐标 X
globalY Integer 全局坐标 Y
movementX Integer 相对上一次鼠标移动事件的 X 位移
movementY Integer 相对上一次鼠标移动事件的 Y 位移
modifiers string[] 修饰键数组,继承自 InputEvent(见下文)

几点使用要点:

  • type 的 7 个取值覆盖了鼠标交互的全部形态:按下(mouseDown)、抬起(mouseUp)、进入/离开元素(mouseEnter / mouseLeave)、右键上下文菜单(contextMenu)、滚轮(mouseWheel)以及移动(mouseMove)。注意 mouseWheel 类型建议改用其子类 MouseWheelInputEvent,它会补充滚轮专属字段。
  • x / y 是相对于页面视口的坐标,因此必须与目标页面当前渲染尺寸匹配;globalX / globalY 则用于需要屏幕级坐标的场景。
  • clickCount 用于表达单击/双击/连击次数,配合 mouseDown + mouseUp 可模拟完整点击序列。

父类 InputEvent:type 与 modifiers

MouseInputEvent 继承自 InputEvent,其中 modifiers 字段是一个字符串数组,可取:

shiftcontrolctrlaltmetacommandcmdiskeypadisautorepeatleftbuttondownmiddlebuttondownrightbuttondowncapslocknumlockleftright

前 7 个是按键修饰符(ctrlcontrol 的别名、cmdcommand 的别名),leftbuttondown 等三个用于表达"发送本事件时其他鼠标按钮正处于按下状态"——例如模拟按住左键拖拽时发送 mouseMove

子类 MouseWheelInputEvent

MouseWheelInputEvent 继承自 MouseInputEventtype 固定为 mouseWheel,并额外提供滚轮事件专属字段:

字段 类型 说明
deltaX / deltaY Integer 水平和垂直滚动增量
wheelTicksX / wheelTicksY Integer 传统滚轮刻度值
accelerationRatioX / accelerationRatioY Integer 加速度比例
hasPreciseScrollingDeltas boolean 是否为精确滚动增量(触控板平滑滚动场景)
canScroll boolean 当前是否可滚动

键盘输入则对应另一个平级结构 KeyboardInputEvent,与鼠标事件共享同一个 sendInputEvent() 入口。

实际使用:webContents.sendInputEvent

MouseInputEvent 最主要的使用方式是作为 contents.sendInputEvent(inputEvent) 的参数,该方法向页面发送一个输入事件,可接受的类型为 MouseInputEvent | MouseWheelInputEvent | KeyboardInputEvent

文档中明确给出了一个重要前提:

包含该 contents 的 BrowserWindow 必须处于聚焦状态(focused),sendInputEvent() 才能生效。

一个模拟完整左键点击的示例(参考 api-web-contents-spec.ts 中的测试写法):

// 主进程:在页面 (100, 100) 位置模拟一次左键点击
w.webContents.sendInputEvent({ type: 'mouseDown', button: 'left', x: 100, y: 100 });
w.webContents.sendInputEvent({ type: 'mouseUp', button: 'left', x: 100, y: 100 });

模拟带修饰键的右键上下文菜单事件:

// 触发 contextmenu 事件
w.webContents.sendInputEvent({ type: 'contextMenu', button: 'right', x: 200, y: 150 });

模拟滚轮滚动(使用 MouseWheelInputEvent 扩展字段):

// 向下滚动 3 个滚轮刻度
w.webContents.sendInputEvent({
  type: 'mouseWheel',
  x: 300,
  y: 300,
  deltaX: 0,
  deltaY: -3,
  wheelTicksX: 0,
  wheelTicksY: -3
});

该能力同样适用于 <webview> 标签:sendInputEvent 被列入了 web-view-methods.ts 的 webview 方法白名单,因此 webview.sendInputEvent(...)webContents.sendInputEvent(...) 行为一致,详见 webview-tag.md

源码级原理:一条鼠标事件的投递链路

Electron 在主进程侧的 C++ 实现位于 electron_api_web_contents.cc,方法在 V8 绑定处通过 .SetMethod("sendInputEvent", &WebContents::SendInputEvent) 注册(见 electron_api_web_contents.cc#L5043)。

SendInputEvent 的实现可以看到鼠标事件的处理流程:

  1. 解析事件类型:先通过 gin::GetWebInputEventType 将 JS 对象中的 type 字符串解析为 blink::WebInputEvent::Type 枚举;
  2. 鼠标事件分支:当 IsMouseEventType(type) 为真时,用 gin 的转换机制把 JS 对象整体反序列化为 blink::WebMouseEventxybuttonclickCountmodifiers 等字段在此完成映射),然后进入两条投递路径之一:
    • 若该 WebContents 是离屏渲染(OffScreen Rendering)模式,则调用 GetOffScreenRenderWidgetHostView()->SendMouseEvent(mouse_event)
    • 否则调用 Chromium 的 rwh->ForwardMouseEvent(mouse_event),即通过 RenderWidgetHost 把事件转发给渲染进程;
  3. 滚轮事件分支kMouseWheel 类型会反序列化为 blink::WebMouseWheelEvent。源码中有一段值得注意的细节——由于 Chromium 要求滚轮事件携带 phase 信息(并以此做了 DCHECK 校验),Electron 会先补上 phase = kPhaseBegan 并以阻塞方式 ForwardWheelEvent,随后再合成一个 kPhaseEnded 的收尾事件来完成本次滚动手势。这正是上面 MouseWheelInputEvent 示例中不需要手动传 phase 的原因。

也就是说,文档层面的 x/y/button/clickCount 等字段,最终都对应到 Blink 原生输入事件对象的同名属性,再经由 Chromium 的输入转发机制进入页面的 JavaScript 事件循环,被 clickmousedowncontextmenu 等标准 DOM 事件监听器捕获。测试文件 api-web-contents-spec.tsdescribe('sendInputEvent(event)') 以及多处 { type: 'mouseDown', button: 'left', x: 100, y: 100 } 形式的用例,正是对这一链路的持续回归验证。

实践注意事项

  • 窗口必须聚焦:这是文档明确声明的运行前提,自动化脚本中发送事件前应确保目标 BrowserWindowfocus()
  • 事件顺序要符合真实手势mousedownmouseup 成对出现;双击需以 clickCount: 2 的第二次 mouseDown 表达;拖拽需在 mouseMove 中携带 leftbuttondown 修饰符;
  • 坐标基准是视口x / y 相对页面视口而非屏幕,跨分辨率测试时注意与窗口实际尺寸一致;
  • 离屏渲染可用:源码中 OffScreen 分支独立存在,说明该 API 同样支持 offscreen 模式的 WebContents,这对无窗口自动化尤其有用。

相关文档

登录后查看全文
热门项目推荐
相关项目推荐