Cocoa Virtual Keystrokes Pain

时间:2010-04-19 08:38:09

标签: objective-c cocoa macos copy-paste nspasteboard

我正在编写一个应用程序,通过将突出显示的文本复制到NSPasteboard的generalPasteboard中来响应热键。在环顾四周寻找发送虚拟击键的解决方案后,我发现了这一点:How to send a "Cmd-C" keystroke to the active application in objective-c, or tell the application to do a copy operation?

我尝试过用NSAppleScript建议的applescript:

NSLog(@"Hotkey Pressed");
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; 

NSAppleScript *playScript;
playScript = [[NSAppleScript alloc] initWithSource:@"tell application \"System Events\" to keystroke \"c\" using command down"];

if([playScript isCompiled] == NO){
[playScript compileAndReturnError:nil];
}

id exerror = [playScript executeAndReturnError:nil];

if(exerror == nil){
 NSLog(@"Script Failed");
}

它有效,但仅在我第一次点击热键时。每次后续点击都不会抓取突出显示的文本。 generalPasteboard仍包含与再次运行脚本之前相同的内容。在运行代码之前清除generalPasteboard是没有用的,因为在尝试读取粘贴板内容时代码会失败。这是日志:

 Pastify[16929:a0b] woooooooo! I'm being CALLED
 Pastify[16929:a0b] Hotkey Pressed
 Pastify[16929:a0b] Error loading /Library/ScriptingAdditions/Adobe Unit Types.osax/Contents/MacOS/Adobe Unit Types:  dlopen(/Library/ScriptingAdditions/Adobe Unit Types.osax/Contents/MacOS/Adobe Unit Types, 262): no suitable image found.  Did find:
    /Library/ScriptingAdditions/Adobe Unit Types.osax/Contents/MacOS/Adobe Unit Types: no matching architecture in universal wrapper
 Pastify: OpenScripting.framework - scripting addition "/Library/ScriptingAdditions/Adobe Unit Types.osax" declares no loadable handlers.
 Pastify[16929:a0b] Size of copiedItems: 1
 Pastify[16929:a0b] Content of paste: 2010-04-19 03:41:04.355 Pastify[16929:a0b] woooooooo! I'm being CALLED
 Pastify[16929:a0b] Hotkey Pressed
 Pastify[16929:a0b] Size of copiedItems: 1
 Pastify[16929:a0b] Content of paste: 2010-04-19 03:41:04.355 Pastify[16929:a0b] woooooooo! I'm being CALLED
 Pastify[16929:a0b] Hotkey Pressed
 Pastify[16929:a0b] Size of copiedItems: 1
 Pastify[16929:a0b] Content of paste: 2010-04-19 03:41:04.355 Pastify[16929:a0b] woooooooo! I'm being CALLED

所以我尝试了下一个建议的解决方案:

 CFRelease(CGEventCreate(NULL));

 CGEventRef event1, event2, event3, event4;
 event1 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)50, true);
 event2 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)8, true);
 event3 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)8, false);
 event4 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)50, false);

 CGEventPost(kCGHIDEventTap, event1);
 CGEventPost(kCGHIDEventTap, event2);
 CGEventPost(kCGHIDEventTap, event3);
 CGEventPost(kCGHIDEventTap, event4);

上面应该发出按键Command + c,但我得到的只是一声嘟嘟声,而且粘贴板内容没有变化。

我的智慧结束了 - 任何人都可以告诉我我缺少的是什么,或者指出我想要的东西如此简单?

3 个答案:

答案 0 :(得分:1)

只是一个想法...... cmd-c技巧适用于最前面的应用程序。我怀疑你第一次运行热键触发这个正确的应用程序是最前面的,cmd-c工作,然后你的应用程序与粘贴板做了一些事情。在第二次运行时,热键被激活,但之前的应用程序不再是最前面的,因此cmd-c不起作用。实质上,您将cmd-c发送到其他应用程序。也许你的应用程序已经出现在前面或其他方面。

要避免此问题,您需要确保您定位的应用程序位于最前面。首先,您需要一些方法来找出最前面的应用程序是什么,然后在执行cmd -c激活该应用程序之前。例如在applescript中,如果我想在Safari上运行cmd -c,我会使用:

tell application "Safari" to activate
tell application "System Events" to keystroke "c" using command down

答案 1 :(得分:1)

您是否有理由不能使用服务?

如果你真的想通过合成事件来做到这一点,你最好的办法是发布一个修改过的键盘事件而不是向下/向上 - 有关详细信息,请参阅此问题。

Simulating key press events in Mac OS X

如果这不起作用,那么,你知道在哪里找到我: - )

答案 2 :(得分:0)

我真的不明白你为什么要这样做,但是如果你想确保你的事件进入特定的过程,那么使用CGEventPost的“ToPSN”变体。