无法使用CGEventTap阻止大写锁定

Tho*_*ich 4 capslock quartz-graphics cgeventtap

我正在使用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;
}
Run Code Online (Sandbox Code Playgroud)

如果我理解正确返回NULL应该有效地阻止keypress传播.实际上它也适用于"正常"的键盘和下降事件.但无论如何,封锁都会切换.任何想法为什么会这样?我做出了错误的假设吗?和/或我如何以不同的方式做事来实现我的目标?

谢谢,

雷神

Mec*_*cki 8

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

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

在每个级别传播(由" - >"表示),您可以放置​​事件点击并阻止和/或修改键事件.键盘驱动程序和窗口服务器都是特权组件,另外两个是普通用户级组件.

最早可以捕获键盘事件的是事件从驱动程序(内核空间)传播到Window Server(用户空间,但仍然是特权).但是,如上所述,大写锁定状态是在驱动程序内部处理的,因此捕获事件已经太晚了.驱动程序已经启用了键盘上的大写灯(如果有必要,而不是由硬件独立执行),并记住大写锁定状态正在打开,这对将来的所有按键操作都有影响.

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

我看到使用事件点击实现这一点的唯一方法是手动将带有大写锁定的每个按键重新写入没有大写锁定的按键(没有设置大写字母标记,并且附加的字母,如果有的话是小写).此外,为了不混淆用户,您可以关闭大写灯,如Apple的示例代码所示.

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

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