如何监控全局修饰键状态(在任何应用程序中)?

时间:2009-10-21 19:23:25

标签: objective-c cocoa macos-carbon

我在Cocoa项目中使用了一些Carbon代码来处理来自其他应用程序的全局键事件(快捷方式)。目前我已经设置了kEventHotKeyReleased事件处理程序,当我的应用程序处于非活动状态时,我可以成功获取热键。这会在我的应用程序中触发一些操作。

我对kEventHotKeyReleased行为的问题是:

例如,我按下Cmd-Shift-P组合键。一旦我释放“P”键,就会触发热键事件。 我需要能够在所有键未被按下时触发事件(或手动触发)(即:Cmd和Shift键也被释放)。< / p>

监控热键很容易,但我没有看到任何用于监控个别按键的内容。如果我可以监控修改键关键状态,我将会开展业务。

有关如何执行此操作的任何提示?

提前致谢!


更新

我已尝试使用kEventRawKeyUpkEventRawKeyModifiersChanged,但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 完全相同的方式设置它们,也不会这样做。

globalHotKeyHandler

kEventHotKeyReleased调用kEventRawKeyUp方法,但由于某些原因我无法理解globalHotKeyHandler。这是我的OSStatus globalHotkeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) { NSLog(@"Something happened!"); } 方法的样子:

CGEventTap

是否需要进行额外的通话或忘记其他事情?

N.B:乍一看,似乎可以禁用Access for Assistive Devices但 它不是 。所以我很无能为力。


更新2:

我对CFMachPortRef keyUpEventTap = CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,kCGEventKeyUp,&keyUpCallback,NULL); CFRunLoopSourceRef keyUpRunLoopSourceRef = CFMachPortCreateRunLoopSource(NULL, keyUpEventTap, 0); CFRelease(keyUpEventTap); CFRunLoopAddSource(CFRunLoopGetCurrent(), keyUpRunLoopSourceRef, kCFRunLoopDefaultMode); CFRelease(keyUpRunLoopSourceRef); Leibowitzn的建议进行了调查,我想出了这个设置:

CGEventRef keyUpCallback (CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    NSLog(@"KeyUp event tapped!");
    return event;
}

...和回调:

kCGEventKeyUp

正如您所看到的,我正在使用CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventKeyUp),&keyUpCallback,NULL); 作为事件点击的掩码但不知何故我正在接收 鼠标按下事件 ??! ?


更新3:

好吧忘记了,我忽略了文档中对于此参数使用CGEventMaskBit(kCGEventKeyUp)的行,所以正确的调用是:

kCGEventFlagsChanged

我仍然遇到问题:修改键不会触发kCGEventKeyUp ......


更新4:

好的,再次忘记了......我今天问他们5分钟后我一定会回答我自己的问题吧!

要拦截修饰键,请使用CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventFlagsChanged),&callbackFunction,NULL);

kEventRawKeyUp

所以本质上我得到了键和修饰键关键状态检测功能,但我仍然有兴趣知道为什么 {{1}}不起作用。 ..


N.B:另请注意,我正在开发Tiger,目标是尽可能多地支持新版本和旧版本的操作系统。 CGEventTap仅为10.4+,因此我现在将使用它,但欢迎使用向后兼容的解决方案。

2 个答案:

答案 0 :(得分:3)

一种选择是使用EventTaps。这使您可以监视所有键盘事件。看到: http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate

不幸的是,如果应用程序请求安全输入,事件抽头将停止工作。例如Quicken。

答案 1 :(得分:1)

OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);

这不是全球性的。这仅在您自己的应用程序处于活动状态时安装处理程序,并且(我相信)在Carbon事件管理器自己的事件过滤器之后安装。

您需要使用InstallEventHandler,它将事件目标作为其第一个参数(InstallApplicationEventHandler是一个传递应用程序事件目标的宏)。

对于应用程序未处于活动状态时发生的事件,您需要的目标是GetEventMonitorTarget()。对于在应用程序 处于活动状态时发生的事件,您需要的目标是GetEventDispatcherTarget()。要捕获事件,无论哪个应用程序处于活动状态,请在两个目标上安装处理程序。

如今,我只是使用CGEventTaps,正如Leibowitzn建议的那样。