如何监控全局修饰键状态(在任何应用程序中)?
-
05-07-2019 - |
题
我在Cocoa项目中使用了一些Carbon代码来处理来自其他应用程序的全局键事件(快捷方式)。目前我已经设置了 kEventHotKeyReleased
事件处理程序,当我的应用程序处于非活动状态时,我可以成功获取热键。这会在我的应用程序中触发一些操作。
我对 kEventHotKeyReleased
行为的问题是:
例如,我按下Cmd-Shift-P组合键。一旦我释放“P”,键触发热键事件。 我需要能够在所有键未被按下时触发事件(或手动触发)(即:Cmd和Shift键也被释放)。
监控热键很容易,但我没有看到任何用于监控个别按键的内容。如果我可以监控修改键关键状态,我将会开展业务。
有关如何执行此操作的任何提示?
提前致谢!
<强>更新强>
我尝试过使用 kEventRawKeyUp
和 kEventRawKeyModifiersChanged
,但是当 kEventHotKeyReleased
工作时,即使我将它们设置为精确与 kEventHotKeyReleased
相同。
EventTypeSpec eventTypes[] = {{kEventClassKeyboard, kEventHotKeyReleased}, {kEventClassKeyboard, kEventRawKeyUp}};
// Changing the order in the list does not help, nor does removing kEventHotKeyReleased
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);
// err == noErr after this line
为 kEventHotKeyReleased
调用 globalHotKeyHandler
方法,但由于某些原因我无法理解 kEventRawKeyUp
。这是我的 globalHotKeyHandler
方法的样子:
OSStatus globalHotkeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) {
NSLog(@"Something happened!");
}
是否需要进行额外的通话或忘记其他事情?
N.B:乍一看,似乎可以禁用Access for Assistive Devices但 它不是 。所以我很无能为力。
更新2:
我调查了一下 CGEventTap
Leibowitzn建议,我想出了这个设置:
CFMachPortRef keyUpEventTap = CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,kCGEventKeyUp,&keyUpCallback,NULL);
CFRunLoopSourceRef keyUpRunLoopSourceRef = CFMachPortCreateRunLoopSource(NULL, keyUpEventTap, 0);
CFRelease(keyUpEventTap);
CFRunLoopAddSource(CFRunLoopGetCurrent(), keyUpRunLoopSourceRef, kCFRunLoopDefaultMode);
CFRelease(keyUpRunLoopSourceRef);
...和回调:
CGEventRef keyUpCallback (CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
NSLog(@"KeyUp event tapped!");
return event;
}
正如您所看到的,我正在使用 kCGEventKeyUp
作为事件点按的掩码,但不知怎的,我正在接收 鼠标按下事件 ? ?!??
更新3:
好吧忘记了,我忽略了文档中对于此参数使用CGEventMaskBit(kCGEventKeyUp)的行,所以正确的调用是:
CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventKeyUp),&keyUpCallback,NULL);
我仍然遇到问题:修改键不会触发kCGEventKeyUp ......
更新4:
好的,再次忘记了......我今天问他们5分钟后我一定会回答我自己的问题吧!
要拦截修饰键,请使用 kCGEventFlagsChanged
:
CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventFlagsChanged),&callbackFunction,NULL);
所以本质上我得到了键和修饰键关键状态检测功能,但是我仍然有兴趣知道 kEventRawKeyUp
无法正常工作强> ...
N.B:另请注意,我正在开发Tiger,目标是尽可能多地支持新版本和旧版本的操作系统。 CGEventTap仅为10.4+,因此我现在将使用它,但欢迎使用向后兼容的解决方案。
解决方案
一种选择是使用EventTaps。这使您可以监视所有键盘事件。看到: http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate
不幸的是,如果应用程序请求安全输入,事件抽头将停止工作。例如Quicken。
其他提示
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);
这不是全球性的。这仅在您自己的应用程序处于活动状态时安装处理程序,并且(我相信)在Carbon事件管理器自己的事件过滤器之后安装。
您需要使用 InstallEventHandler
,它将事件目标作为其第一个参数( InstallApplicationEventHandler
是一个传递应用程序事件目标的宏)。
对于应用程序未处于活动状态时发生的事件,您需要的目标是 GetEventMonitorTarget()
。对于在应用程序 处于活动状态时发生的事件,您需要的目标是 GetEventDispatcherTarget()
。要捕获事件,无论哪个应用程序处于活动状态,请在两个目标上安装处理程序。
如今,我只是使用CGEventTaps,正如Leibowitzn建议的那样。