You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CGEventTap接收自定义发送CGEvent时CGEventFlags异常如何解决

问题原因
  • 你手动创建CGEvent时传入的keyboardEventSource为nil,系统会为这类无真实HID设备关联的模拟事件自动添加私有标记位:你看到的537001984换算为十六进制是0x20040000,其中包含系统自动附加的CGEventFlags.maskNonCoalesced(非合并事件标记)、模拟事件专属私有位,这些位是物理按键事件不会携带的。
  • 直接给event.flags赋值只会覆盖你显式指定的修饰键位,系统保留的私有标记位不会被覆盖,依然会被追加到最终的flags数值中,所以和物理按键触发的flags数值不一致。
  • 物理按键触发的事件flags除了修饰键位,还会携带HID设备相关的低阶状态位,手动创建的事件默认不会携带这部分内容。
解决方法

提供两种可行方案,按需选择:

方案1:优化模拟事件创建逻辑,尽可能匹配真实事件特征

创建事件时指定和系统硬件事件一致的事件源,避免系统添加多余的私有标记,同时在回调中只过滤业务需要关心的修饰键位,忽略系统私有位即可得到和物理按键一致的输出,修改后的代码如下:

import Cocoa
import Carbon

func createEventTap() {
    func callback(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent, refcon: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
        // 仅保留业务关心的修饰键位,忽略系统私有标记位
        let validFlagMask: CGEventFlags = [.maskShift, .maskControl, .maskAlternate, .maskCommand, .maskAlphaShift]
        let validFlags = event.flags.intersection(validFlagMask)
        print(validFlags.rawValue)
        return Unmanaged.passUnretained(event)
    }

    let eventMask = (1 << CGEventType.keyDown.rawValue)
    let eventTap = CGEvent.tapCreate(tap: .cghidEventTap, place: .tailAppendEventTap, options: .defaultTap
                                     , eventsOfInterest: CGEventMask(eventMask), callback: callback, userInfo: nil)!
    let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
    CGEvent.tapEnable(tap: eventTap, enable: true)
}
 
createEventTap()

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
    // 指定和系统HID状态一致的事件源,减少系统附加标记
    guard let eventSource = CGEventSource(stateID: .hidSystemState) else { return }
    eventSource.flags = .maskShift
    let event = CGEvent(keyboardEventSource: eventSource, virtualKey: CGKeyCode(kVK_Space), keyDown: true)!
    event.post(tap: .cghidEventTap)
})

方案2:回调里手动修正模拟事件的flags

如果需要flags数值完全和物理事件一致,可以在生成模拟事件时给事件添加自定义标识,回调里识别到是自身发送的事件后直接修改flags为目标值:

// 发送事件时添加自定义标记
event.setIntegerValueField(.eventSourceUserData, value: 999)

// 回调中识别并修正flag
if event.getIntegerValueField(.eventSourceUserData) == 999 {
    event.flags = CGEventFlags(rawValue: 131330)
}

内容的提问来源于stack exchange,提问作者Dexter Leng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 20:24:07