Inject keyboard event into NSRunningApplication immediately after foregrounding it

天大地大妈咪最大 提交于 2020-01-30 10:50:46

问题


I am trying to bring to foreground a NSRunningApplication* instance, and inject a keyboard event.

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

... fails to inject keyboard events, but:

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(); }
               );

... succeeds.

I imagine it takes a certain amount of time for the window to render in the foreground, and maybe this happens on a separate thread, and this explains the injection failure.

However this is a very ugly solution. It relies on an arbitrary time interval.

It would be much cleaner to somehow wait for the window to complete foregrounding.

Is there any way of doing this?

PS inject_keystrokes() uses CGEventPost(kCGHIDEventTap, someCGEvent)

PPS Refs:
- Virtual keypress goes to wrong application
- Send NSEvent to background app
- http://advinprog.blogspot.com/2008/06/so-you-want-to-post-keyboard-event-in.html


回答1:


Adding an observer for the KVO property isActive on NSRunningApplication works for me.

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();
    }
}

Note that I manually retain and then release the NSRunningApplication to keep its reference alive, since I'm not keeping it in a property or ivar. You have to be careful that the reference doesn't get dropped with the observer still attached.



来源:https://stackoverflow.com/questions/57006309/inject-keyboard-event-into-nsrunningapplication-immediately-after-foregrounding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!