Как отслеживать состояние глобального ключа-модификатора (в любом приложении)?

StackOverflow https://stackoverflow.com/questions/1603030

  •  05-07-2019
  •  | 
  •  

Вопрос

Я использую некоторый код Carbon в своем проекте Cocoa для обработки глобальных ключевых событий (ярлыков) из других приложений.В настоящее время у меня есть настройка kEventHotKeyReleased обработчик событий, и я могу успешно получать горячие клавиши, когда мое приложение не активно.Это запускает некоторую операцию в моем приложении.

Проблема, с которой я сталкиваюсь, связана с поведением kEventHotKeyReleased является:

Допустим, например, я нажимаю комбинацию клавиш Cmd-Shift-P.Как только я отпускаю клавишу "P", запускается событие горячей клавиши. Мне нужно иметь возможность запускать событие (или вручную запускать его), когда ВСЕ часть клавиш не нажата (тоесть:клавиши Cmd и Shift тоже отпущены).

Легко отслеживать наличие горячих клавиш, но я не видел ничего для мониторинга отдельных нажатий клавиш.Если бы я мог отслеживать состояния ключа-модификатора, я был бы в деле.

Есть какие-нибудь подсказки о том, как это сделать?

Заранее спасибо!


Обновить:

Я пробовал использовать 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:На первый взгляд кажется, что доступ для вспомогательных устройств может быть отключен, но это не так.Так что я совершенно невежественен.


ОБНОВЛЕНИЕ 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 +, поэтому пока я буду использовать это, но было бы желательно использовать обратно совместимое решение.

Это было полезно?

Решение

Одним из вариантов является использование EventTaps .Это позволяет вам отслеживать все события с клавиатурой.Видишь:http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate

К сожалению, нажатия на события перестанут работать, если приложение запрашивает безопасный ввод.Например, Ускорить.

Другие советы

OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);

Это не носит глобального характера.Это устанавливает обработчик только тогда, когда ваше собственное приложение активно, и (я полагаю) после собственных фильтров событий Carbon Event Manager.

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

Для событий, которые происходят, когда ваше приложение неактивно, нужной целью является GetEventMonitorTarget().Для событий, которые происходят во время работы вашего приложения является активен, цель, которую вы хотите, - это GetEventDispatcherTarget().Чтобы перехватывать события независимо от того, какое приложение активно, установите свой обработчик для обоих целевых объектов.

Однако в настоящее время я бы просто использовал CGEventTaps, как предложил Лейбовицн.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top