addGlobalMonitorForEventsMatchingMask无法正常工作

时间:2014-08-26 00:37:28

标签: macos cocoa

我无法获得启用辅助功能的应用程序(开发案例中的XCode)来捕获全局keyDown事件。我已经看到了很多代码示例,如下所示,但这对我来说不适用于10.9.4。

#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>

// 10.9+ only, see this url for compatibility:
// http://stackoverflow.com/questions/17693408/enable-access-for-assistive-devices-programmatically-on-10-9
BOOL checkAccessibility()
{
  NSDictionary* opts = @{(__bridge id)kAXTrustedCheckOptionPrompt: @YES};
  return AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)opts);
}

int main(int argc, const char * argv[])
{
  @autoreleasepool {
    if (checkAccessibility()) {
        NSLog(@"Accessibility Enabled");
    }
    else {
        NSLog(@"Accessibility Disabled");
    }

    NSLog(@"registering keydown mask");
    [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                           handler:^(NSEvent *event){
                                               NSLog(@"keydown: %@", event.characters);

                                           }];

      NSLog(@"entering run loop.");
      [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

收到的输出是:

2014-08-25 17:26:36.054 test[64725:303] Accessibility Enabled
2014-08-25 17:26:36.055 test[64725:303] registering keydown mask
2014-08-25 17:26:36.067 test[64725:303] entering run loop.

一旦到了这里,就不会发生其他日志记录,无论我点击哪个键或者点击它时应用程序有什么焦点。

FWIW,我正在尝试写一个辅助应用程序,而不是键盘记录器或其他邪恶的东西。我已经查看了这个问题的其他实例,但它们似乎要么处理1)应用程序没有辅助启用或2)没有接收某些需要CGEvents接收的“特殊”命令键。我没有看到任何键,即使是简单的键(它已经通过我输入这个帖子而没有记录任何内容)。 TIA!

1 个答案:

答案 0 :(得分:11)

所以,感谢Ken Thomases的上述问题,我能够弄清楚如何做到这一点。关键细节是我使用命令行应用程序模板(我不需要UI,所以我试图保持最小化)。给我的消息,但事后来看,只是创建一个运行循环不会创建一个事件循环。为了在命令行应用程序中复制事件循环的创建,必须使用典型的可可应用程序的更多内容。首先,您必须有一个实现NSApplicationDelegate协议的类,该委托将是应用程序代码所在的位置,主要方法是简单地执行以下操作:

#import <Foundation/Foundation.h>
#include "AppDelegate.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        AppDelegate *delegate = [[AppDelegate alloc] init];

        NSApplication * application = [NSApplication sharedApplication];
        [application setDelegate:delegate];
        [NSApp run];
    }
}

这是一个无笔尖,无菜单的应用程序,就像通​​常的命令行应用程序模板一样,但由于[NSApp run]调用,它确实有一个真正的事件循环。然后我在上面的main方法中使用的应用程序代码移动到app delegate:

#import "AppDelegate.h"

@implementation AppDelegate

// 10.9+ only, see this url for compatibility:
// http://stackoverflow.com/questions/17693408/enable-access-for-assistive-devices-programmatically-on-10-9
BOOL checkAccessibility()
{
    NSDictionary* opts = @{(__bridge id)kAXTrustedCheckOptionPrompt: @YES};
    return AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)opts);
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    if (checkAccessibility()) {
        NSLog(@"Accessibility Enabled");
    }
    else {
        NSLog(@"Accessibility Disabled");
    }

    NSLog(@"registering keydown mask");
    [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                           handler:^(NSEvent *event){
                                               NSLog(@"keydown: %@", event.characters);

                                           }];
}

@end

为了完整和未来的读者,头文件看起来像这样:

#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;

@end