1

我能够通过我的窗口控制器的 keyDown: 方法成功地对键盘事件做出反应。
执行鼠标拖动时出现问题:
键盘事件似乎被延迟并且只会在鼠标启动时触发。

明确地说,我的意思是:
• 在窗口控制器的 keyDown: 方法中放置一个日志语句
• 启动您的应用程序,执行一些拖动操作(例如在 NSSlider 上)
• 在保持拖动的同时,按任意键:没有日志到控制台。
• 释放拖动:出现日志,是的……</p>

我拖动的控件是一个自定义的 NSSlider。
我已经使用“鼠标跟踪循环”方法实现了拖动机制。据我了解,在拖动时,NSApplication 的主运行循环模式正在切换到 NSEventTrackingRunLoopMode,从而限制传入事件。

所以,我只是在我的跟踪循环中添加了 NSKeyDownMask 和 NSKeyUpMask,当遇到时,相应地调用 self.nextResponder keyDown/up: 方法。对于这个特定的自定义子类,我的问题得到了解决。

但是 Cocoa 的原生控件呢?我无法编写该异常...

我曾希望 NSEvent 的“addLocalMonitorForEventsMatchingMask:”方法,但可惜的是,doc 说:“不会为嵌套事件跟踪循环所消耗的事件调用,例如控件跟踪、菜单跟踪或窗口拖动”。

那么,不管应用程序的运行循环模式如何,是否有一个简单的解决方案来接收键盘事件?

4

1 回答 1

2

正如您在NSEventclass'的文档中发现的那样addGlobalMonitorForEventsMatchingMask:handler:,此限制是设计使然。

但是,您可以通过使用 IOKit 框架(特别是 IOHID 部分)来接收低级设备事件/中断来解决它。我最近不得不这样做以在鼠标拖动期间跟踪一些特定的按键。

基本要点是创建一个 IOHID 管理器IOHIDManagerCreate(),然后将设备类型添加到它应该“监视”的管理器,IOHIDManagerSetDeviceMatchingMultiple()通过管理器注册回调,为管理器IOHIDManagerRegisterInputValueCallback()安排适当的运行循环IOHIDManagerScheduleWithRunLoop(),最后用 . 打开管理器IOHIDManagerOpen()

要在鼠标拖动期间获取这些低级事件,请在单独的线程中执行此设置。在为 manager 调度 run-loop 时,使用CFRunLoopGetCurrent()获取当前线程的 run-loop,并调用CFRunLoopRun()after IOHIDManagerOpen()

Apple 提供的本指南以及Stack Overflow 上的问答可帮助您入门。

于 2014-03-27T23:31:48.090 回答