11

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

我的行为问题kEventHotKeyReleased是:

比如说我按下 Cmd-Shift-P 组合键。只要我松开“P”键,就会触发热键事件。我需要能够在所有键都未按下时触发事件(或手动触发它) (即:Cmd 和 Shift 键也被释放)。

监视热键很容易,但我没有看到监视单个击键的情况。如果我可以监控修饰键状态,我会做生意。

关于如何做到这一点的任何提示?

提前致谢!


更新:

我尝试过使用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!");
}

是否需要打一个额外的电话或我忘记了其他什么?

注意:乍一看,似乎辅助设备的访问已被禁用,但事实并非如此。所以我很无知。


更新 2:

我对CGEventTapLeibowitzn 提出的建议进行了一些调查,并提出了这个设置:

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不起作用......


注意:另外请注意,我在 Tiger 上进行开发的目标是尽可能多地支持新旧版本的操作系统。CGEventTap 仅 10.4+,所以我现在将使用它,但欢迎使用向后兼容的解决方案。

4

2 回答 2

3

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

不幸的是,如果应用程序请求安全输入,事件点击将停止工作。例如速腾。

于 2009-10-21T20:18:42.657 回答
1
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);

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

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

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

不过,现在我只使用 CGEventTaps,正如 Leibowitzn 建议的那样。

于 2009-10-22T06:45:55.473 回答