Предыстория: Linux, привычки и боль

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

Но обстоятельства сложились так, что мне пришлось переехать на Windows. И тут начались фантомные боли. Стандартными средствами повесить смену языка на CapsLock — задача нетривиальная, а сторонний софт часто перегружен лишним функционалом.

Спасение в Switchy

Switchy
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

Я переписал логику. Вместо слепого переключения "вперед", программа теперь точно знает, на какой язык переключаться.

  1. При старте программа считывает ID раскладок (HKL) из ini файла или авто-детектит первые две из системного списка.

  2. При нажатии CapsLock определяем текущую раскладку активного окна.

  3. Если текущая Layout1 — включаем Layout2. В любом другом случае (даже если включен 3-й или 4-й язык) — принудительно возвращаем Layout1.

Вместо эмуляции клавиатуры используется прямая отправка сообщения окну:

PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, (LPARAM)targetLayout);

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

Фичи и конфиг

Проект обзавелся файлом конфигурации switchy.ini, который должен лежать рядом с .exe.

Возможности:

  1. Жесткое задание языков: Можно указать HEX-коды раскладок (например, 00000409 для US). Если оставить пустым — подхватит первые две из системы.

  2. Свой хоткей: Если вы сектант правого Ctrl или другой клавиши, код клавиши можно поменять в конфиге (по умолчанию 20 — это CapsLock).

  3. Оригинальный CapsLock: Доступен по Shift + Hotkey.

  4. Вкл/Выкл: Утилиту можно временно отключить нажатием 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

Надеюсь, кому-то это сбережет нервы так же, как и мне. Пользуйтесь на здоровье!