我正在为Mac OSX的打字器应用程序进行打字,该应用程序需要将键击向它转发到它,即使该应用程序不重视。

有没有办法通过NSDistributedNotificationCenter将系统转发到该应用程序?我已经谷歌搜索了自己很愚蠢的,但是找不到答案...

编辑: 下面的示例代码.

感谢@nsgod将我指向正确的方向 - 我最终添加了一个 全球事件监视器 使用该方法 addGlobalMonitorForEventsMatchingMask:handler:, ,工作得很好。为了完整,我的实施看起来像这样:

// register for keys throughout the device...
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                       handler:^(NSEvent *event){

    NSString *chars = [[event characters] lowercaseString];
    unichar character = [chars characterAtIndex:0];

    NSLog(@"keydown globally! Which key? This key: %c", character);

}];

对我来说,棘手的部分是使用块,所以我会提供一些描述,以防万一它可以帮助任何人:

关于上述代码的要注意的是全部 一个方法调用 在nsevent上。该块是作为参数提供的,直接 功能。您可以想到这是一个内联代表方法。仅仅因为这花了一段时间才为我沉没,我将在这里逐步进行逐步进行:

[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask

这是没有问题的。您正在调用NSEVENT上的类方法,并告诉您您要监视哪个事件,在这种情况下为NSKeyDownMask。一个 支持事件类型的面具列表 可以被找寻到 这里.

现在,我们来到了棘手的部分:Handler,期望一个障碍:

handler:^(NSEvent *event){

我花了一些编译错误才能正确解决这个问题,但是(谢谢Apple)它们是非常建设性的错误消息。首先要注意的是克拉 ^。这标志着块的开始。之后,在括号内,

NSEvent *event

它声明您将在块中使用的变量来捕获事件。你可以称呼它

NSEvent *someCustomNameForAnEvent

没关系,您只是在块中使用该名称。然后,这几乎就是它。确保关闭卷发支架,然后支架完成方法调用:

}];

你完成了!这确实是一个“单线”。在应用程序中执行此调用的何处都没关系 - 我在AppDelegate的ApplicationDidfinishLaunching方法中进行操作。然后,在块中,您可以在应用程序中调用其他方法。

有帮助吗?

解决方案

如果您对OS X 10.6+的最低要求还可以,并且可以使用“仅阅读”访问事件的访问,则可以在可可中安装全局事件监视器:可可活动处理指南:监视事件.

如果您需要支持OS X 10.5及更早的OS X,并且仅阅读访问是可以的,并且不介意与Carbon Event Manager合作,则基本上可以使用碳等于 GetEventMonitorTarget(). 。 (虽然您很难找到有关该方法的任何(官方)文档)。我相信,该API首先在OS X 10.3中使用。

如果您需要对事件流进行阅读 - 写入访问,则需要查看稍低的API,该API是ApplicationsEvceServices> CoreGraphics的一部分:CGEventTapCreate() 和朋友。这首先在10.4中提供。

请注意,所有3种方法都将要求用户在系统首选项中启用启用辅助设备的访问权限>通用访问偏好窗格(至少对于关键事件)。

其他提示

我正在发布适合我案件的代码。

应用程序启动后,我将添加全球活动处理程序。我的快捷方式使CTRL+ALT+CMD+T打开我的应用程序。

- (void) applicationWillFinishLaunching:(NSNotification *)aNotification
{
    // Register global key handler, passing a block as a callback function
    [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                           handler:^(NSEvent *event){

        // Activate app when pressing cmd+ctrl+alt+T
        if([event modifierFlags] == 1835305 && [[event charactersIgnoringModifiers] compare:@"t"] == 0) {

              [NSApp activateIgnoringOtherApps:YES];
        }
    }];

}

我发现的问题是,另一个应用程序在全球登记的任何密钥都不会被关注……或者至少在我的情况下,也许我做错了什么。

如果您的程序需要显示所有键,例如“ Command-Shift-3”,则不会看到它显示出来...因为它被OS占用。

还是有人弄清楚了?我很想知道...

正如NSGOD已经指出的那样,您也可以使用CoreGraphics。

在您的班级中(例如,Init):

CFRunLoopRef runloop = (CFRunLoopRef)CFRunLoopGetCurrent();

CGEventMask interestedEvents = NSKeyDown;
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 
                                        0, interestedEvents, myCGEventCallback, self);
// by passing self as last argument, you can later send events to this class instance

CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, 
                                                           eventTap, 0);
CFRunLoopAddSource((CFRunLoopRef)runloop, source, kCFRunLoopCommonModes);
CFRunLoopRun();

班级外,但在同一.m文件中:

CGEventRef myCGEventCallback(CGEventTapProxy proxy, 
                             CGEventType type, 
                             CGEventRef event, 
                             void *refcon)
{

    if(type == NX_KEYDOWN)
    {
       // we convert our event into plain unicode
       UniChar myUnichar[2];
       UniCharCount actualLength;
       UniCharCount outputLength = 1;
       CGEventKeyboardGetUnicodeString(event, outputLength, &actualLength, myUnichar);

       // do something with the key

       NSLog(@"Character: %c", *myUnichar);
       NSLog(@"Int Value: %i", *myUnichar);

       // you can now also call your class instance with refcon
       [(id)refcon sendUniChar:*myUnichar];
   }

   // send event to next application
   return event;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top