无法使用 CGEventTap 阻止大写锁定

发布于 2024-09-03 07:06:06 字数 1625 浏览 3 评论 0原文

我正在使用 Quartz CGEventTap 尝试全局拦截大写锁定按键并阻止它们(让它们做一些有用的事情)。我成功检测到大写锁定按键,但到目前为止无法阻止它们。我的代码(源自这个 stackoverflow答案)是像这样的事情:

eventTap = CGEventTapCreate(kCGHIDEventTap,
                            kCGTailAppendEventTap, 
                            kCGEventTapOptionDefault, 
                            eventMask,
                            myCGEventCallback,
                            &oldFlags);

runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef theEvent, void *refcon)
{
    CGEventFlags *oldFlags = (CGEventFlags *)refcon; 

    switch (type)
    {
        case kCGEventFlagsChanged:
        {
            CGEventFlags newFlags = CGEventGetFlags(theEvent);
            CGEventFlags changedFlags = *oldFlags ^ newFlags; 
            *oldFlags = newFlags;

            if (changedFlags == 65536)
            {
                NSLog(@"Capslock pressed. Let's not return the event");
                return NULL;
            }
            break;
        }
        default:
            break;
    }

    NSLog(@"Different modifier than capslock. Returning the event");
    return theEvent;
}

如果我理解正确,返回 NULL 应该有效地阻止按键传播。事实上,它也适用于“正常”的 keyup 和 -down 事件。然而,大写锁定无论如何都会切换。有什么想法吗?我做出了错误的假设吗?和/或我怎样才能以不同的方式做事来实现我的目标?

谢谢,

托尔

I'm using Quartz CGEventTap in an attempt to globally intercept capslock presses and block them (to have them do something useful instead). I succesfully detect capslock presses but have so far been unable to block them. My code (originating from this stackoverflow answer) is something like this:

eventTap = CGEventTapCreate(kCGHIDEventTap,
                            kCGTailAppendEventTap, 
                            kCGEventTapOptionDefault, 
                            eventMask,
                            myCGEventCallback,
                            &oldFlags);

runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef theEvent, void *refcon)
{
    CGEventFlags *oldFlags = (CGEventFlags *)refcon; 

    switch (type)
    {
        case kCGEventFlagsChanged:
        {
            CGEventFlags newFlags = CGEventGetFlags(theEvent);
            CGEventFlags changedFlags = *oldFlags ^ newFlags; 
            *oldFlags = newFlags;

            if (changedFlags == 65536)
            {
                NSLog(@"Capslock pressed. Let's not return the event");
                return NULL;
            }
            break;
        }
        default:
            break;
    }

    NSLog(@"Different modifier than capslock. Returning the event");
    return theEvent;
}

If I understand correctly returning NULL should effectively block the keypress from propagating. Indeed it also does for "normal" keyup and -down events. However capslock toggles regardless. Any ideas why that is? Am I making incorrect assumptions? And/or how can I do things differently to achieve my goal?

Thanks,

Thor

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

微暖i 2024-09-10 07:06:06

你不能像这样阻止大写锁定。大写锁定是一种情况,由键盘驱动程序处理,而不是由 Window Server 或单个应用程序处理。按键事件在 OS X 中传播如下:

键盘驱动程序 ->窗口服务器->用户会话->活动应用程序

在每个级别传播(由“->”表示),您可以放置​​事件点击并阻止和/或修改关键事件。 Keyboard Driver 和 Window Server 都是特权组件,另外两个是普通用户级组件。

最早可以捕获键盘事件是当事件从驱动程序(内核空间)传播到 Window 服务器(用户空间,但仍然具有特权)时。然而,如上所述,大写锁定状态是在驱动程序内部处理的,因此捕获事件已经为时已晚。驱动程序将已经启用键盘上的大写锁定指示灯(如果有必要,并且不由硬件自行执行)并记住大写锁定状态处于打开状态,这会对将来的所有按键产生影响。

您可以通过编程方式关闭 HID 设备的大写锁定灯(Apple 甚至有 示例代码),但这不会关闭大写锁定,它只是关闭灯。

我认为使用事件点击来实现的唯一方法是手动将每个带有大写锁定的按键重写为不带大写锁定的按键(未设置大写锁定标志且附加字母(如果有)为小写)。此外,为了不让用户感到困惑,您需要关闭大写锁定灯,如 Apple 的示例代码所示。

其他替代方案是:编写您自己的键盘驱动程序,以控制键盘而不是苹果的标准驱动程序(没有您想象的那么难,但仍然足够难)或侵入驱动程序(邪恶,但有效)。例如,一些键盘重新映射器仅覆盖驱动程序的单个方法(驱动程序在 OS X 中是 C++,因此它们是 OO 对象,您可以在运行时动态覆盖 C++ 方法;不是真正覆盖它们,而是操作方法表)。这两种解决方案的问题是:第一个意味着除非您的驱动程序与 Apple 的驱动程序一样好,否则某些 USB 键盘可能无法与您的驱动程序配合使用,而另一些则可以,第二个意味着如果您犯了任何错误,系统会用内核恐慌来惩罚这个错误。

我正在寻找一种在 Mac 上以编程方式切换大写锁定的方法,但到目前为止还没有成功。但我可以向你保证,事件点击并不是正确的选择。

You cannot block capslock like that. Capslock is a condition, that is handled by the keyboard driver, not by the Window Server or the individual applications. A keypress event propagates in OS X like that:

Keyboard Driver -> Window Server -> User Session -> Active Application

At each level propagation (indicated by "->") you can place an event tap and block and/or modify key events. Keyboard Driver and Window Server are both privileged components, the other two are normal user level components.

The earliest you can catch a keyboard event is when the event propagates from the Driver (kernel space) to the Window Server (user space, but still privileged). However, as noted above, the capslock state is handled internally in the driver, thus catching an event there is already too late. The driver will already have enabled the capslock light on the keyboard (if necessary at all and not performed by the hardware on its own) and remembered the capslock state being on, which has an effect on all future key presses.

You can turn off the capslock light programmatically for HID devices (Apple has even sample code for that), but this will not turn-off capslock, it just turns off the light.

The only way I see to implement that using event taps is to manually re-write every key press with capslock to a key press without capslock (one where the capslock flag is not set and the attached letter, if any, is lower case). Further, to not confuse the user, you'd turn off the capslock light as shown by Apple's sample code.

Other alternatives are: Write your own keyboard driver, that takes control over the keyboard instead of Apple's standard driver (not as hard as you think, but still hard hard enough) or hacking your way into the driver (evil, but works). E.g. some keyboard remappers override only single methods of the driver (drivers are C++ in OS X, thus they are OO-objects and you can dynamically override C++ methods at runtime; not really override them, but rather manipulate method tables). The problems with those two solutions are: The first one means that unless your driver is as good as the one from Apple, some USB keyboards may not work with your driver, while others do, the second one means if you make any mistake, the system punishes this mistake with a kernel panic.

I'm looking myself for a way to programmatically toggle capslock on Mac, without success so far. But I can assure you, event taps are not the way to go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文