Очень давно тому назад я впервые себе закупил MacBook. Тогда они были ещё белые и пластиковые. Чуть позже у меня появился первый MacBook Unibody, который в алюминиевом корпусе, но при этом ещё не обзавёлся приставкой pro или air. На тот момент я особо не парился с переключением раскладки клавиатуры и меня всё устраивало. Впрочем тогда мне особо и не приходилось вести какую-то профессиональную деятельность на этих машинках и я не заботился о настраивании некоего рабочего процесса и подборе приложений.
Тогда эти машинки у меня не задержались надолго. И на ~12 лет я просто забыл о существовании MacOS и яблочных устройств. Но в один прекрасный (или не очень) момент пришлось о них вспомнить. На работе сказали, что есть два стула - "совсем не очень" и "так себе". И этим "так себе" оказался Macbook Pro. И тут я уже подошёл к маку несколько более придирчиво, профессионально, если можно так выразиться.
На своих линупсах я уже давненько использую CapsLock для переключения раскладки клавиатуры и это работает быстро и чётко. А тут.. MacOS предлагает такую опцию из коробки. Казалось бы - вот оно, счастье. Но тут есть подвох. И вот я хочу поведать очередную охренительную историю о такой казалось бы простой вещи, как переключение языковой раскладки клавиатуры.
Штатно, насколько я помню, переключение раскладки в MacOS происходит по Option+Space/Option+Shift+Space что несколько неудобно, так как приходится сдвигать не только пальцы, но и руку целиком, если хочешь переключиться одной рукой. Можно переключаться двумя руками, но такой привычки ни у меня, ни у моих знакомых просто нету. А вот у моих знакомых-программистов есть привычка переключать раскладку по CapsLock, которую я благополучно перенял. Довольно удобный маппинг. В современной жизни кнопка Caps Lock используется крайне редко, но при этом находится в довольно удобной позиции относительно левого мизинца.
В Windows, например, переключение штатно висит на Alt+Shift, (в старых инстолляторах windows переключение раскладки было (неочевидным образом) назначено на left shift+right shift). Как альтернативный вариант, Windows предлагает переключение раскладки на Ctrl+Shift. Оба варианта пользуются в народных массах довольно широкой популярностью. И благодаря своей распространённости - это тоже неплохой вариант: механическая память - очень сильный мотиватор.
Сочетания кнопок "как в венде" для переключения клавиатурной раскладки в MacOS штатным образом намапить не получится: кнопки Cmd, Option, Alt, Shift, Ctrl - это модификаторы, а сочетание кнопок в MacOS должно состоять из 1 и более модификатора и одной обычной кнопки. По этой же причине нельзя зарегистрировать CapsLock в качестве переключателя раскладок из меню keyboard shortcuts.
Но вернёмся к нашим баранам.
Итак, переключение на Caps Lock. Можно настроить прям в настройках клавиатуры - переключение на английский и обратно по Caps Lock. Поскольку у меня всего 2 локали - это выглядит как то что надо. И... тут возникает нюанс: при нажатии на Caps Lock переключение происходит "какбы" не моментально и если начать печатать текст сразу после переключения, не выждав ~0.3 секунды, то переключение раскладки не произойдёт. Кроме того, само по себе переключение в некоторых случаях не происходит. Таким образом, штатные средства нам не подходят - они настолько жалкие, что вызывают только раздражение.
Другой вариант - это Karabiner Elements. Это якобы приложение для... автоматизации чего-то. Чего - непонятно. Но в своей бесплатной версии приложение умеет как раз то, что нам надо. А именно - ремапить любую кнопку клавиатуры на любую другую кнопку. Есть, в том числе, поддержка кнопок F вплоть до F24. Кажется, на старых эполовских клавиатурах я видел кнопки F1..F16 и это самое большое число F-кнопок которое я щупал... Ну да ладно. Ремапим Caps Lock на F18. Переходим в настройки переключения Input Layout-ов и говорим, что хотим не Option+Space, для Select Previous Input Source, а F18. Вуаля, работает. Причём, работает максимально чётко, быстро, без лагов, пропусков итд.
Но... остался некий нерешённый момент: я привык, что у меня при русском языке загорается CapsLed. На маке это было бы очень удобно, потому что верхнюю панельку я авто-скрываю. И, если часы я могу поставить на видное мест и бросать на них взгляд время от времени, то вот про текущую раскладку клавиатуры я могу узнать только нажав кнопку.
И тут я узнАю про Hammerspoon - это приложение, как ни странно, но тоже для автоматизации процессов взаимодействия с UI. Предполагается, что можно написать некую скриптоту, которая сможет что-то там себе творить, беря на себя некую регулярную рутину в работе. Скриптота пишется на lua. С одной стороны это, наверно, хорошо, но с другой - lua довольно многословный язык со странными конструкциями и некоторыми детскими болезнями.
Так вот, в Hammerspoon есть возможность взаимодействовать с клавиатурой, в том числе менять layout. И... зажигать лампочку Caps Lock! Казалось бы, вот оно, счастье! Но не всё так радужно.
Итак, вернёмся к обработчику CapsLock, реализованному самой Apple. Именно с ним взаимдействует Hammerspoon.
У нас есть 3 режима работы кнопки Caps Lock:
- дефолтный. Когда кнопка работает, как задумывали разработчики Apple.
- режим переключения раскладок + если подержать кнопку Caps Lock, то она сработает как Caps Lock.
- режим No Action
Первый режим. Я тут выше по тексту писал, что он работает недостаточно чётко. И... на практике - это самый хорошо работающий режим. При нажатии на CapsLock, в приложение прилетает несколько событий. И... интересное дело, но событий о нажатии и об отпускании кнопки не прилетает. Прилетает (как правило) пачка событий об изменении состояния флагов модификаторов. Их прилетает от 1 до 8 штук на одно нажатие кнопки. Что касается сканкодов, то здесь всё довольно интересно: в пачке событий присутствуют как сканкод кнопки CapsLock, так и сканкод 255. Причём, вразнобой. Из интересного: поскольку CapsLock - это (какбы) не совсем модификатор, то в таблице состояния модификаторов ничего не меняется. То есть, прилетает пачка событий по изменению флагов режимов, но при этом в списке режимов ничего не меняется. Определить с точностью "что это было" - невозможно, так как вся пачка может прилететь со сканкодом 255, а не со сканкодом клавиши CapsLock. Но при этом бывает и обратная ситуация - при нажатии на клавишу CapsLock сам по себе режим CapsLock меняется, но никаких событий в Hammerspoon не прилетает. А ещё иногда бывает, что нажатия не регистрируются вообще. Также присутствует проблема, когда нажатия происходят слишком часто, например CapsLock нажимается два раза или три, подряд, не выждав заветные ~0.3 секунды, то повторные нажатия могут и не зарегистрироваться, а могут спровоцировать ещё бОльший "дребезг".
Второй режим. Очень похож на первый. Но работает ещё менее уверенно - события приходят с бОльшим разбросом в параметрах, во всяком случае мне так показалось.
Третий режим. О, здесь вообще всё шикарно. Адекватный человек рассчитывает, что события от клавиши CapsLock будут пропускаться "как есть" и ОС на них просто не будет реагировать - режим работы называется ведь "No Action". Название намекает. Но дело Стива Возняка живёт и тут. Но, если Стив делал хоть и странные хаки, но в итоге они были изящными и, вроде как, никого не обламывали, то в этом случае запахло продажниками. No Action на самом деле не выключает реакцию ОС на нажатие кнопки, а выключает события от кнопки. То есть, никаких сканкодов от нажатия на эту кнопку более в систему не поступает. Максимально бесполезный режим.
И, да, Hammerspoon способен зажечь лампочку, да, он способен управлять режимом Caps Lock независимо от нажатий на саму кнопку, да, он способен отследить нажатия на кнопку и переключить раскладки. Но картину портит как раз тот факт, что сама MacOS не способна адекватным образом доставлять события в программу.
И тем не менее, есть ещё и другой момент. Дело в том, что Hammerspoon под капотом использует lua для создания скриптов своей бизнес-логики. Из опыта коллег, чтобы встроить lua в качестве скриптового языка, много трудов не надо, но чтобы заставить lua работать хорошо и надёжно, придётся очень так знатно попотеть и даже при этом будут некоторые "шероховатости". То есть конкрентно скриптота на lua работает хорошо и быстро. Но возникают нюансы, когда есть конкуренция за ресурсы.
Сам по себе интерпретатор lua не предоставляет абсолютно никаких возможностей по созданию семафоров или мьютексов. А они нужны для работы с оборудованием. Более того, запись даже простых переменных в lua не "атомарно". То есть реализовать мьютекс на глобальных переменных - это такая себе затея. И в случае переключения раскладок, когда в Hammerspoon прилетает сразу куча событий, с очень маленьким интервалом между ними, происходит как раз конкурентное исполнение сразу кучи lua-шных коллбэков-обработчиков событий. И если событий будет сравнительно много (а в MacOS, с её умением заставить приложения работать в "полудрёме", "очень много" может скопиться довольно быстро), обработчик событий "залипает". При этом, вначале события начинают исполняться с задержкой, а потом и вовсе перестают.
Чтобы "залепить" обработчик событий в Hammerspoon с помощью кнопки CapsLock, надо её понажимать в течение ~ полуминуты с интервалами примерно от 0.2 до 0.7 секунды, тогда нагенерится достаточное количество событий...
Не хочу сказать, что программа плохая, для автоматизации она вполне подходит, например, она умеет показать, что только что произошло показав на экране полупрозрачную всплывашку, в ней довольно удобно назначать сочетания кнопок (прям в скрипте), также для этой штуки есть несколько неплохих "рецептов", например тот же самый ClipBoard History, который запоминает историю буффера обмена, с возможностью выбрать предыдущие скопированные строки текста. Также можно сделать простой обработчик раскладки окон на рабочем столе. Можно даже попробовать залезть в UI определённого приложения и автоматизировать работу с его элементами управления. Собственно, для этого по идее Hammerspoon и был создан, но мало кто использует его конкретно для таких штук. Всё больше как некоторую замену-подпорку для привычек, сохранившихся при переходе с каких-нибудь линуксовых тайловых wm.
Но таки снова вернёмся к MacOS и процессу переключения раскладок.
Потратив в общей сложности пару дней целиком на написание всяческих скриптов и окончательно разочаровавшись как в возможностях MacOS по работе с кнопкой CapsLock, так и в программе Hammerspoon, я пришёл к такому сетапу:
- Karabiner Elements ремапит CapsLock на F18
- Hammerspoon по нажатию на F18 переключает раскладку с "Russian" на "U.S." и обратно, в зависимости от текущего её состояния. И показывает текущую раскладку в качестве полупрозрачного alert-а на экране.
План по маппингу лампочки CapsLock провалился с треском, потому что для перехвата событий от кнопки CapsLock, Carabiner Elements хочет себе забирать ещё и лампочку. Забирает он себе лампочку с концами, то есть ивенты по изменению её состояния, которые генерит Hammerspoon не долетают до этой лампочки просто потому что она исчезает из списка доступных устройств.
В итоге победой мои исследования/приключения назвать нельзя. Да, был приобретён опыт, но цель полностью достигнута не была. Хотя, как побочный эффект, у меня теперь есть программа, работающая с историей буфера обмена, что само по себе неплохо. А также мьютилка микрофона. И ещё есть удобная мне мапилка кнопкосочетаний.