0

我正在尝试将一个NSRunningApplication*实例置于前台,并注入一个键盘事件。

NSRunningApplication* app = ...;
[app activateWithOptions: 0];
inject_keystrokes();

... 无法注入键盘事件,但是:

NSRunningApplication* app = ...;
[app activateWithOptions: 0];
dispatch_time_t _100ms = dispatch_time( DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC) );
dispatch_after(
               _100ms,
               dispatch_get_main_queue(),
               ^{ inject_keystrokes(); }
               );

...成功。

我想窗口在前台渲染需要一定的时间,这可能发生在一个单独的线程上,这解释了注入失败。

然而,这是一个非常丑陋的解决方案。它依赖于任意时间间隔。

以某种方式等待窗口完成前景化会更干净。

有没有办法做到这一点?

PSinject_keystrokes()用途CGEventPost(kCGHIDEventTap, someCGEvent)

PPS 参考:
-虚拟按键进入错误的应用程序
-将 NSEvent 发送到后台应用程序
- http://advinprog.blogspot.com/2008/06/so-you-want-to-post-keyboard-event-in.html

4

1 回答 1

2

isActive为我的KVO 属性添加一个观察者NSRunningApplication

for (NSRunningApplication* ra in [[NSWorkspace sharedWorkspace] runningApplications])
{
    if ([ra.bundleIdentifier isEqualToString:@"com.apple.TextEdit"])
    {
        [ra addObserver:self forKeyPath:@"isActive" options:0 context:ra];
        [ra retain];
        [ra activateWithOptions:0];
    }
}

// ...

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
    if ([keyPath isEqualToString:@"isActive"])
    {
        NSRunningApplication* ra = (NSRunningApplication*) context;
        [ra removeObserver:self forKeyPath:@"isActive"];
        [ra release];
        inject_keystrokes();
    }
}

请注意,我手动保留然后释放NSRunningApplication以使其引用保持活动状态,因为我没有将它保存在属性或 ivar 中。您必须小心,在观察者仍然连接的情况下,引用不会被丢弃。

于 2019-07-13T20:10:09.373 回答