-
-
Save joseph-sch/830b0c3f8e94b43414ea538195461724 to your computer and use it in GitHub Desktop.
#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") | |
} |
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.
GetGUIThreadInfo
DLL call withidThread
set to 0 ("If this parameter is NULL, the function returns information for the foreground thread.) & fetchedhwndFocus
field in theGUITHREADINFO
structure, as per this comment on Connecting UWP apps hosted byApplicationFrameHost
to their real processesGetForegroundWindow
would also work