macOS应用程序:处理绑定到全局键盘快捷键的组合键
在某些应用程序中,应用程序直接处理键盘快捷键是有意义的,否则这些快捷键会绑定到系统范围的组合。例如⌘-空间(通常为聚光灯)或⌘-选项卡(通常为应用程序切换器)。这适用于各种Mac应用,如VMWare Fusion、苹果自己的屏幕共享和远程桌面客户端(分别将事件转发到VM或服务器,而不是本地处理),以及应用商店中的一些类似第三方应用 我们希望在我们正在开发的应用程序中实现这样一种模式,但却很难找到解决方法。我应该指出,所讨论的应用程序是一个普通的前台应用程序,是沙盒的,任何解决方案都必须遵守应用程序商店规则。商店中的其他应用程序可以做到这一点,这意味着这必须是可能的 明确地说,我们希望:macOS应用程序:处理绑定到全局键盘快捷键的组合键,macos,cocoa,keyboard-shortcuts,keyboard-events,nsevent,Macos,Cocoa,Keyboard Shortcuts,Keyboard Events,Nsevent,在某些应用程序中,应用程序直接处理键盘快捷键是有意义的,否则这些快捷键会绑定到系统范围的组合。例如⌘-空间(通常为聚光灯)或⌘-选项卡(通常为应用程序切换器)。这适用于各种Mac应用,如VMWare Fusion、苹果自己的屏幕共享和远程桌面客户端(分别将事件转发到VM或服务器,而不是本地处理),以及应用商店中的一些类似第三方应用 我们希望在我们正在开发的应用程序中实现这样一种模式,但却很难找到解决方法。我应该指出,所讨论的应用程序是一个普通的前台应用程序,是沙盒的,任何解决方案都必须遵守应用程
- 检测并处理所有按键,包括绑定到全局快捷方式的按键
- 防止全局快捷方式触发其全局绑定效果
NSApplication
的sendEvent:
方法是基于修改器标志检测潜在快捷方式的方法,将它们发送到窗口,如果失败,则发送到菜单栏。没有明确说明全局绑定的快捷方式会发生什么情况
我尝试了子类化NSApplication
并重写sendEvent:
。无论我是否将所有事件传递给超类实现,或者如果我在按下时说“filter modifier key events”⌘-空格时,我接收按下和释放命令的事件(⌘) 键,但不是空格键。聚光灯用户界面总是弹出
我没有从苹果或其他公司找到太多关于非应用程序子类化及其早期事件处理的信息。我似乎无法找出全局快捷方式是在什么级别被检测和处理的
有人能给我指一下正确的方向吗
不起作用的可能解决方案:
我在其他堆栈溢出帖子中看到过一些建议,但这些建议不适用于我见过的其他应用程序,这些应用程序会这样做(并且会破坏应用程序商店规则):
- 可访问性API(需要特殊许可)
- 事件点击/挂钩(需要以root身份运行)
NSevent
的addGlobalMonitorForEventsMatchingMask:handler:
同时并没有阻止全局快捷方式处理程序为这些事件触发,所以我甚至没有费心去尝试它。好的,Cocoa事件方法和Quartz事件抽头都被取消了,因为它们要么需要根或可访问性访问权限,要么没有捕获eve在被告席之前,他已经被逮捕了
Carbon的PushSymbolicChotKeyMode
被取消,因为根据文档,它需要可访问性
Carbon'sRegisterEventThotKey
可能是因为苹果公司似乎不允许它(请参阅我在问题评论中的链接)。然而,即使如此,我已经测试过了,你也不能用它来捕获Command+Tab
我快速证明了这一概念的有效性,但YMMV:
- 在此实现
示例类。您需要链接IOKitKeyboardWatcher
- 添加硬件-USB(com.apple.security.device.USB)沙盒权限。这是必要的,因为KeyboardWatcher使用HID捕捉按键
将为您提供所按下的键。您可以根据自己的需要对其进行修改Handle\u DeviceEventCallback
- 使用
阻止任务切换程序和聚光灯。您需要链接碳setsystemimode
setsystemimode(kUIModeContentSuppressed,kUIOptionDisableProcessSwitch);
请注意,这仅在应用程序位于前台时有效(可能是您想要的)。我使用跟踪矩形在我的视图上设置了此选项,因此它仅在鼠标位于我的视图上时生效(如在Remotix中):
Remotix似乎将Carbon和IOKit联系在一起,但我看不出他们是否有USB权限(我尝试了演示,而不是应用商店版本)。他们可能正在做类似的事情
实现这一点的正常方法是安装Quartz事件点击。但是,要接收针对其他应用程序的事件,您需要(如您所说)成为root用户,或者为您的应用程序启用可访问性访问 似乎无法使用具有当前沙箱规则的事件点击。这在中得到确认。该链接仅为登录,但引用线程中的内容: 是否有机会通过阻止启动iTunes来处理来自媒体键的事件。在沙盒之前,可以通过创建CGEventTap来处理事件,但现在沙盒使用hid控件来拒绝 不,这在应用程序沙盒中当前不可能实现 我不确定是否有其他方法可以做到这一点;我想知道应用商店中的哪些应用程序可以做到这一点
VMWare Fusion显然不是沙盒,苹果自己的应用程序也不受规则约束。请记住,沙盒只在2012年推出后添加的新应用程序上强制执行。在该日期之前添加的应用程序没有强制执行沙盒。请看这一点。我早就解决了这个问题,但我只是注意到我从未在这里发布过。答案是这不是一个公共API,但有许多Mac App Store应用程序通过混淆函数名并动态查找来使用它。苹果似乎不介意。该API使用起来非常简单,而且有大量的开放示例源代码浮动。
- (void)viewDidLoad {
[super viewDidLoad];
NSTrackingArea* trackingArea = [[NSTrackingArea alloc] initWithRect:[self.view bounds] options: (NSTrackingMouseEnteredAndExited |
NSTrackingActiveAlways) owner:self userInfo:nil];
[self.view addTrackingArea:trackingArea];
}
- (void) mouseEntered:(NSEvent*)theEvent {
SetSystemUIMode(kUIModeContentSuppressed, kUIOptionDisableProcessSwitch);
}
- (void) mouseExited:(NSEvent*)theEvent {
SetSystemUIMode(kUIModeNormal, 0);
}