IMKit поймать событие NSKeyup

В качестве эксперимента я пытаюсь добиться следующего:

  • Пусть пробел работает как ключ-модификатор - как и клавиша Shift - где удерживание клавиши пробела и клавиши ввода печатают разные буквы. Выделение пробела приведет к нормальному состоянию состояния, и просто нажатие на него ведет себя как обычный пробел.

Я думал об обработке события keydown и *****, но, по-видимому, handleEvent:client: в IMKServerInput Protocol, кажется, только ловут ключевые события и события мыши.

Без большого опыта работы с cocoa, Ive пробовал некоторые методы без успеха:

Я пришел к выводу, что IMKit способен пассивно принимать события. Поскольку это не приложение, не существует метода keyUp: для переопределения - AFAIK, IMKit не наследует класс NSResponder.

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

Может ли кто-нибудь помочь мне в правильном направлении?

2 ответа

Я пробовал все возможные альтернативы один за другим и в конечном итоге добился этого, создав глобальную EventTap с CGEventTap.

Код в основном выглядит следующим образом:

// Create an event tap.
CGEventMask eventMask = ((1 << kCGEventKeyDown) | (1 << kCGEventKeyUp));
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap,
 kCGHeadInsertEventTap,
 0,
 eventMask,
 myCGEventCallback,
 NULL);

if (!eventTap) {
 NSLog(@"failed to create event tap\n");
 return NO;
} else {
 // Create a run loop source.
 runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
 // Add to the current run loop.
 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
 // Enable the event tap.
 CGEventTapEnable(eventTap, true);
 return YES;
}

где myCGEventCallback обрабатывает глобальные состояния.

Между тем вот некоторые из того, что я выяснил:

  • В соответствии с документом " Последовательность ввода ключевых слов" приложение передает только событие keydown в набор методов ввода, после того, как пробует другую цепочку обработчиков в цепочке. Вы не можете позволить IMKServerInput "поймать" событие NSKeyUp. Просто добавление NSKeyUpMask к recognizedEvents: не работает.
  • addLocalMonitorForEventsMatchingMask:handler: и CGEventTapCreateForPSN не поймает событие. Я полагаю, это связано с тем, что, хотя метод ввода может выполняться как отдельный процесс, само событие запускается из приложения, например TextEdit, и передается методу ввода.
  • IOHIDManager: для добавления новых аппаратных устройств и создания драйверов.
  • Создание глобальной EventTap требует либо запуска процесса с правами sudo - копирование метода ввода в /Library/Input Methods не выполняется с привилегиями sudo - или регистрации приложения в элементе управления Accessibility. Это в системных настройках → Безопасность и конфиденциальность → вкладка "Безопасность" → "Доступность" в Mavericks.


Протокол IMKStateSetting recognizedEvents: метод должен включать события NSKeyUp:

- (**********)recognizedEvents:(id)sender {
 return NSKeyDownMask | NSKeyUpMask;
}

Клиент вызывает этот метод, чтобы проверить, поддерживает ли метод ввода событие. Реализация по умолчанию возвращает NSKeyDownMask.

Однако при тестировании мой метод ввода по-прежнему не NSKeyUp события NSKeyUp. Это похоже на ошибку.

Я подал следующий радар и надеюсь, что другие его дублируют:

rdar://21376535

licensed under cc by-sa 3.0 with attribution.