Я использую некоторый код углерода в своем проекте Какао для обработки глобальных ключевых событий (ярлыков) из других приложений. В настоящее время я настроил обработчик событий kEventHotKeyReleased
и могу успешно получать горячие клавиши, когда мое приложение не активно. Это вызывает некоторые операции в моем приложении.
У меня проблема с поведением kEventHotKeyReleased
:
Скажем, например, я нажимаю комбинацию клавиш Cmd-Shift-P. Как только я отпускаю клавишу «P», запускается событие горячей клавиши. Мне нужно иметь возможность инициировать событие (или запустить его вручную), когда все клавиш не нажаты (т. Е. Клавиши Cmd и Shift тоже отпущены).
Легко отслеживать горячие клавиши, но я ничего не видел для мониторинга отдельных нажатий клавиш. Если бы я мог следить за состояниями клавиш-модификаторов, я бы занимался бизнесом.
Любые советы о том, как это сделать?
Заранее спасибо!
UPDATE:
Я пытался использовать kEventRawKeyUp
и kEventRawKeyModifiersChanged
, но, хотя kEventHotKeyReleased
работает, эти два не работают, хотя я настроил их точно так же, как kEventHotKeyReleased
.
EventTypeSpec eventTypes[] = {{kEventClassKeyboard, kEventHotKeyReleased}, {kEventClassKeyboard, kEventRawKeyUp}};
// Changing the order in the list does not help, nor does removing kEventHotKeyReleased
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);
// err == noErr after this line
Метод globalHotKeyHandler
вызывается для kEventHotKeyReleased
, но не для kEventRawKeyUp
по какой-то причине, которую я не могу понять. Вот как выглядит мой globalHotKeyHandler
метод:
OSStatus globalHotkeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) {
NSLog(@"Something happened!");
}
Нужно ли сделать дополнительный звонок или что-то еще, что я забыл?
N.B: На первый взгляд может показаться, что Access for Assistive Devices отключен, но это не . Так что я довольно невежественен.
ОБНОВЛЕНИЕ 2:
Я немного исследовал предложенный Лейбовицн CGEventTap
и придумал эту настройку:
CFMachPortRef keyUpEventTap = CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,kCGEventKeyUp,&keyUpCallback,NULL);
CFRunLoopSourceRef keyUpRunLoopSourceRef = CFMachPortCreateRunLoopSource(NULL, keyUpEventTap, 0);
CFRelease(keyUpEventTap);
CFRunLoopAddSource(CFRunLoopGetCurrent(), keyUpRunLoopSourceRef, kCFRunLoopDefaultMode);
CFRelease(keyUpRunLoopSourceRef);
... и обратный вызов:
CGEventRef keyUpCallback (CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
NSLog(@"KeyUp event tapped!");
return event;
}
Как видите, я использую kCGEventKeyUp
в качестве маски для события, но каким-то образом я получаю события мыши внизу ??! ??
ОБНОВЛЕНИЕ 3:
Хорошо, забудьте, что я пропустил строку в документе, в которой говорится, что для этого параметра используется CGEventMaskBit (kCGEventKeyUp), поэтому правильный вызов:
CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventKeyUp),&keyUpCallback,NULL);
У меня все еще есть проблема: клавиши-модификаторы не вызывают kCGEventKeyUp ...
ОБНОВЛЕНИЕ 4:
Хорошо, забудь об этом снова ... Я обязательно отвечу на свои вопросы через 5 минут после того, как задаю их сегодня, да!
Чтобы перехватить клавиши-модификаторы, используйте kCGEventFlagsChanged
:
CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventFlagsChanged),&callbackFunction,NULL);
Итак, по сути, у меня работает определение состояния ключа и ключа модификатора, но Мне все еще интересно узнать , почему kEventRawKeyUp
не работает ...
N.B .: Также обратите внимание, что я разрабатываю на Tiger с целью как можно большей поддержки новых и старых версий ОС. CGEventTap - только 10.4+, поэтому я буду использовать это сейчас, но было бы желательно использовать обратно совместимое решение.