macOS下用CGEvent模拟Cmd+V粘贴无效果,代码遗漏了什么?
焦点被触发按钮抢占
你点击NSButton触发粘贴逻辑时,按钮会成为当前第一响应者,原本NSTextField的输入焦点会被抢走,模拟的Cmd+V事件会被发送到按钮而非输入框,自然不会触发粘贴。
解决方案:在发送模拟按键前先让目标NSTextField成为第一响应者,或者调用[NSApp preventWindowOrdering]避免点击按钮时抢夺焦点,也可以在点击按钮后加少量延迟再发送模拟事件,或者直接调用NSTextField的paste:方法不用模拟按键。缺少辅助功能权限
macOS从10.14之后就要求应用获取辅助功能权限才能发送系统级模拟按键事件。
解决方案:检查系统偏好设置>安全与隐私>隐私>辅助功能,确认你的应用已经被添加并勾选授权。可以在代码中用AXIsProcessTrusted()判断当前是否已经拿到权限,没拿到的话引导用户去开启。模拟按键事件构造错误
你当前只给keyDown事件设置了Command修饰符,keyUp事件没有携带相同的修饰符,系统会识别为按键序列不合法,不会触发对应的快捷键行为。
修改后的PostCommandAndKey参考代码:
void PostCommandAndKey(CGKeyCode keyCode) { CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); CGEventRef eventDown = CGEventCreateKeyboardEvent(source, keyCode, YES); CGEventRef eventUp = CGEventCreateKeyboardEvent(source, keyCode, NO); // 给按下和抬起事件都设置Command修饰 CGEventSetFlags(eventDown, kCGEventFlagMaskCommand); CGEventSetFlags(eventUp, kCGEventFlagMaskCommand); CGEventPost(kCGSessionEventTap, eventDown); // 加短延迟避免事件被系统丢弃 usleep(1000); CGEventPost(kCGSessionEventTap, eventUp); CFRelease(eventUp); CFRelease(eventDown); CFRelease(source); }
剪贴板写入和模拟按键无间隔
部分场景下剪贴板写入后需要极短的时间同步,立刻发送粘贴事件可能系统读取的还是旧的剪贴板内容。可以在写完剪贴板后、调用PostCommandAndKey前加10~50ms的延迟。同窗口内粘贴可直接调用系统方法无需模拟按键
如果你的需求只是在当前应用的NSTextField里粘贴内容,完全不用模拟全局快捷键,直接调用第一响应者的paste方法即可,无需申请权限,稳定性更高:
- (void) pasteClicked:(id)sender{ NSButton *button = (NSButton *)sender; PasteItem *pi = self.pasteItems[button.tag]; [self.pasteBoard setString:pi.text forType:NSPasteboardTypeString]; // 直接让当前第一响应者执行粘贴操作 [[[NSApp keyWindow] firstResponder] paste:nil]; }
内容的提问来源于stack exchange,提问作者Anoop Vaidya

