Back to Home

Windows 11 Keyboard Layout Switching AutoHotkey

The article describes an AutoHotkey v2 script for stable Alt+Shift keyboard layout switching in Windows 11. Bypasses the standard mechanism via WinAPI, includes debounce and UAC support. Full code and setup instructions.

Fix Alt+Shift in Windows 11: AutoHotkey script
Advertisement 728x90

Stable Keyboard Layout Switching in Windows 11 with AutoHotkey v2

In Windows 11, the standard Alt+Shift shortcut sometimes misses language switches during fast typing. After a system reboot, it works correctly, but over time the mechanism starts to fail. Switching via Win+Space remains stable, indicating delays in the standard hotkey handler's processing.

Common recommendations—disabling sticky keys, restarting ctfmon.exe, or reinstalling language packs—don't solve the problem in most cases.

Solution Based on AutoHotkey v2

Intercept the Alt+Shift combination via an AutoHotkey v2 script that directly calls Windows API to change the layout. This bypasses the built-in mechanism, ensuring predictable operation without misses.

Google AdInline article slot

Advantages of This Approach

  • Fast triggering even with frequent presses.
  • Protection against duplicate events.
  • Works in active window threads (thread-specific layout).

An alternative is Punto Switcher with auto-switching, but for developers, manual control is preferable due to flexibility.

Script Setup

Install AutoHotkey v2. Create a file LangSwitch.ahk and insert the code:

#Requires AutoHotkey v2.0
#SingleInstance Force
; Switch between RU and EN with Alt+Shift (in any press order)
~*LAlt::TrySwitch()
~*RAlt::TrySwitch()
~*LShift::TrySwitch()
~*RShift::TrySwitch()
TrySwitch() {
    static lastTick := 0
    if !(GetKeyState("Alt", "P") && GetKeyState("Shift", "P"))
        return
    ; Protection against double-triggering from simultaneous key events
    now := A_TickCount
    if (now - lastTick < 150)
        return
    lastTick := now
    ToggleRuEn()
}
ToggleRuEn() {
    static RU := 0x0419
    static EN := 0x0409
    hwnd := WinActive("A")
    if !hwnd
        return
    ; Current layout of the active window's thread
    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)
}

Script Logic Breakdown

  • Key Hooks: ~LAlt, ~RAlt, etc., trigger on press without blocking (~) and in any order.
  • Combination Check: GetKeyState confirms simultaneous Alt+Shift press.
  • Debounce: A 150 ms interval prevents multiple calls from key jitter.
  • Getting Layout: GetKeyboardLayout for the active window's threadId returns the HKL of the current thread.
  • Switching: PostMessage with WM_INPUTLANGCHANGEREQUEST (0x50) applies the target HKL.

Disabling the Standard Hotkey

Settings → Time & Language → Typing → Advanced keyboard settings → Input language hotkeys.

Google AdInline article slot

Select "Switch input language" → "Change key sequence" → "Not assigned".

Autostart and UAC

  • Create a script shortcut in shell:startup.
  • For UAC applications: run via C:\Program Files\AutoHotkey\v2\AutoHotkey64_UIA.exe (uiAccess).

Requires AutoHotkey installed in Program Files.

Key Points

  • The script uses thread-specific layout via GetWindowThreadProcessId and GetKeyboardLayout.
  • PostMessage(0x50) ensures switching without window focus.
  • Debounce of 150 ms minimizes false triggers during fast input.
  • UIAccess mode resolves administrator permission issues.
  • RU/EN support: 0x0419 and 0x0409.

— Editorial Team

Google AdInline article slot
Advertisement 728x90

Read Next