Не удается заблокировать колпачок с помощью CGEventTap - PullRequest
4 голосов
/ 29 мая 2010

Я использую 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. Однако капслок переключается независимо. Есть идеи, почему это так? Я делаю неправильные предположения? И / или как я могу действовать по-другому для достижения своей цели?

Спасибо

Thor

1 Ответ

8 голосов
/ 21 июня 2010

Вы не можете так блокировать колпачок. Capslock - это условие, которое обрабатывается драйвером клавиатуры, а не Windows Server или отдельными приложениями. Событие нажатия клавиши распространяется в OS X так:

Драйвер клавиатуры -> Сервер Windows -> Сеанс пользователя -> Активное приложение

На каждом уровне распространения (обозначается «->») вы можете разместить событие, блокировать и / или изменять ключевые события. Драйвер клавиатуры и Window Server оба являются привилегированными компонентами, остальные два являются компонентами обычного уровня пользователя.

Самое раннее, что вы можете поймать событие клавиатуры, это когда событие распространяется от драйвера (пространство ядра) к серверу окон (пространство пользователя, но все еще привилегированное). Однако, как отмечалось выше, состояние capslock обрабатывается внутри драйвера, таким образом, перехват события там уже слишком поздно. Драйвер уже включил подсветку колпачка на клавиатуре (если это вообще необходимо и не выполняется аппаратно самостоятельно) и запомнил, что состояние колпачка включено, что влияет на все будущие нажатия клавиш.

Вы можете программно отключить подсветку колпачка для устройств HID (Apple имеет даже образец кода для этого ), но это не отключит блокировку, а просто выключит подсветку.

Единственный способ реализовать использование метчиков событий - вручную переписывать каждое нажатие клавиши с помощью capslock на нажатие клавиши без capslock (тот, где флаг capslock не установлен, а прикрепленная буква, если таковая имеется, меньше дело). Кроме того, чтобы не вводить пользователя в заблуждение, вы должны выключить световой индикатор, как показано в примере кода Apple.

Другие альтернативы: написать свой собственный драйвер клавиатуры, который берет на себя управление клавиатурой вместо стандартного драйвера Apple (не так сложно, как вы думаете, но все еще достаточно сложно) или взломать свой путь к драйверу (зло, но работает ). Например. некоторые переназначения клавиатуры переопределяют только отдельные методы драйвера (драйверы - это C ++ в OS X, поэтому они являются объектами OO, и вы можете динамически переопределять методы C ++ во время выполнения; на самом деле они не переопределяют их, а скорее управляют таблицами методов). Проблемы с этими двумя решениями: первое означает, что, если ваш драйвер не так хорош, как у Apple, некоторые USB-клавиатуры могут не работать с вашим драйвером, в то время как другие - нет, второе означает, что если вы допустили какую-либо ошибку, система наказывает эту ошибку паникой ядра.

Я сам ищу способ программно переключать capslock на Mac, но пока безуспешно. Но я могу заверить вас, что прослушивание событий - не лучший способ.

...