Skip to content

Instantly share code, notes, and snippets.

@j1lecks
Forked from joseph-sch/KeyboardLanguage.ahk
Created February 17, 2025 06:57
Show Gist options
  • Select an option

  • Save j1lecks/af41ceb4558136f2e3f3ed3fcf265419 to your computer and use it in GitHub Desktop.

Select an option

Save j1lecks/af41ceb4558136f2e3f3ed3fcf265419 to your computer and use it in GitHub Desktop.
For multi-language Windows users, make the keyboard choice prominent when it changes
#Requires AutoHotkey v2.0
#SingleInstance Force
global popup, langText, guiCreated := false, prevLangID := 0
; Check the keyboard layout every 200ms
SetTimer(CheckKeyboardLayout, 200)
CheckKeyboardLayout() {
global popup, langText, guiCreated, prevLangID
; Get focused window handle
hwndFocus := GetFocusedWindowHandle()
if (!hwndFocus) {
ToolTip("No window in focus")
SetTimer(() => ToolTip(""), -1000)
return
}
; Retrieve the language ID of the keyboard layout for the focused window
langID := GetKeyboardLangID(hwndFocus)
; Exit if the language hasn't changed
if (langID = prevLangID)
return
; Store the new language ID
prevLangID := langID
; Get the middle of the active window
try {
WinGetPos(&x, &y, &w, &h, "A")
x := x + w // 2
y := y + h // 2
} catch as e {
x := 0
y := 0
}
; If it doesn't exist, create the GUI object
if (!guiCreated) {
popup := Gui("+AlwaysOnTop -Caption +ToolWindow")
popup.SetFont("s32 Bold cFFFFFF", "Arial")
langText := popup.Add("Text", "Center", LangIDToLabel(langID).label)
guiCreated := true
}
; Set the language text and background color
langText.Text := LangIDToLabel(langID).label
popup.BackColor := LangIDToLabel(langID).color
; Show the popup at the chosen position
popup.Show("x" x " y" y " NoActivate")
; Hide the popup after 1.5 second
SetTimer(HideLayoutGui, -1500)
}
GetKeyboardLangID(hWnd) {
; Retrieve the thread ID for the window
threadID := DllCall("GetWindowThreadProcessId", "Ptr", hWnd, "Ptr", 0, "UInt")
; Retrieve the current keyboard layout for that thread
currentLayout := DllCall("GetKeyboardLayout", "UInt", threadID, "Ptr")
; Extract the language ID (low word)
langID := currentLayout & 0xFFFF
; Return the language ID
return langID
}
LangIDToLabel(langID) {
; Determine language code and background color
if (langID = 0x0409) {
; English (US International)
label := "ENG"
color := "797300"
} else if (langID = 0x040C) {
; French (US International)
label := "FRA"
color := "090fc7"
} else if (langID = 0x040D) {
; Hebrew (Standard)
label := "HEB"
color := "af0101"
} else {
label := Format("0x{:04X}", langID)
color := "FFFFFF" ; White fallback
}
; Return an object with both lang and color
return { label: label, color: color }
}
HideLayoutGui() {
global popup
popup.Hide()
}
GetFocusedWindowHandle() {
info := Buffer(72, 0)
NumPut("UInt", 72, info) ; Set the cbSize member to 72
res := DllCall("GetGUIThreadInfo", "UInt", 0, "Ptr", info.Ptr)
if (!res)
return 0
return NumGet(info, 16, "Ptr")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment