可可:拖动时不会触发键盘事件(NSEventTrackingRunLoopMode) [英] Cocoa: No keyboard events will fire while dragging (NSEventTrackingRunLoopMode)

查看:168
本文介绍了可可:拖动时不会触发键盘事件(NSEventTrackingRunLoopMode)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以通过我的窗口控件的keyDown:方法成功地对键盘事件作出反应。

执行鼠标拖动时出现问题:

键盘事件似乎被延迟,只会在鼠标上起火。要清楚,我的意思是:

•在你的窗口控制器的keyDown:方法中放置一个日志语句

•启动您的应用程序,执行一些拖动操作(例如NSSlider)

•同时保持拖动,按任意键:无任何日志到控制台。

•释放拖动:日志出现,yay ...



我拖动的控件是一个自定义NSSlider。

我已经实现了拖动机制,使用鼠标跟踪循环方法
为了理解,拖动时,NSApplication的主运行环路模式正在切换到NSEventTrackingRunLoopMode,从而限制传入事件。



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



但是可可的本机控件呢?我不能编写这个例外...



我曾经希望NSEvent的addLocalMonitorForEventsMatchingMask:方法
但唉,说:不会被调用对于由嵌套事件跟踪循环(如控制跟踪,菜单跟踪或窗口拖动)消耗的事件。



所以,没有一个直接的解决方案来接收键盘事件无论应用程序的runloop模式如何?

解决方案

正如您在 NSEvent class' addGlobalMonitorForEventsMatchingMask:handler:,这个限制是设计的。



但是,你可以使用IOKit框架(特别是IOHID部分)来接收低级别的设备事件/中断。我最近只需要在鼠标拖动期间跟踪一些特定的按键。



基本要点是使用 IOHIDManagerCreate创建一个IOHID管理器),然后将设备类型添加到管理器中,该应用程序应该使用 IOHIDManagerSetDeviceMatchingMultiple()监控注册一个回调经理通过 IOHIDManagerRegisterInputValueCallback(),为 IOHIDManagerScheduleWithRunLoop()为管理员安排正确的运行循环,最后打开经理与 IOHIDManagerOpen()



要在鼠标拖动期间获取这些低级别的事件,请在单独的线程。在调度管理器的运行循环时,使用 CFRunLoopGetCurrent()获取当前线程的运行循环,并调用 CFRunLoopRun() code> after IOHIDManagerOpen()



本指南来自Apple 可以帮助您开始使用这个问题在这里Stack Overflow


I am successfully able to react to keyboard events through my window controller's keyDown: method.
The problem arises while performing a mouse drag:
Keyboard events seem to be delayed and will only fire on mouse up.

To be clear, what I mean is:
• place a log statement in you window controller's keyDown: method
• launch your app, perform some drag operation (on a NSSlider for ex.)
• while maintaining the drag, press any key: nothing logs to the console.
• release drag : logs appear, yay…

The control i am dragging is a custom NSSlider.
I have implemented the dragging mechanism using a 'Mouse-Tracking Loop' Approach. for what I understand, when dragging, NSApplication's main run loop mode is being switched to NSEventTrackingRunLoopMode, thus restricting incoming events.

So, i simply added NSKeyDownMask & NSKeyUpMask in my tracking loop and when encoutered, called self.nextResponder keyDown/up: method accordingly. My problem is solved for this particular custom subclass.

But what about cocoa's native controls ? I can't code that exception...

I had hoped for NSEvent's "addLocalMonitorForEventsMatchingMask:" method but alas, says doc : "will not be called for events that are consumed by nested event-tracking loops such as control tracking, menu tracking, or window dragging".

So, isn't there a straightforward solution to receive keyboard events regardless of the app's runloop mode ?

解决方案

As you found in the documentation for the NSEvent class' addGlobalMonitorForEventsMatchingMask:handler:, this limitation is by design.

However, you can work around it by using the IOKit framework (specifically the IOHID portions) to receive low level device events/interrupts. I just had to do this recently for tracking some specific keypresses during mouse-drags.

The basic gist is to create an IOHID manager with IOHIDManagerCreate(), then add the type(s) of devices to the manager that it should "monitor" with IOHIDManagerSetDeviceMatchingMultiple(), register a callback with the manager via IOHIDManagerRegisterInputValueCallback(), schedule the proper run-loop for the manager with IOHIDManagerScheduleWithRunLoop(), and finally open the manager with IOHIDManagerOpen().

To get these low level events during mouse-drags, perform this setup in a separate thread. When scheduling the run-loop for the manager, use CFRunLoopGetCurrent() to get the run loop for the current thread, and call CFRunLoopRun() after IOHIDManagerOpen().

This guide from Apple can help you get started, along with this Q&A here on Stack Overflow.

这篇关于可可:拖动时不会触发键盘事件(NSEventTrackingRunLoopMode)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆