我在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建议的那样。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top