quartz-graphics - 无法使用 CGEventTap 阻止大写锁定

标签 quartz-graphics capslock cgeventtap

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

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 事件。但是无论如何大写锁定都会切换。任何想法为什么会这样?我是否做出了错误的假设?和/或我怎样才能以不同的方式做事来实现我的目标?

谢谢,

雷神

最佳答案

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

键盘驱动程序 -> 窗口服务器 -> 用户 session -> 事件应用程序

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

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

您可以通过编程方式关闭 HID 设备的大写锁定灯(Apple 甚至有 sample code for that ),但这不会关闭大写锁定,它只会关闭灯。

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

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

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

关于quartz-graphics - 无法使用 CGEventTap 阻止大写锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2935931/

相关文章:

iphone - 如何将 UIView 渲染成两部分

c++ - 检查 C++ 中 CAPSLOCK 是否打开/关闭

macos - 如何在 mac os x 中将 ESCAPE 键映射到 CAPS LOCK?

objective-c - 在 OS X 中以编程方式模拟/切换 CAPS LOCK

cocoa - CGEventTap 阻止应用程序输入

线程中的 Swift 3 CFRunLoopRun?

objective-c - 如何在 cocoa 中绘制椭圆渐变?

ios - 模式填充那个 "follows"的路径?

iphone - 哪个框架最适合创建原始形状绘图应用程序?

macos - 映射大写字母仅在 vim 中锁定?