【问题标题】:Adding a global monitor with NSEventMaskKeyDown mask does not trigger使用 NSEventMaskKeyDown 掩码添加全局监视器不会触发
【发布时间】:2018-04-08 21:55:23
【问题描述】:

我正在开发一个 MacOS 菜单栏应用程序,该应用程序需要跟踪一些全局快捷方式,以便于调整外部显示器上的显示亮度。但是,我无法让它在任何与键盘相关的事件上触发处理程序(鼠标事件工作得很好)。

我正在使用以下代码检查可访问性

NSDictionary *options = @{CFBridgingRelease(kAXTrustedCheckOptionPrompt): @YES};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);

然后,我使用以下方法添加全局事件监视器:

self.eventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent * event) {
    NSLog(@"Some event");
}];

如果我将NSEventMaskKeyDown 切换到NSEventMaskMouseMove 或其他与鼠标相关的东西,一切正常。如果我尝试NSEventMaskAny,则不会再次触发(这看起来很奇怪,因为它仍然应该在鼠标上触发)。

【问题讨论】:

    标签: macos keydown nsevent


    【解决方案1】:

    NSEventMaskMouseMove 有效但NSEventMaskKeyDown 无效这一事实清楚地表明您的应用当前没有满足跟踪关键事件所需的所有要求。 NSEventMaskMouseMove 不被视为需要特殊安全保护的事件,甚至在AXIsProcessTrustedWithOptions 返回false 时有效。

    Charles Srstkathis answer 中提到的关键事件需要更多权限:

    这不起作用的原因是因为 .keyDown 的全局监视器 事件需要比其他一些事件处理程序更多的权限, 包括有人认为这是副本的那个。这个 主要是因为全局 .keyDown 监视器可用于恶意 用途,例如键盘记录程序。所以有额外的安全性 采取措施确保我们是合法的:

    1) 您的应用需要进行代码签名。

    2) 您的应用无需启用应用沙盒,并且:

    3) 您的应用需要在安全和隐私中注册 首选项窗格,在辅助功能下。

    您需要在应用目标的“常规”窗格中启用代码签名。确保设置了“团队”和“签名证书”:

    您还必须在 Capabilities 窗格中禁用“App Sandbox”:

    请注意,为了满足第三个要求,您还需要将 Xcode 本身添加到 Accessibility 窗格中。否则,您希望能够调试您的事件监控。

    关于关键事件的另外两个提示:

    发送到NSSecureTextField(或NSSecureTextFieldCell)的关键事件被屏蔽,因此没有事件监视器可以拦截或读取它们。这是一项安全功能,可防止应用程序在输入密码时窃取密码,并且没有 API 可以绕过它。

    关于与 AppStore 兼容的全局快捷方式的说明:很明显,您无法将应用上传到已禁用沙盒的 AppStore。如果您计划通过 Mac AppStore (MAS) 分发您的应用程序,您必须使用不同的 API。 This thread 提到了一堆对 MAS 友好的解决方案。他们使用旧的Carbon 时代的RegisterEventHotKey API。 Apple promised拒绝使用它的应用程序。

    【讨论】:

    • 谢谢马克西米利安。你说的很有道理。但是,我检查了所有内容,并且所有先决条件似乎都符合要求。该应用程序经过代码签名,沙盒已关闭,应用程序和 Xcode 均已在安全和隐私/可访问性中进行检查,不寻找安全字段的输入...有趣的是,我尝试了 CGEventTapCreate(),但也失败了(不能创建水龙头)。由于缺乏文档,我有点沮丧,尤其是在失败原因方面。接下来我将尝试旧的 Carbon API(因为我有一个来自 Spectacle.app 的示例)
    • 您的应用被视为根本没有按键权限。一个新创建的具有相同代码行的 Mac 应用程序项目的行为与您所描述的完全相同(在激活代码签名并为其关闭沙盒之前):MouseMove 有效,KeyDown 无效。我会在新项目中使用您的代码对此进行调查。您还可以更改您现有的应用程序:捆绑 ID、代码签名、AppStore 权利……以便将其视为新应用程序。
    • 用一个从一开始就关闭沙盒的新应用程序进行了尝试(默认情况下它们都是代码签名的)。没运气。我准备放弃这种方法,走碳路线
    • 奇怪。 Xcode 9.3 中的一个简单的新 Cocoa 应用程序在遵循上面的三个步骤后,只有 applicationDidFinishLaunching 中的 (Swift) 行 NSEvent.addGlobalMonitorForEvents(matching: .keyDown) { print($0) } 对我有用。这就是我在发布答案之前对其进行测试的方式。您的项目是否真的默认进行了代码签名?我必须为每个新的 Cocoa 应用选择一个团队并选择“启用开发签名”。
    • 它应该......但它没有。最后,我放弃了这一点,并实施了完美满足我需求的 Carbon 解决方案。请注意,如果我尝试监听按键,这也不起作用,但是在监听我通过我的应用程序注册的热键时它起作用了。最后,我想要的只是支持系统范围的热键,我现在拥有了。
    猜你喜欢
    • 1970-01-01
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多