【问题标题】:Cocoa: No keyboard events will fire while dragging (NSEventTrackingRunLoopMode)Cocoa:拖动时不会触发键盘事件(NSEventTrackingRunLoopMode)
【发布时间】:2013-08-05 13:10:18
【问题描述】:

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

要清楚,我的意思是:
• 在窗口控制器的 keyDown 中放置一条日志语句:方法
• 启动您的应用程序,执行一些拖动操作(例如在 NSSlider 上)
• 在保持拖动的同时,按任意键:控制台不会记录任何内容。
• 释放拖动:出现日志,是的……

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

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

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

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

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

【问题讨论】:

  • 我有一个类似的问题,当我使用“鼠标跟踪循环”方法时,计时器似乎没有触发——无论我将计时器添加到哪种运行循环模式。当下拉顶级菜单时,计时器会触发...... - 那么这方面有什么进展吗?

标签: objective-c cocoa event-handling nsrunloop


【解决方案1】:

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

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

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

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

This guide from Apple 和this Q&A here on Stack Overflow 可以帮助您入门。

【讨论】:

  • 我一直在努力让 IOHIDManager 与全屏 CGL 应用程序一起工作。我没有从所有示例中意识到您必须提供运行循环......直到我读到您的答案才意识到运行循环可能应该在另一个线程上。非常感谢!
  • 对如何使用 Swift 实现它有什么建议吗?我有一个可以通过这个解决方案解决的问题 - stackoverflow.com/questions/53631958/…
猜你喜欢
  • 2011-03-06
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-10-26
  • 2014-05-25
  • 2013-09-22
  • 1970-01-01
相关资源
最近更新 更多