How do I fix an AHK script for switching keyboard layouts in Windows system windows?
I’m using Windows 10 and this is my first time working with AutoHotkey. I created a script to switch keyboard layouts: Russian language on right Ctrl and English on left Ctrl. Here’s my script:
~LCtrl up::
If (A_PriorKey = "LControl") {
SendMessage, 0x50,, 0x4090409,, A ; English
}
~RCtrl up::
If (A_PriorKey = "RControl") {
SendMessage, 0x50,, 0x4190419,, A ; Russian
}
The script works correctly in regular windows but doesn’t trigger in Windows system windows, for example, in the standard file save dialog.
What’s the error in my script and how can I fix it?
Note: I know that PuntoSwitcher solves this problem, but I don’t want to use this program.
Additionally: I want to keep only this script as the method for switching languages in the system, without adding additional key combinations in system settings and without emulating their presses.
The issue with your AHK script is that Windows system windows (such as file save dialogs) have a special input handling mechanism and don’t always respond to standard AutoHotkey messages. In system windows, direct calls to system APIs via DllCall are often required instead of using SendMessage.
Contents
- Main Issue
- Solution 1: Using DllCall with LoadKeyboardLayout
- Solution 2: Complete Replacement of System Hotkeys
- Solution 3: Running Script as Administrator
- Full Working Script
- System Setup for Single Switching Method
- Troubleshooting Recommendations
Main Issue
Windows system windows use their own input handling mechanism that ignores standard AutoHotkey messages. Your SendMessage, 0x50 method works in regular applications but not in system dialogs because:
- System windows have limited access to external messages
- They use their own input handler
- Lower-level Windows API calls are required
Solution 1: Using DllCall with LoadKeyboardLayout
The most reliable method is to directly call system functions through DllCall:
~LCtrl up::
If (A_PriorKey = "LControl") {
SetKeyboardLayout(0x0409) ; English (US)
}
return
~RCtrl up::
If (A_PriorKey = "RControl") {
SetKeyboardLayout(0x0419) ; Russian
}
return
SetKeyboardLayout(LocaleID) {
; Load keyboard layout
hKL := DllCall("LoadKeyboardLayout", "Str", Format("{:08X}", LocaleID), "UInt", 0x00000001)
; Set layout for current thread
DllCall("ActivateKeyboardLayout", "UInt", hKL, "UInt", 0x00000000)
; Update system parameters
VarSetCapacity(LAN, 8, 0)
NumPut(LocaleID, LAN, 0, "UInt")
NumPut(LocaleID, LAN, 4, "UInt")
DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &LAN, "UInt", 0x0002)
}
This method works in most system windows since it uses direct calls to Windows system functions.
Solution 2: Complete Replacement of System Hotkeys
To completely replace system hotkeys, you need to:
- Disable standard switching in Windows settings
- Create your own handler that will work everywhere
; Complete replacement of system hotkeys
#NoEnv
#SingleInstance Force
SetBatchLines, -1
; Disable standard switching (run as administrator)
OnExit, ExitSub
ExitSub:
DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &OldLAN, "UInt", 0x0002)
ExitApp
; Save current settings
VarSetCapacity(OldLAN, 8, 0)
DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &OldLAN, "UInt", 0x0002)
; Hotkeys for switching
~LCtrl up::
If (A_PriorKey = "LControl") {
SetKeyboardLayout(0x0409) ; English
}
return
~RCtrl up::
If (A_PriorKey = "RControl") {
SetKeyboardLayout(0x0419) ; Russian
}
return
Solution 3: Running Script as Administrator
Some system windows require elevated privileges:
- Create a shortcut for your script
- Open the shortcut properties
- Go to the “Compatibility” tab
- Check “Run this program as an administrator”
- Apply changes
Full Working Script
#NoEnv
#SingleInstance Force
SetBatchLines, -1
; Set script to work with all windows
#InstallKeybdHook
#UseHook On
; Function to set keyboard layout
SetKeyboardLayout(LocaleID) {
try {
; Try through ActivateKeyboardLayout first
hKL := DllCall("LoadKeyboardLayout", "Str", Format("{:08X}", LocaleID), "UInt", 0x00000001)
DllCall("ActivateKeyboardLayout", "UInt", hKL, "UInt", 0x00000000)
; Update system parameters
VarSetCapacity(LAN, 8, 0)
NumPut(LocaleID, LAN, 0, "UInt")
NumPut(LocaleID, LAN, 4, "UInt")
DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &LAN, "UInt", 0x0002)
; Additional attempt for stubborn windows
PostMessage, 0x50, 0, % (LocaleID << 16) | LocaleID, , A
}
return
}
; Hotkeys
~LCtrl up::
If (A_PriorKey = "LControl") {
SetKeyboardLayout(0x0409) ; English (US)
ToolTip, English Layout, 1000
}
return
~RCtrl up::
If (A_PriorKey = "RControl") {
SetKeyboardLayout(0x0419) ; Russian
ToolTip, Russian Layout, 1000
}
return
; Remove tooltip after 1 second
SetTimer, RemoveToolTip, -1000
RemoveToolTip:
ToolTip
return
System Setup for Single Switching Method
To leave only your method in the system:
- Open Settings → Time & Language → Language
- Click on Language options
- In the Keyboards section, click Advanced keyboard settings
- In the Text services and input languages window, select the Advanced Key Settings tab
- Set None for “Switch Input Language”
- Apply changes and restart your computer
Troubleshooting Recommendations
If the script still doesn’t work:
- Check language codes: Make sure 0x0409 and 0x0419 correspond to your languages
- Add debug information:autohotkey
~LCtrl up:: If (A_PriorKey = "LControl") { MsgBox, Switching to English SetKeyboardLayout(0x0409) } return - Try alternative language codes:
- English: 0x0409 (US), 0x0809 (UK)
- Russian: 0x0419, 0x0422 (Ukraine)
- Try using WinAPI directly:autohotkey
SetKeyboardLayout(LocaleID) { static hKL := {} if !hKL.HasKey(LocaleID) { hKL[LocaleID] := DllCall("LoadKeyboardLayout", "Str", Format("{:08X}", LocaleID), "UInt", 1) } return DllCall("ActivateKeyboardLayout", "UInt", hKL[LocaleID], "UInt", 0) }
Important: Some system windows may require restarting after changing language settings. Also make sure your script is running as administrator for maximum compatibility.
Sources
- AutoHotkey Community - Switch keyboard layout
- AutoHotkey Community - How to change keyboard language layout
- Stack Overflow - AutoHotkey: Disable Ctrl+Shift
- Super User - Setting different keys for switching between keyboard layouts
- AutoHotkey Community - Keyboard layout switcher for many layouts
Conclusion
The main issues with switching keyboard layouts in Windows system windows are resolved by using direct WinAPI calls through DllCall instead of standard AutoHotkey messages. Key points:
- Use
DllCall("LoadKeyboardLayout")andDllCall("ActivateKeyboardLayout")for reliable operation - Run the script as administrator for access to all system windows
- Disable standard keyboard shortcuts in Windows settings
- For maximum compatibility, use a combination of different methods
The provided script should work in all types of windows, including system dialogs, and will allow you to have a single method for switching languages without using external programs.