4

我正在使用 Quartz CGEventTap 试图全局拦截 capslock 按下并阻止它们(让它们做一些有用的事情)。我成功检测到 capslock 按下,但到目前为止还无法阻止它们。我的代码(源自这个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 事件。但是不管怎样,大写锁定都会切换。任何想法为什么会这样?我是否做出了错误的假设?和/或我怎样才能以不同的方式做事来实现我的目标?

谢谢,

雷神

4

1 回答 1

9

你不能像那样阻止大写锁定。Capslock 是一种条件,由键盘驱动程序处理,而不是由 Window 服务器或单个应用程序处理。一个按键事件在 OS X 中像这样传播:

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

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

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

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

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

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

我正在寻找一种在 Mac 上以编程方式切换大写锁定的方法,但到目前为止没有成功。但我可以向你保证,事件水龙头不是要走的路。

于 2010-06-21T14:26:08.780 回答