Не удается заблокировать колпачок с помощью CGEventTap
Я использую Quartz CGEventTap в попытке глобально перехватить нажатия клавиш и заблокировать их (чтобы они вместо этого сделали что-то полезное). Я успешно обнаружил нажатие на капслок, но до сих пор не смог их заблокировать. Мой код (происходящий из этого ответа на stackru) выглядит примерно так:
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. Однако капслок переключается независимо. Есть идеи, почему это так? Я делаю неправильные предположения? И / или как я могу действовать по-другому, чтобы достичь своей цели?
Спасибо,
Тор
1 ответ
Вы не можете так блокировать колпачок. Capslock - это условие, которое обрабатывается драйвером клавиатуры, а не Windows Server или отдельными приложениями. Событие нажатия клавиши распространяется в OS X так:
Драйвер клавиатуры -> Сервер Windows -> Сеанс пользователя -> Активное приложение
На каждом уровне распространения (обозначается как "->") вы можете размещать событие, блокировать и / или изменять ключевые события. Драйвер клавиатуры и Window Server оба являются привилегированными компонентами, остальные два являются компонентами обычного уровня пользователя.
Самое раннее, что вы можете поймать событие клавиатуры, - это когда событие распространяется от Driver (пространство ядра) к Window Server (пространство пользователя, но все еще привилегированное). Однако, как отмечено выше, состояние capslock обрабатывается внутри драйвера, таким образом, обнаружение события уже слишком поздно. Драйвер уже включил подсветку колпачка на клавиатуре (если это вообще необходимо и не выполняется аппаратно самостоятельно) и запомнил, что состояние колпачка включено, что влияет на все будущие нажатия клавиш.
Вы можете программно отключить подсветку колпачка для устройств HID (для этого у Apple есть даже пример кода), но это не отключит блокировку колпачка, а просто выключит подсветку.
Единственный способ, который я вижу, чтобы реализовать это с использованием отводов событий, - это вручную переписывать каждое нажатие клавиши с помощью capslock на нажатие клавиши без capslock (тот, где флаг capslock не установлен, а прикрепленная буква, если таковая имеется, строчная). Кроме того, чтобы не вводить пользователя в заблуждение, вы должны выключить световой индикатор, как показано в примере кода Apple.
Другие альтернативы: написать свой собственный драйвер клавиатуры, который берет на себя управление клавиатурой вместо стандартного драйвера Apple (не так сложно, как вы думаете, но все еще достаточно сложно) или взломать свой путь к драйверу (зло, но работает). Например, некоторые переназначения клавиатуры переопределяют только отдельные методы драйвера (драйверы - это C++ в OS X, поэтому они являются объектами OO, и вы можете динамически переопределять методы C++ во время выполнения; на самом деле они не переопределяют их, а скорее манипулируют таблицами методов). Проблемы с этими двумя решениями: первое означает, что, если ваш драйвер не так хорош, как у Apple, некоторые USB-клавиатуры могут не работать с вашим драйвером, в то время как другие - нет, второе означает, что если вы допустили какую-либо ошибку, система наказывает эту ошибку паникой ядра.
Я сам ищу способ программно переключать capslock на Mac, но пока безуспешно. Но я могу заверить вас, что прослушивание событий - не лучший способ.