Добрый день!

Столкнулся с неприятной проблемой в Windows 11: при быстром переключении раскладки (Alt+Shift) язык меняется не всегда. Сразу после перезагрузки ПК все работает, но проблема появляется через какое-то время.

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

В чем суть проблемы

По ощущениям (и по комментариям других пользователей), стандартный механизм Windows 11 иногда не успевает корректно обработать/отрисовать переключение раскладки при быстрых нажатиях.

Косвенное подтверждение: переключение через Win+Пробел при этом работает стабильно.

Что обычно советуют, но мне не помогло

  • отключить залипание клавиш;

  • перезапустить ctfmon.exe;

  • переустановить языки/раскладки.

В моем случае эффекта не было.

Решение

Я отказался от стандартного механизма переключения и сделал его через AutoHotkey v2.
Скачать: https://www.autohotkey.com/

Варианты

  • Punto Switcher — простой вариант, можно переключать одной клавишей или автоматически. Но для разработки автопереключение часто неудобно.

  • AutoHotkey v2 — гибко, быстро и предсказуемо. Этот вариант я и выбрал.

Настройка AutoHotkey

Устанавливаем AutoHotkey v2

Скрипт перехватывает нажатие Alt+Shift и выполняет переключение раскладки напрямую через API Windows, обходя стандартный механизм смены языка в Windows 11. За счет этого переключение между RU и EN срабатывает стабильнее при быстром наборе, без пропусков и задержек, которые иногда возникают у штатного переключателя.
Также в скрипте есть защита от двойного срабатывания, чтобы при одном нажатии язык менялся ровно один раз.

Создаем файлик скрипта в любом удобном месте, и называем например LangSwitch.ahk
Вставляем и сохраняем:

#Requires AutoHotkey v2.0
#SingleInstance Force
; Переключение между RU и EN по Alt+Shift (в любом порядке нажатия)
~*LAlt::TrySwitch()
~*RAlt::TrySwitch()
~*LShift::TrySwitch()
~*RShift::TrySwitch()
TrySwitch() {
    static lastTick := 0
    if !(GetKeyState("Alt", "P") && GetKeyState("Shift", "P"))
        return
    ; Защита от двойного срабатывания при одновременных событиях клавиш
    now := A_TickCount
    if (now - lastTick < 150)
        return
    lastTick := now
    ToggleRuEn()
}
ToggleRuEn() {
    static RU := 0x0419
    static EN := 0x0409
    hwnd := WinActive("A")
    if !hwnd
        return
    ; Текущая раскладка потока активного окна
    threadId := DllCall("GetWindowThreadProcessId", "Ptr", hwnd, "UInt*", 0, "UInt")
    hkl := DllCall("GetKeyboardLayout", "UInt", threadId, "UPtr")
    langId := hkl & 0xFFFF
    target := (langId = RU) ? EN : RU
    targetHKL := (target << 16) | target
    ; WM_INPUTLANGCHANGEREQUEST
    DllCall("PostMessage", "Ptr", hwnd, "UInt", 0x50, "Ptr", 0, "Ptr", targetHKL)
}

Перед запуском скрипта рекомендую отключить стандартный механизм смены раскладки:
Заходим в Параметры --> Время и язык ---> Ввод --> Дополнительные параметры клавиатуры --> Сочетания клавиш для языков ввода.
Нажимаем на "Переключить язык ввода", справа снизу "Сменить сочетание клавиш" -- и выбираем в колонках "Не назначено"

Далее можем его запустить, ну и для удобства добавить в автозагрузку -
Нажимаем Win + R, пишем shell:startup
Создаем ярлык и указываем его на наш файлик со скриптом

Готово.