【问题标题】:How to monitor global modifier key state (in any application)?如何监控全局修饰键状态(在任何应用程序中)?
【发布时间】:2009-10-21 19:23:25
【问题描述】:

我在我的 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

globalHotKeyHandler 方法是为 kEventHotKeyReleased 调用的,但不是为 kEventRawKeyUp 调用的,出于某种我似乎无法理解的原因。这是我的globalHotKeyHandler 方法的样子:

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

是否还有其他需要拨打的电话或其他我忘记的电话?

N.B:乍一看,辅助设备访问似乎被禁用,但不是。所以我很无知。


更新 2:

我对@9​​87654333@ 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+,所以我现在将使用它,但欢迎使用向后兼容的解决方案。

【问题讨论】:

    标签: objective-c cocoa macos-carbon


    【解决方案1】:

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

    很遗憾,如果应用程序请求安全输入,事件点击将停止工作。例如快点。

    【讨论】:

    • 我认为有一种方法可以只监控修饰键。查看 Google 快速搜索框的源代码。它有一些代码可以检测用户何时点击命令键两次。请参阅:google.com/codesearch/…\.googlecode\.com
    • 啊,他们只是在注册以下碳事件:{ kEventClassKeyboard, kEventRawKeyModifiersChanged }
    • 我注意到 kEventRawKeyModifiersChanged 和 kEventRawKeyUp 但我似乎无法让它们为我的一生工作。请参阅我的问题中的更新。 (谢谢你的帮助!)
    • 我不确定问题可能是什么。热键会干扰吗?如果禁用热键会发生什么?另外,尝试下载 Google 的快速搜索框。代码很好。
    • 就像我在代码 cmets 中写的那样,如果我删除热键事件类型,kEventRawKeyUp 也不起作用。事件类型的顺序不会改变任何事情,看起来 kEventRawKeyUp 只是被忽略了。为什么一种类型的事件不能正常工作,而另一种则正常?
    【解决方案2】:
    OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);
    

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

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

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

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

    【讨论】:

    • 这很奇怪,因为 InstallApplicationEventHandler 会在任何地方安装我的热键,而不仅仅是在我的应用程序处于活动状态时。我可以从任何应用程序触发热键。此外,当我尝试将 InstallEventHandler 与 GetEventMonitorTarget() 一起使用时,它似乎不起作用,但我一定是做错了什么。使用 CGEventTap 代替我现在使用的有什么好处?
    • 另外,如果您只想注册一个热键,请使用the RegisterEventHotKey function,它就是为此目的而存在的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 2012-03-07
    • 2011-02-13
    • 2011-04-20
    相关资源
    最近更新 更多