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

For*_*orm 11 cocoa macos-carbon objective-c

我在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
Run Code Online (Sandbox Code Playgroud)

要求该globalHotKeyHandler方法kEventHotKeyReleased,但kEventRawKeyUp由于某种原因我似乎无法掌握.这是我的globalHotKeyHandler方法的样子:

OSStatus globalHotkeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) {
    NSLog(@"Something happened!");
}
Run Code Online (Sandbox Code Playgroud)

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

注意:乍一看,似乎可以禁用Access for Assistive Devices,但事实并非如此.所以我很无能为力.


更新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);
Run Code Online (Sandbox Code Playgroud)

...和回调:

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

正如你所看到的那样,我正在使用它kCGEventKeyUp作为事件点击的掩码,但不知怎的,我正在接收鼠标按下事件 ??!??


更新3:

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

CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventKeyUp),&keyUpCallback,NULL);
Run Code Online (Sandbox Code Playgroud)

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


更新4:

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

要拦截修改键,请使用kCGEventFlagsChanged:

CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventFlagsChanged),&callbackFunction,NULL);
Run Code Online (Sandbox Code Playgroud)

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


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

Lei*_*tzn 3

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

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