Раскладка клавиатуры под одной клавишей: Caps Lock переключает язык, а при
переключении в нижней части каждого монитора коротко всплывает плашка с
двухбуквенной меткой — RU, EN, DE. Плюс значок в области уведомлений,
который показывает текущую раскладку постоянно.
Утилита для Windows 10/11, C++20 и голый Win32 + GDI+, без зависимостей и без
установщика: один самодостаточный .exe.
Индикатор раскладки в Windows живёт в углу панели задач, а взгляд при наборе текста — в другом месте. CapsLayout показывает смену языка в поле зрения, а не в углу экрана, и гаснет меньше чем за секунду.
Вторая половина той же задачи — само переключение: штатные Alt+Shift и
Win+Space требуют двух рук и уводят пальцы с основной позиции. Caps Lock — одна
клавиша под мизинцем, и в наборе текста она почти не нужна.
- Плашка появляется на всех мониторах: по центру по горизонтали и у нижнего
края рабочей области, чтобы не перекрывать панель задач и не лезть в середину
экрана. Размер считается по DPI конкретного монитора (
PerMonitorV2), поэтому на смешанных конфигурациях выглядит одинаково. - Анимация: 90 мс появление, 550 мс показ, 220 мс угасание. Быстрые повторные переключения не мигают — показ просто продлевается.
- Подсказка не участвует в жизни фокуса: не активируется, пропускает клики насквозь, не попадает в Alt+Tab и на панель задач.
- Значок в трее с текущей раскладкой; клик левой кнопкой переключает раскладку и показывает подсказку, правой — меню.
- Переключение раскладки клавишей Caps Lock — работает сразу после запуска, отключается в меню трея. Верхний регистр остаётся на Shift + Caps Lock.
- Автозапуск при входе в систему — переключателем в меню трея.
- Один экземпляр на сессию; значок восстанавливается после перезапуска проводника.
Отслеживание раскладки работает строго по событию: пока раскладка не переключается, утилита не просыпается ни разу — постоянного опроса нет.
Тонкость в том, что документированный shell-hook HSHELL_LANGUAGE (8) в
Windows 11 не доставляется: при исправном hook замерено 0 событий на 74
переключения. Фактически смену раскладки сигнализирует недокументированный код
0x38 (lParam = 8) — 21 попадание из 21, и он молчит при Alt+Tab между окнами
с разными раскладками, то есть означает именно «пользователь переключил», а не
«активное окно сменилось».
Событие приходит на 20–70 мс раньше фактической смены раскладки, поэтому запрос состояния прямо в обработчике вернул бы ещё старое значение. Вместо опроса запускается короткая разовая серия проверок (10 мс, максимум 20 тиков), которая останавливается на первом же изменении.
Отрисовка — GDI+ в 32-битный DIB с альфа-каналом и вывод через
UpdateLayeredWindow.
Здесь событийность заканчивается: перехват клавиши — это глобальный хук
WH_KEYBOARD_LL, и пока переключатель включён, утилита получает управление на
каждое нажатие и отпускание любой клавиши. Работы в колбэке ровно на
сравнение кода клавиши, но честнее сказать прямо: выключенный переключатель не
стоит ничего, включённый — стоит вызова функции на каждое событие клавиатуры.
Колбэк намеренно не делает ничего тяжёлого: у низкоуровневого хука есть
LowLevelHooksTimeout (по умолчанию 300 мс), и превысив его, хук снимается
системой молча. Поэтому колбэк только шлёт сообщение окну-контроллеру, а
переключение выполняет цикл сообщений.
Само переключение — SendInput с Win+Space, то есть тот же путь, которым идёт
пользователь. Из-за этого оно работает и в UWP, и в Electron, где адресованное
окну WM_INPUTLANGCHANGEREQUEST можно просто не обработать. Четыре события
(Win вниз, пробел вниз, пробел вверх, Win вверх) уходят одним вызовом, чтобы
между ними не вклинился посторонний ввод, а Win отпускается после пробела —
одиночное нажатие-отпускание Win открыло бы меню «Пуск».
Обычный Caps Lock остаётся на Shift + Caps Lock: с зажатым модификатором
клавиша проходит насквозь. Нажатие и отпускание всегда гасятся парой — пропустив
отпускание, утилита всё равно переключила бы регистр, а погасив только его,
оставила бы системе нажатие без пары.
Нужна Visual Studio 2022 (или новее) с рабочей нагрузкой «Разработка классических приложений на C++». Windows SDK берётся новейший установленный.
Открыть CapsLayout.sln и собрать конфигурацию Release | x64, либо из
командной строки разработчика:
msbuild CapsLayout.sln /p:Configuration=Release /p:Platform=x64Результат — bin\Release\CapsLayout.exe. Release собирается со статическим CRT,
так что распространяемые пакеты Visual C++ на целевой машине не нужны.
Запустить CapsLayout.exe — окна у программы нет, появляется только значок в
области уведомлений.
| Действие | Результат |
|---|---|
| Переключить раскладку | Подсказка на всех мониторах |
Caps Lock |
Следующая раскладка (если не отключено в меню) |
Shift + Caps Lock |
Обычный Caps Lock — верхний регистр |
| Клик левой по значку | Следующая раскладка |
| Клик правой по значку | Меню: Caps Lock, автозапуск, выход |
Автозапуск включается через меню и записывает путь к исполняемому файлу в
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run (значение
CapsLayout); снятие галочки удаляет значение. Состояние переключателя Caps Lock
хранится в HKEY_CURRENT_USER\Software\CapsLayout (REG_DWORD CapsLockSwitch).
Больше утилита ничего никуда не пишет и не передаёт.
- Только Windows 10/11 x64.
- Определение смены раскладки опирается на недокументированный код shell hook — в будущих версиях Windows поведение может измениться.
- Неизвестный язык показывается шестнадцатеричным
LANGID: подсказка лучше честно сообщит, что язык не опознан, чем покажет неверные буквы. - Переключение по Caps Lock выполняется симуляцией
Win+Space, поэтому при каждом нажатии на мгновение мелькает системная плашка выбора языка. Взамен переключение работает везде, где работает штатный хоткей, включая UWP. - Если
Win+Spaceперехвачен сторонним лаунчером, Caps Lock откроет его вместо смены раскладки. - Над окнами с правами администратора Caps Lock не перехватывается: утилита
запускается с обычными правами (
asInvoker). - Настройки, кроме автозапуска и Caps Lock, не выносятся наружу — длительность
показа, размер и цвета правятся константами в
overlay.cpp.
| Файл | Назначение |
|---|---|
main.cpp |
Окно-контроллер, shell hook, логика реакции на событие |
overlay.cpp / .h |
Полупрозрачные окна подсказки на каждом мониторе |
tray.cpp / .h |
Значок в трее, контекстное меню, автозапуск |
layout.cpp / .h |
Определение активной раскладки и её метки |
capslock.cpp / .h |
Перехват Caps Lock и переключение раскладки |
MIT © Sergei Shipovskii