Mac:将按键事件发送到后台窗口

问题描述:

我正在使用 Quartz事件服务将关键命令发送到应用程序,但似乎它被设计为仅发送到每个应用程序的最前面的窗口.在Windows中,您可以使用 SendKeys API .

I am using Quartz Event Services to send key commands to applications, but it appears that it was designed to only sent to the front-most window for each application. In Windows, you can send a key event to a specific window using the SendKeys API.

我知道您可以使用AppleScripts定位特定的窗口并发送关键命令,而无需将该窗口置于该应用程序的前台,但是我想知道是否有一种方法可以在C/Objective-C中以编程方式执行此操作.似乎有该功能,但是找不到任何有关API的文档.

I know that you can target specific windows using AppleScripts and send key commands without bringing that window to the foreground for that application, but wondering if there is a way to do this programmatically in C/Objective-C. Seems like the functionality is there, but cannot find any documentation for an API.

****注意**:这两个窗口都不是我的应用程序创建的窗口,可能是两个应用程序都属于同一进程*

****Note**: Neither window is a window created by my application, and it may be that both applications are owned by the same process*

示例:在下面,我无需先将蓝色窗口置于最前面,就可以将命令发送至前景窗口(上行五文本编辑器),但不能发送至蓝色背景窗口(标准文本编辑器).您可能会认为以编程方式进行的窗口切换速度很快,但是实际上却非常引人注目.我该如何做,以便在Windows之间复制击键?

Example: Below, I can send commands to the foreground window (The Up-Goer Five Text Editor), but not to the blue background window (Standard Text editor) without first bringing the blue window to the front. You would think that Window switching programmatically is fast, but it is actually very noticeable. How do I do this, as to copy keystrokes between windows?

您可以使用 CGEventPostToPSN 来实现.此示例在后台时将"Q"向下键/向上键发送到TextEdit.

You can do it with CGEventPostToPSN. This sample send 'Q' key down/key up to TextEdit, while it's in background.

// action when a button of the foreground application is clicked
// send 'Q' key down/key up to TextEdit
-(IBAction)sendQKeyEventToTextEdit:(id)sender
{
    // check if textEdit is running
     if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.TextEdit"] count])
    {
        // get TextEdit.app pid
        pid_t pid = [(NSRunningApplication*)[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.TextEdit"] objectAtIndex:0] processIdentifier];

        CGEventRef qKeyUp;
        CGEventRef qKeyDown;
        ProcessSerialNumber psn;

        // get TextEdit.app PSN
        OSStatus err = GetProcessForPID(pid, &psn);
        if (err == noErr)
        {
            // see HIToolbox/Events.h for key codes
            qKeyDown = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)0x0C, true);
            qKeyUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)0x0C, false);

            CGEventPostToPSN(&psn, qKeyDown);
            CGEventPostToPSN(&psn, qKeyUp);

            CFRelease(qKeyDown);
            CFRelease(qKeyUp);
        }
    }
}