Skip to content

Instantly share code, notes, and snippets.

@joseph-sch
Created February 17, 2025 06:46
Show Gist options
  • Save joseph-sch/830b0c3f8e94b43414ea538195461724 to your computer and use it in GitHub Desktop.
Save joseph-sch/830b0c3f8e94b43414ea538195461724 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")
}
@joseph-sch
Copy link
Author

joseph-sch commented Feb 17, 2025

@joseph-sch
Copy link
Author

ChatGPT's o3-mini's comments:

The script you're using seems mostly fine for its purposes, but there are a few points to consider.
It uses a timer to check the keyboard layout, but using "A" with WinGetPos might not work properly with UWP apps since they don’t follow the regular window handle approach. Also, the tooltip shows "No window in focus" before checking hWndFocus, which could be misleading if there’s a focus issue.
Other than that, the overall flow seems solid, though I might suggest making sure the timer’s interval is suitable for performance.
It seems like there could be an issue with mixing hWndFocus and the active window for position calculations. hWndFocus is used to get the proper window handle, but then using the active window in WinGetPos may cause discrepancies, especially with UWP apps.
Using the same handle from GetFocusedWindowHandle consistently might solve this issue. Also, I notice a minor detail with GetWindowThreadProcessId, where the process ID isn't needed, which is fine.
Overall, common themes are consistent logic and alignment with window handles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment