CGEvent 是 macOS 中 Core Graphics 框架提供的一个结构体,用于表示一个低层级的输入事件,比如键盘、鼠标、滚轮等事件。它既可以表示系统中捕捉到的真实用户事件,也可以用于创建和发送模拟事件(synthetic event),广泛用于辅助功能、自动化控制、截图软件等场景。
常见用途
1、创建虚拟键盘事件(例如自动输入);
2、读取和修改事件的具体属性(如位置、键码、按钮等);
3、获取当前系统或用户的真实事件数据;
4、监听/拦截事件(配合 tap,比如 CGEventTapCreate)。
构造方法
1、init(mouseEventSource:mouseType: mouseCursorPosition: mouseButton:)
init?(mouseEventSource: CGEventSource?, mouseType: CGEventType, mouseCursorPosition: CGPoint, mouseButton: CGMouseButton)
创建鼠标事件:
1)mouseType: .leftMouseDown、.leftMouseUp、.mouseMoved 等;
2)mouseCursorPosition: 屏幕坐标(0,0)在左下角;
3)mouseButton: .left、.right、.center。
2、init(keyboardEventSource:virtualKey:keyDown:)
init?(keyboardEventSource: CGEventSource?, virtualKey: CGKeyCode, keyDown: Bool)
创建键盘事件:
virtualKey: 键码(如 0 是 A);
keyDown: true 表示按下,false 表示松开。
3、init(tap:type:event:)
init?(tap: CGEventTapLocation, type: CGEventType, event: CGEvent?)
拷贝一个已有事件(较少使用)。
4、init?(scrollWheelEvent2Source:unit:wheelCount:…)
init?(scrollWheelEvent2Source source: CGEventSource?,
unit: CGScrollEventUnit,
wheelCount: Int32,
wheel1: Int32,
wheel2: Int32,
wheel3: Int32)
1)source:CGEventSource?类型,事件源,通常使用 .hidSystemState 创建;
2)unit:CGScrollEventUnit类型,滚动单位,分为像素(.pixel)或行(.line);
3)wheelCount:Int32类型,滚轮数量(1~3),对应后续的 wheel1/2/3;
4)wheel1:Int32类型,主垂直滚轮(正数表示向上,负数表示向下);
5)wheel2:Int32类型,水平滚轮(正数表示右滚,负数表示左滚);
6)wheel3:Int32类型,第三维度滚动,一般不使用,设为 0。
常用属性
1、type: 获取事件类型(CGEventType);
2、location: 获取事件的位置(CGPoint);
3、timestamp: 时间戳(CGEventTimestamp);
4、flags: 获取按键修饰符(如 .maskCommand, .maskShift 等)。
常用方法
1、func post(tap: CGEventTapLocation):将事件“发送/注入”到系统事件流中(例如模拟鼠标点击);
2、func setIntegerValueField(_ field: CGEventField, value: Int64):设置整数类型的字段(如鼠标按钮编号、滚动值、键码等);
3、func integerValueField(_ field: CGEventField) -> Int64:获取事件中的某个整数值;
4、func setDoubleValueField(_ field: CGEventField, value: Double):设置双精度字段(通常用于压感、鼠标速度等);
5、func doubleValueField(_ field: CGEventField) -> Double:获取 double 类型的字段值;
6、func setFlags(_ flags: CGEventFlags):设置事件的修饰符(Command、Shift 等);
7、func flags() -> CGEventFlags:获取事件包含的修饰符;
8、func setType(_ type: CGEventType):设置事件类型,例如 .leftMouseDown;
9、func type() -> CGEventType:获取事件类型;
10、func setLocation(_ point: CGPoint):设置事件的位置;
11、func location() -> CGPoint:获取事件的位置;
12、func setUnicodeString(…):设置输入文本内容(用于文本键入)。
使用示例:
if let event = CGEvent(mouseEventSource: nil,
mouseType: .leftMouseDown,
mouseCursorPosition: CGPoint(x: 100, y: 100),
mouseButton: .left) {
event.setType(.leftMouseDown)
event.setLocation(CGPoint(x: 200, y: 200))
event.setFlags(.maskCommand) // 按下了 Command 键时的事件
event.post(tap: .cghidEventTap)
}
CGEventType
这是表示事件类型的枚举,例如鼠标点击、移动、键盘事件等。
1、.mouseMoved:鼠标移动;
2、.leftMouseDown:左键按下;
3、.leftMouseUp:左键抬起;
4、.rightMouseDown:右键按下;
5、.rightMouseUp:右键抬起;
6、.otherMouseDown:其他按钮按下(如中键);
7、.otherMouseUp:其他按钮抬起;
8、.scrollWheel:鼠标滚轮滚动;
9、.mouseDragged:拖动(左键按下后移动);
10、.rightMouseDragged:右键拖动;
11、.otherMouseDragged:其他键拖动。、
这类值用于指定事件的类型,例如:
let event = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: point, mouseButton: .left)
CGMouseButton
这是表示具体使用了哪一个鼠标按钮的枚举,和 mouseType 组合使用。
.left (0):左键;
.right (1):右键;
.center (2):中键或滚轮键。
例如:
let event = CGEvent(mouseEventSource: nil,
mouseType: .otherMouseDown,
mouseCursorPosition: CGPoint(x: 100, y: 100),
mouseButton: .center)
搭配 CGEventSource 使用
CGEventSource 是 macOS 中 Core Graphics 框架(CoreGraphics.framework)中的一个结构体类型,代表一个事件源(event source),主要用于创建和发送“合成的输入事件”(如模拟键盘按键、鼠标移动/点击等)。
let eventSource = CGEventSource(stateID: .hidSystemState)
.hidSystemState:表示来源于人类输入设备(Human Interface Device),用于模拟真实用户行为;
.combinedSessionState:用于模拟多个用户会话共享的事件。
构造模拟事件时通常提供一个 CGEventSource:
let src = CGEventSource(stateID: .hidSystemState)
let mouseDown = CGEvent(mouseEventSource: src, mouseType: .leftMouseDown, mouseCursorPosition: pos, mouseButton: .left)
let mouseUp = CGEvent(mouseEventSource: src, mouseType: .leftMouseUp, mouseCursorPosition: pos, mouseButton: .left)
使用场景
1、模拟鼠标点击
let source = CGEventSource(stateID: .hidSystemState)!
let point = CGPoint(x: 300, y: 300)
let mouseDown = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: point, mouseButton: .left)
let mouseUp = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: point, mouseButton: .left)
mouseDown?.post(tap: .cghidEventTap)
mouseUp?.post(tap: .cghidEventTap)
2、模拟按键输入
let source = CGEventSource(stateID: .hidSystemState)!
let keyDown = CGEvent(keyboardEventSource: source, virtualKey: 0x0, keyDown: true) // 'A' 键
let keyUp = CGEvent(keyboardEventSource: source, virtualKey: 0x0, keyDown: false)
keyDown?.post(tap: .cghidEventTap)
keyUp?.post(tap: .cghidEventTap)
3、模拟滚轮向下滚动3行
let source = CGEventSource(stateID: .hidSystemState)
let scrollEvent = CGEvent(scrollWheelEvent2Source: source,
unit: .line,
wheelCount: 1,
wheel1: -3,
wheel2: 0,
wheel3: 0)
scrollEvent?.post(tap: .cghidEventTap)
事件发送方法
CGEvent的post方法用于将事件发送给系统。
func post(tap: .cghidEventTap)
其中参数 tap 指的是事件注入位置:
.cghidEventTap: 直接注入到系统硬件事件流中(更自然、推荐)。
.cgSessionEventTap: 注入到当前用户 session(某些权限较低的操作可能用它)。
.cgAnnotatedSessionEventTap: 用于辅助功能系统(通常不使用)。
示例:模拟点击
mouseDown?.post(tap: .cghidEventTap)
mouseUp?.post(tap: .cghidEventTap)
意思是:先模拟鼠标按下,再模拟松开,从而完成一次点击。
注意事项
所有 CGEvent 模拟的输入事件默认没有 UI 权限限制,但部分应用(沙盒内或需要辅助功能权限)可能拦截失败;
如果开发的是沙盒应用(App Sandbox 开启),必须请求辅助功能权限(Accessibility);
post(tap:) 并不会触发自己代码内部的 NSEvent.addGlobalMonitor 监听器。
总结
CGEvent可以模拟鼠标、键盘和滚轮的事件,不能用来监听用户输入。
在大多数情况下 CGEventType 与 CGMouseButton 是一一对应的(比如 .leftMouseDown 对应 .left)。
对于 CGEventType.otherMouseDown / otherMouseDragged / otherMouseUp,必须通过 CGMouseButton 告诉系统是哪个「非左/右」键触发了事件(中键、侧键等等)。