我在Cocoa项目中使用了一些Carbon代码来处理来自其他应用程序的全局键事件(快捷方式)。目前我已经设置了kEventHotKeyReleased
事件处理程序,当我的应用程序处于非活动状态时,我可以成功获取热键。这会在我的应用程序中触发一些操作。
我对kEventHotKeyReleased
行为的问题是:
例如,我按下Cmd-Shift-P组合键。一旦我释放“P”键,就会触发热键事件。 我需要能够在所有键未被按下时触发事件(或手动触发)(即:Cmd和Shift键也被释放)。< / p>
监控热键很容易,但我没有看到任何用于监控个别按键的内容。如果我可以监控修改键关键状态,我将会开展业务。
有关如何执行此操作的任何提示?
提前致谢!
更新
我已尝试使用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
完全相同的方式设置它们,也不会这样做。
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+,因此我现在将使用它,但欢迎使用向后兼容的解决方案。
答案 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建议的那样。