Предыстория: Linux, привычки и боль
Долгое время моим основным рабочим окружением был Linux. Там, как известно, «из коробки» (или через легкий тюнинг конфигов) можно повесить смену раскладки на любую клавишу. Я привык использовать для этого CapsLock. Это эргономично: мизинец лежит рядом, не нужно выкручивать пальцы в аккорды типа Alt+Shift или тянуться к Win+Space.
Но обстоятельства сложились так, что мне пришлось переехать на Windows. И тут начались фантомные боли. Стандартными средствами повесить смену языка на CapsLock — задача нетривиальная, а сторонний софт часто перегружен лишним функционалом.
Спасение в Switchy

В поисках решения я наткнулся на замечательный проект Switchy от пользователя erryox.
Хочу выразить огромную благодарность автору. Утилита делала ровно то, что нужно: вешала смену раскладки на CapsLock, оставляя оригинальный функционал (включение лампочки капса) на Shift+CapsLock. Проект написан на чистом C, без лишних зависимостей, весит копейки и работает через низкоуровневый хук клавиатуры.
Однако, сейчас оригинальный репозиторий находится в архиве, а в процессе использования я столкнулся с кейсом, который оригинальная утилита не покрывала.
Проблема «карусели» из раскладок
Оригинальный Switchy (и многие аналоги) работают по принципу эмуляции нажатия системных хоткеев (например, посылают системе Alt+Shift или Win+Space).
Это отлично работает, если у вас две раскладки (EN/RU).
Но что делать, если вы программист, лингвист или просто живете в мультикультурной среде? У меня, например, установлено 5 раскладкок (EN, RU, плюс два специфичных языка и символьная типографская раскладка).
При нажатии на CapsLock оригинальная утилита просто переключает на "следующую". Получается карусель:
EN -> RU -> L3 -> L4 -> Символы -> EN...
В 99% времени мне нужно переключаться только между EN и RU. А прокручивать каждый раз весь список, чтобы написать коммент в коде, дико раздражает.
Решение: Switchy Fork
Так появился мой форк. Идея проста: CapsLock должен переключать только между двумя основными языками, игнорируя остальные. А если мне вдруг понадобится немецкий или японский — я выберу его мышкой или стандартным Win+Space.
Как это работает под капотом
В оригинале использовалась эмуляция нажатия:
// Оригинальный подход (упрощенно)
keybd_event(VK_MENU, 0, 0, 0); // Alt
keybd_event(VK_LSHIFT, 0, 0, 0); // Shift
// ...release keys
Я переписал логику. Вместо слепого переключения "вперед", программа теперь точно знает, на какой язык переключаться.
При старте программа считывает ID раскладок (HKL) из
iniфайла или авто-детектит первые две из системного списка.При нажатии CapsLock определяем текущую раскладку активного окна.
Если текущая
Layout1— включаемLayout2. В любом другом случае (даже если включен 3-й или 4-й язык) — принудительно возвращаемLayout1.
Вместо эмуляции клавиатуры используется прямая отправка сообщения окну:
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, (LPARAM)targetLayout);
Это работает надежнее и быстрее, чем эмуляция нажатия клавиш, и позволяет жестко зафиксировать пару языков для быстрого переключения.
Фичи и конфиг
Проект обзавелся файлом конфигурации switchy.ini, который должен лежать рядом с .exe.
Возможности:
Жесткое задание языков: Можно указать HEX-коды раскладок (например,
00000409для US). Если оставить пустым — подхватит первые две из системы.Свой хоткей: Если вы сектант правого Ctrl или другой клавиши, код клавиши можно поменять в конфиге (по умолчанию
20— это CapsLock).Оригинальный CapsLock: Доступен по
Shift + Hotkey.Вкл/Выкл: Утилиту можно временно отключить нажатием
Alt + Hotkey.
Пример switchy.ini:
[Settings]
; HKL раскладок можно найти в реестре или гугле
; 00000409 = English (US)
; 00000419 = Russian
; 00000422 = Ukrainian
; 00000407 = German
; 0000040C = French
; Оставьте пустым для автоопределения (1-я и 2-я раскладки в системе)
Layout1=00000409
Layout2=00000419
; Коды клавиши
; 20 = Caps Lock (По умолчанию)
; 19 = Pause/Break
; 45 = Insert
; 112 = F1
SwitchKey=20
Где взять
Исходный код и релиз доступны на GitHub — Switchy
Надеюсь, кому-то это сбережет нервы так же, как и мне. Пользуйтесь на здоровье!