如何在Mac Cocoa应用程序中实现快捷键输入?

13

我需要在我的Cocoa应用程序中制作一个全局热键输入框。

我知道有Shortcut Recorder,但这是一个非常古老的解决方案。它使用了已被弃用的Carbon实现的部分,如果我使用它,我就无法将我的应用程序发布到Mac App Store。

是否有任何现成的现代解决方案?有人可以告诉我如何自己制作(我不知道从哪里开始)吗?


1
并不是Carbon的所有部分都已经过时,只有GUI部分。 - jscs
3个回答

16

有一个现代化的框架叫做MASShortcut可以在OS X 10.7+中实现全局快捷键。


7
(他建造的)<- 并没有什么不对的,但应该是透明的。 - cwRichardKim
这只适用于其他应用程序中不存在的快捷方式吗?我在注册快捷方式时遇到了问题,其中一个我看到在另一个应用程序中实现。此外,如果我更改默认快捷键,则不起作用,并且非修饰键不在任何应用程序中工作,而我的应用程序正在运行。我想捕获cmd+c和alt+cmd+v。 - Cristi Băluță

15

并非所有的Carbon都已被弃用。你不能再制作纯Carbon应用程序了,但是一些API仍然存在,并且其中一些仍然是完成某些任务最简单的方法。

其中之一就是Carbon事件热键API。你当然可以使用NSEvent的事件监视器方法来筛选所有事件,但这是不必要的工作。Carbon事件热键API仍然受支持,而且更简单——你只需告诉它你想匹配哪个键以及按下该键时要调用哪个函数。而且还有像DDHotKey这样的Cocoa包装器,使其变得更加简单。

  • RegisterEventHotKey,相关的Carbon事件函数(请参见同一文档中的UnregisterEventHotKey)
  • KeyboardShortcuts,用Swift编写,包括一个SwiftUI热键记录器视图[由项目作者在编辑中添加到此答案]。

谢谢,Peter!但我知道如何注册热键。对我来说很简单。我想记录用户的按键,所以我需要在偏好设置窗口中实现类似于“热键 NSTextField”的东西。 - Victor Shcherbakov
@VictorShcherbakov:ShortcutRecorder仍然是我所知道的最好的方法。至少在主干版本中,它应该是64位兼容的。http://code.google.com/p/shortcutrecorder/ - Peter Hosey
快捷键记录器(演示应用程序)在我的Lion + Xcode4上无法工作。因此,我仍然很乐意听取除快捷键记录器之外的其他输入字段选项。 - cyphunk

13
在Mac OS X 10.6及以上版本中,您可以使用NSEvent类定义的方法+addGlobalMonitorForEventsMatchingMask:handler:+addLocalMonitorForEventsMatchingMask:handler:事件监视报告以下信息:

本地和全局事件监视器是互斥的。例如,全局监视器不会观察安装它的应用程序的事件流。本地事件监视器只观察其应用程序的事件流。要监视所有应用程序(包括“当前”应用程序)的事件,必须安装两个事件监视器。

该页面显示的代码是为本地事件监视器而编写的,但全局事件监视器的代码相似; 改变的是调用的NSEvent的方法。
_eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:
        (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyDownMask)
        handler:^(NSEvent *incomingEvent) {
    NSEvent *result = incomingEvent;
    NSWindow *targetWindowForEvent = [incomingEvent window];
    if (targetWindowForEvent != _window) {
        [self _closeAndSendAction:NO];
    } else if ([incomingEvent type] == NSKeyDown) {
        if ([incomingEvent keyCode] == 53) {
            // Escape
            [self _closeAndSendAction:NO];
            result = nil; // Don't process the event
        } else if ([incomingEvent keyCode] == 36) {
            // Enter
            [self _closeAndSendAction:YES];
            result = nil;
        }
    }
    return result;
}];

一旦不再需要监视器,您可以使用以下代码将其移除:

[NSEvent removeMonitor:_eventMonitor];

虽然这样做可以实现,但这是一种较为困难的方式。Carbon事件管理器的API仍然得到支持,而且更加简单易用,两个第三方Cocoa封装使其更加容易上手。 - Peter Hosey
9
除非该应用程序获得辅助功能的信任,否则此方法无法用于关键事件。 - Frank Krueger
全局监视器不起作用,但在本地我已经让它监听按键了。不过我想那些寻找全局热键的人会感兴趣 :)。 - H.Rabiee
2
另一个需要注意的问题是,使用此方法的某些关键命令仍会触发“Funk”错误声音。有人知道如何停止这个吗? - xandermonkey
@kiamlaluno 谢谢您清晰的回答。它有效。 - Jeba Moses

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接