Cadoiz
Cadoiz

Reputation: 1676

How do you get the current keyboard layout (language setting) in AutoHotkey

I would like to have the possibility to let my script be sensitive to the current keyboard-layout. Something like

#If %keyboardLang% == en-US
    a::
    MsgBox, I pressed a on an english keyboard
    return

#If %keyboardLang% == de-US
    a::
    MsgBox, I pressed a on an german keyboard
    return

Upvotes: 1

Views: 1801

Answers (3)

YellowAfterlife
YellowAfterlife

Reputation: 3192

To those whom it may concern, AHK2.x version:

GetCurrentKeyboardLayout() {
    hwnd := DllCall("GetForegroundWindow")
    if hwnd == 0
        return 0
    threadID := DllCall("GetWindowThreadProcessId", "UInt", hwnd, "UInt", 0)
    return DllCall("GetKeyboardLayout", "UInt", threadID, "UInt")
}

Upvotes: 2

anonymous1184
anonymous1184

Reputation: 98

@Cadoiz pointed you in the right direction. According to MSDN the value returned is in fact two:

The name of the input locale identifier to load. This name is a string composed of the hexadecimal value of the Language Identifier (low word) and a device identifier (high word). For example, U.S. English has a language identifier of 0x0409, so the primary U.S. English layout is named "00000409". Variants of U.S. English layout -- (such as the Dvorak layout) are named "00010409", "00020409", and so on.

So there can be lots of combinations, what you need is the second value. So I came up with this:

F1::
    MsgBox % "Keyboard layout: " GetLayout(Language := "") "`n"
        . "Keyboard language identifier: " Language
return

#if GetLayout(Language := "") = "gr"
    a::MsgBox 0x40, Layout, % "Current layout: " Language
#if GetLayout(Language := "") = "us"
    a::MsgBox 0x40, Layout, % "Current layout: " Language
#if

GetLayout(ByRef Language := "")
{
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "Ptr",hWnd, "Ptr",0)
    KLID := DllCall("GetKeyboardLayout", "Ptr",ThreadID, "Ptr")
    KLID := Format("0x{:x}", KLID)
    Lang := "0x" A_Language
    Locale := KLID & Lang
    Info := KeyboardInfo()
    return Info.Layout[Locale], Language := Info.Language[Locale]
}

KeyboardInfo()
{
    static Out := {}
    if Out.Count()
        return Out
    Layout := {}
    loop reg, HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout\DosKeybCodes
    {
        RegRead Data
        Code := "0x" A_LoopRegName
        Layout[Code + 0] := Data
    }
    Language := {}
    loop reg, HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layouts, KVR
    {
        RegRead Data
        if ErrorLevel
            Name := "0x" A_LoopRegName
        else if (A_LoopRegName = "Layout Text")
            Language[Name + 0] := Data
    }
    return Out := { "Layout":Layout, "Language":Language }
}

Upvotes: 3

Cadoiz
Cadoiz

Reputation: 1676

Windows allows custom language settings independently for each window. If you don't care, you can just use the active window. You can retrieve a Language ID with this script (some examples given):

SetFormat, Integer, H
WinGet, WinID,, A ;get the active Window
ThreadID:=DllCall("GetWindowThreadProcessId", "UInt", WinID, "UInt", 0)
InputLocaleID:=DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")

if (InputLocaleID == 0x4070407)
    languageName = german
else if (InputLocaleID == 0xF0010409)
    languageName = US international
else if (InputLocaleID == 0x4090409 )
    languageName = US english

MsgBox, The language of the active window is %languageName%. (code: %InputLocaleID%)

Upvotes: 1

Related Questions