Как перехватить / переназначить произвольное событие клавиатуры на OSX?

Я хотел бы на карту:

  • CAPS-LOCK для Fn
  • Fn влево-мышь
  • LSHIFT+3 к #
  • RSHIFT+3 к чему-то еще
  • и т.п.

Я тщательно искал любой инструмент, который предлагает полную свободу для переназначения ввода с клавиатуры, но не могу найти. (В Windows есть AutoHotkey).

Я планирую написать свой собственный инструмент, который анализирует файл конфигурации.

Но как на самом деле копаться и делать это?

Решение этой проблемы потребует тщательного понимания прохождения нажатия клавиш в операционной системе, чтобы перехватить его в соответствующей точке.

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

Но где (и как)?

Изменить: я подробно излагаю результаты моего исследования в ответе ниже (который может быть перенесен обратно в вопрос в какой-то момент).

2 ответа

Я делаю это сообщество вики, пожалуйста, не стесняйтесь его улучшать.

Подвопросы, которые я задал:

Я могу перехватить почти все события keydown / keyup в нижней части среднего уровня. За исключением питания, а также нажатия клавиши CAPSLOCK при переходе из ON в OFF.

Довольно противно!

Работая на нижнем уровне, я могу получить все ключи вверх / вниз, кроме PowerKey.

Если бы не этот неуклюжий показатель успеха 75% для CapsLock, у меня было бы хорошее решение. Досадно, что обработка ключа в таком полезном месте значительно увеличивает необходимую сложность.

Я нашел DDHidLib и в настоящее время просматриваю его, чтобы выяснить, сглаживает ли он эту проблему.

Исследование

Поиск в Google "keyEventWithType CGEventTapCreate" кажется хорошей идеей, поскольку они являются важными компонентами для прослушивания события и его повторной отправки.

Ура! Изменить вывод keyDown - этот код компилируется и с незначительными изменениями (CGEventMaskBit( kCGEventKeyDown ) | CGEventMaskBit( kCGEventFlagsChanged ),) Я также могу подобрать клавиши-модификаторы. Я получаю разные коды клавиш для LSHIFT и RSHIFT. Brilliant!

Проблемы с вышесказанным:

  • Нажатие kCGEventKeyDown работает для некоторых функциональных клавиш, но не для других. Похоже, что Apple перегружает только определенные ключи, а перегруженные, похоже, попадают на более низкий уровень.
  • Клавиша Power/Eject не попадает.
  • Я не вижу никакого способа однозначно определить, от какого устройства исходит нажатие клавиши.

Как нажать (подключить) F7 через F12 и Power/Eject на клавиатуре MacBook

http://blog.tklee.org/2008/09/modifiers-across-keyboards.html
-> http://forums.macrumors.com/showthread.php?t=778484
-> https://github.com/maravillas/dual-keyboards

https://github.com/pkamb/PowerKey может дать некоторое представление
-> https://github.com/pkamb/PowerKey/blob/master/PowerKey/PKPowerKeyEventListener.m
-> Обработка событий клавиатуры Apple Keyboard - Rogue Amoeba
... общесистемный ярлык для Mac OS X
-> http://snippets.aktagon.com/snippets/361-registering-global-hot-keys-with-cocoa-and-objective-c

Еще одна проблема: LSHIFT-вниз RSHIFT-вниз и вверх LSHIFT-вверх. События RSHIFT не будут пойманы.

Похоже, мне нужно окунуться в IOKit

Использование IOHIDManager для получения событий ключа модификатора
-> https://github.com/candera/khordr/blob/master/src/c/keygrab/hid-scratch.c

kEventRawKeyDown in:

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/
Developer/SDKs/MacOSX10.10.sdk/System/Library/
Frameworks//Carbon.framework/Frameworks/HIToolbox.framework/
Headers/CarbonEvents.h

Ресурсы

3-х уровневая:

  • Cocoa / AppKit - это оболочка более высокого уровня
  • Кварц берет события из IOKit направляет их в приложения
    Примечание: NSEvent построен на Quartz Event

  • IOKit - общается с оборудованием

3-х уровневая

Top Tier (Какао / AppKit)

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html - этот документ является обязательным для просмотра и показывает вышеуказанную базовую трехуровневую архитектуру рис. Однако, похоже, что он фокусируется только на верхнем уровне (Cocoa / AppKit).

http://www.hcs.harvard.edu/~jrus/Site/Cocoa%20Text%20System.html <- в этой статье показаны 3 файла конфигурации OSX, которые работают на еще более высоком уровне и позволяют создавать собственные сопоставления. Это задокументировано здесь.

^ KeyBindingsEditor позволяет вам сделать вышеуказанные изменения.

Средний Ярус (Кварц)

QuartzEventServicesRef

NSEvent - специально создание событий

Пара рабочих примеров кода на этом уровне. Однако все они выполняют один и тот же основной прием: получают один код виртуального ключа и излучают другой. Таким образом, вы можете использовать эту технику, например, чтобы поменять местами "a" и "z".

Перехватывать ввод с клавиатуры в OSX - приводит к прослушиванию кварцевых событий

Измените NSEvent, чтобы посылать клавишу, отличную от той, которая была нажата - Дейв Де Лонг (Dave De Long) предоставляет рабочий пример, также используя QET.

https://gist.github.com/wewearglasses/8313195 <- "Глобальная клавиатура хук для OSX" - еще одна короткая рабочая демонстрация с использованием QET.

Ukelele позволяет вам выбрать, какой Unicode ассоциируется с определенным ключом или клавишей Modifier+. Не разрешает переназначение модификаторов, а также не устраняет неоднозначность влево от правых клавиш Shift и т. Д.

Ввод с клавиатуры в OSX - ответ указывает на addGlobalMonitorForEventsMatchingMask в NSEvent (в AppKit)

Базовый уровень (IOKit)

IOKitFundamentals <- Также IOKit ("Обработка прерываний в наборе ввода-вывода... Два типа событий инициируют прерывание:... Асинхронные события, такие как нажатия клавиш")

https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Other_APIs/AH_Other_APIs.html

Как игры для Mac OS X могут получать события ввода с клавиатуры низкого уровня? <- геймеры заинтересованы в этом!

http://phrack.org/issues/66/16.html - иногда хакеры представляют вещи наиболее четко, еще не прочитав это. IOKit снова, кажется.


Больше ссылок...

Как вы реализуете глобальные зацепки клавиатуры в Mac OS X? <- ссылки на статью.

OSX: обнаруживать общесистемные события keyDown? <- немного ОТ, так как это связано только с глобальным мониторингом, то есть только для чтения.

http://www.codeitive.com/7QHSeVjPWq/where-can-i-find-kcgkeyboardeventkeycode-list-of-key-codes-for-cyrillic-language.html

Вы проверили Karabiner (который делает все, что вы хотите сделать... до OSX 10.11 ... MacOS 10.12 изменил модель драйвера клавиатуры, и авторы - в основном Tekezo- все еще переписывают Karabiner, чтобы учесть новую модель - это по состоянию на февраль 2017 года) Karabiner имеет открытый исходный код, и вы можете скачать код с Github и использовать его.

В рамках переписывания они выпустили элементы Karabiner, которые работают на 10.12 Sierra, но пока не могут сделать все, что сделал карабинер.

Карабинер очень мощный, и я очень скучаю по нему 10.12

Другие вопросы по тегам