Я использую код Carbon в моем проекте Cocoa для обработки событий глобального ключа (ярлыков) из других приложений. В настоящее время я установил обработчик событий 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 для вспомогательных устройств отключен, но он не. Поэтому я довольно невежественный.
ОБНОВЛЕНИЕ 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+, поэтому я буду использовать это сейчас, но приветствуется обратное совместимое решение.