Different keyboard layouts in AutoHotKey

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 05:28

In Polish, there are two keyboard layouts for Windows: the programmer's layout and the 214 layout.
I use the 214 layout, but it's missing a few characters and letters.

I wrote the following script:

Code: Select all

Ralt & ,::[
RAlt & .::]
RAlt & a::Ą
RAlt & e::Ę
RAlt & c::Ć
RAlt & j::Ń
RAlt & o::Ó
RAlt & s::Ś
RAlt & y::Ż
RAlt & z::Ż
RAlt & x::Ź
RAlt & -::|
RAlt & ó::Send('{U+005E}')
Missing characters work on 214 layout.
The problem is that the script also works for the programmer's keyboard layout and blocks some letters.
How do I make the script recognize different keyboard layouts and only work for 214 layout and not work for the programmer's layout?
Last edited by Ragnar on 09 Dec 2024, 09:23, edited 1 time in total.
Reason: code tags; moved from Scripts and Functions (v2) to Ask for Help (v2)

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 09:37

Welcome to this AutoHotkey forum!

You may be able to get the layout and then use #HotIf to restrict your hotkeys to that layout.

Instead of RAlt & ..., you can do it the following way, usually better.

Code: Select all

>!,::[

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 10:05

Thanks for the quick response.

Unfortunately >!,::[ doesn't work in AHK v2.
And how exactly do I apply #HotIf to a selected keyboard layout?

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 11:08

Code: Select all

#Requires AutoHotkey 2
#HotIf GetInputLangName(GetInputLangID()) = 'English'
<^>!,::SendText '['
#HotIf GetInputLangName(GetInputLangID()) = 'French'
<^>!,::SendText 'f'
#HotIf

GetInputLangID(hWnd := '') {
 ; https://www.autohotkey.com/boards/viewtopic.php?f=82&t=124723&p=554340#p554340
 (!hWnd) && hWnd := WinActive('A'), childPID := ''
 If WinGetProcessName(hWnd) = 'ApplicationFrameHost.exe' {
  pid := WinGetPID(hWnd)
  For ctl in WinGetControls(hWnd)
   DllCall('GetWindowThreadProcessId', 'Ptr', ctl, 'UIntP', childPID)
  Until childPID != pid
  DetectHiddenWindows True
  hWnd := WinExist('ahk_pid' childPID)
 }
 threadId := DllCall('GetWindowThreadProcessId', 'Ptr', hWnd, 'UInt', 0)
 lyt      := DllCall('GetKeyboardLayout', 'Ptr', threadId, 'UInt')
 Return langID := Format('{:#x}', lyt & 0x3FFF)
}

GetInputLangName(langId)  {
 Static LOCALE_SENGLANGUAGE := 0x1001
 charCount := DllCall('GetLocaleInfo', 'UInt', langId, 'UInt', LOCALE_SENGLANGUAGE, 'UInt', 0, 'UInt', 0)
 localeSig := Buffer(size := charCount << 1)
 DllCall('GetLocaleInfo', 'UInt', langId, 'UInt', LOCALE_SENGLANGUAGE, 'Ptr', localeSig, 'UInt', size)
 Return StrGet(localeSig)
}

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 13:16

SUPER!!!!!!!
The script works great for English and French.
You can also change it to Polish and German, for example, and it works.

But Polish has two keyboard layouts - 214 and programmer (that's what they're called in Polish, I don't know what they're called in English).
Do you know what to enter so that the script can distinguish between these two keyboard layouts?

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 13:24

You can display the language name after you have switched to that keyboard. Alternatively, you could display the language ID and use that.

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 14:17

After switching to a given keyboard layout, it shows POL 214 and POL PLP respectively.
Is that what I should use?
And where can I find the language ID for each keyboard layout?

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 14:30

Sure, try it. I mean that you can use the script to display the language name to you, so that you can then adjust your script accordingly.

Below are some codes. I do not know whether this list is comprehensive.

https://www.autohotkey.com/docs/v2/misc/Languages.htm

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 14:48

It doesn't work.
I've tried different methods and nothing.
Can you give an example for French, for example?
I'm trying this, but it doesn't work:

#HotIf GetInputLangName(GetInputLangID()) = '100C'
<^>!,::SendText '['

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 15:17

Getting the input language name would get you the language name rather than the ID. Since you found language names that you need, I would go with those.

Code: Select all

; This script shows the current language name
#Requires AutoHotkey 2
MsgBox A_Clipboard := GetInputLangName(GetInputLangID()), 'Language name', 'Iconi'

GetInputLangID(hWnd := '') {
 ; https://www.autohotkey.com/boards/viewtopic.php?f=82&t=124723&p=554340#p554340
 (!hWnd) && hWnd := WinActive('A'), childPID := ''
 If WinGetProcessName(hWnd) = 'ApplicationFrameHost.exe' {
  pid := WinGetPID(hWnd)
  For ctl in WinGetControls(hWnd)
   DllCall('GetWindowThreadProcessId', 'Ptr', ctl, 'UIntP', childPID)
  Until childPID != pid
  DetectHiddenWindows True
  hWnd := WinExist('ahk_pid' childPID)
 }
 threadId := DllCall('GetWindowThreadProcessId', 'Ptr', hWnd, 'UInt', 0)
 lyt      := DllCall('GetKeyboardLayout', 'Ptr', threadId, 'UInt')
 Return langID := Format('{:#x}', lyt & 0x3FFF)
}

GetInputLangName(langId)  {
 Static LOCALE_SENGLANGUAGE := 0x1001
 charCount := DllCall('GetLocaleInfo', 'UInt', langId, 'UInt', LOCALE_SENGLANGUAGE, 'UInt', 0, 'UInt', 0)
 localeSig := Buffer(size := charCount << 1)
 DllCall('GetLocaleInfo', 'UInt', langId, 'UInt', LOCALE_SENGLANGUAGE, 'Ptr', localeSig, 'UInt', size)
 Return StrGet(localeSig)
}

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 15:31

This script for each Polish keyboard layout shows only: Polish.
Unfortunately I still don't know what the two different Polish keyboard layouts are called.
And how do I apply an ID to the script below, instead of e.g. 'French' or 'English'?

Code: Select all

#Requires AutoHotkey 2
#HotIf GetInputLangName(GetInputLangID()) = 'English'
<^>!,::SendText '['
#HotIf GetInputLangName(GetInputLangID()) = 'French'
<^>!,::SendText 'f'
#HotIf

GetInputLangID(hWnd := '') {
 ; https://www.autohotkey.com/boards/viewtopic.php?f=82&t=124723&p=554340#p554340
 (!hWnd) && hWnd := WinActive('A'), childPID := ''
 If WinGetProcessName(hWnd) = 'ApplicationFrameHost.exe' {
  pid := WinGetPID(hWnd)
  For ctl in WinGetControls(hWnd)
   DllCall('GetWindowThreadProcessId', 'Ptr', ctl, 'UIntP', childPID)
  Until childPID != pid
  DetectHiddenWindows True
  hWnd := WinExist('ahk_pid' childPID)
 }
 threadId := DllCall('GetWindowThreadProcessId', 'Ptr', hWnd, 'UInt', 0)
 l
Last edited by Ragnar on 09 Dec 2024, 15:59, edited 1 time in total.
Reason: code tags

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 16:23

Perhaps:

Code: Select all

#Requires AutoHotkey 2
polishProg := 0x0415
polish214  := 0x10415
us         := 0x0409
#HotIf GetInputLangID() = polishProg
<^>!,::SendText '['
#HotIf GetInputLangID() = polish214
<^>!,::SendText '214214214'
#HotIf GetInputLangID() = us
<^>!,::SendText 'ususususus'
#HotIf

GetInputLangID(hWnd := '') {
 ; https://www.autohotkey.com/boards/viewtopic.php?f=82&t=124723&p=554340#p554340
 (!hWnd) && hWnd := WinActive('A'), childPID := ''
 If WinGetProcessName(hWnd) = 'ApplicationFrameHost.exe' {
  pid := WinGetPID(hWnd)
  For ctl in WinGetControls(hWnd)
   DllCall('GetWindowThreadProcessId', 'Ptr', ctl, 'UIntP', childPID)
  Until childPID != pid
  DetectHiddenWindows True
  hWnd := WinExist('ahk_pid' childPID)
 }
 threadId := DllCall('GetWindowThreadProcessId', 'Ptr', hWnd, 'UInt', 0)
 lyt      := DllCall('GetKeyboardLayout', 'Ptr', threadId, 'UInt')
 Return langID := Format('{:#x}', lyt & 0x3FFF)
}

GetInputLangName(langId)  {
 Static LOCALE_SENGLANGUAGE := 0x1001
 charCount := DllCall('GetLocaleInfo', 'UInt', langId, 'UInt', LOCALE_SENGLANGUAGE, 'UInt', 0, 'UInt', 0)
 localeSig := Buffer(size := charCount << 1)
 DllCall('GetLocaleInfo', 'UInt', langId, 'UInt', LOCALE_SENGLANGUAGE, 'Ptr', localeSig, 'UInt', size)
 Return StrGet(localeSig)
}

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 09 Dec 2024, 16:34

This script for each Polish keyboard layout shows the same ID: 0x415.

I'll try, but how do I use the ID for the script above, instead of e.g. 'French' or 'English'?

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 09 Dec 2024, 16:46

I have posted a new script above. You could try it. That is my only thought! Others may have more information for you.

User avatar
Seven0528
Posts: 547
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: Different keyboard layouts in AutoHotKey

Post by Seven0528 » 10 Dec 2024, 01:42

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
#HotIf (getActiveWindowKeyboardLayout() & 0xFFFFFFFF == 0xF0070415)
F7::  {
    msgbox("Polish (214)")
}
#HotIf (getActiveWindowKeyboardLayout() & 0xFFFFFFFF == 0x04150415)
F7::  {
    msgbox("Polish (Programmers)")
}
#HotIf
getActiveWindowKeyboardLayout()    {
    hKL := 0
    if (hWnd := winExist("A"))    {
        idThread    := dllCall("User32.dll\GetWindowThreadProcessId", "Ptr",hWnd, "Ptr",0, "UInt")
        hKL         := dllCall("User32.dll\GetKeyboardLayout", "UInt",idThread, "Ptr")
    }
    return hKL
}
 As you can see from the existing code, only the lower bits of the hKL are being extracted for evaluation.
I don’t even agree with the approach of extracting langID by masking with 0x3FFF (I believe treating the entire lower WORD as langID by using 0xFFFF is more accurate).
However, in this case, relying on langID alone is insufficient.
Since it is the same language, the difference in the upper WORD, the deviceID, must be compared.
In that case, it would be better to compare the entire hKL instead.
Details related to language layouts like this are not documented.

The code I provided is not entirely precise, but it should be able to distinguish keyboard layouts in most environments.
Lastly, the reason for masking hKL with 0xFFFFFFFF for comparison is due to differences in the return values between 32-bit and 64-bit environments.
In this case, the Polish (214) keyboard would display different return values for each.


 +)

Code: Select all

#define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p))

Code: Select all

msgbox(format("0x{:X}", 0x3F << 10 | 0x03FF)) ;  0xFFFF
MAKELANGID macro (winnt.h)
I was personally curious, so I just calculated it, and it seems that the maximum value a langID can have is 0xFFFF.
Last edited by Seven0528 on 11 Dec 2024, 18:41, edited 1 time in total.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 10 Dec 2024, 04:24

Great, your code works wonderfully!!!
It recognizes Polish keyboard layouts.
I modified it for my needs and it works.
Check if I did it right:

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
#HotIf (getActiveWindowKeyboardLayout() & 0xFFFFFFFF == 0xF0070415)

<^>!,::SendText '['
<^>!.::SendText ']'
<^>!a::SendText 'Ą'
<^>!e::SendText 'Ę'
<^>!c::SendText 'Ć'
<^>!j::SendText 'Ń'
<^>!o::SendText 'Ó'
<^>!s::SendText 'Ś'
<^>!y::SendText 'Ż'
<^>!z::SendText 'Ż'
<^>!x::SendText 'Ź'
<^>!-::SendText '|'
<^>!ó::Send('{U+005E}')

#HotIf (getActiveWindowKeyboardLayout() & 0xFFFFFFFF == 0x04150415)

#HotIf
getActiveWindowKeyboardLayout()    {
    hKL := 0
    if (hWnd := winExist("A"))    {
        idThread    := dllCall("User32.dll\GetWindowThreadProcessId", "Ptr",hWnd, "Ptr",0, "UInt")
        hKL         := dllCall("User32.dll\GetKeyboardLayout", "UInt",idThread, "Ptr")
    }
    return hKL
}

I understand that for example for German it will be:
0xFFFFFFFF == 0x04070407
Last edited by Ragnar on 10 Dec 2024, 04:31, edited 1 time in total.
Reason: code tags

User avatar
Seven0528
Posts: 547
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: Different keyboard layouts in AutoHotKey

Post by Seven0528 » 10 Dec 2024, 05:16

 Sure. It seems fine.
If you're curious about the current value of hKL, please execute the following code.

Code: Select all

#HotIf
F7::msgBox(format("0x{:08X}", getActiveWindowKeyboardLayout() & 0xFFFFFFFF)) ;  In Korean, this would be represented as 0x04120412
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.

heinzeb
Posts: 8
Joined: 09 Dec 2024, 05:20

Re: Different keyboard layouts in AutoHotKey

Post by heinzeb » 10 Dec 2024, 05:49

Brilliant!!!!!
Everything works as it should.

I also fixed:
<^>!ó::Send('{U+005E}')
to:
<^>!ó::SendText '^'

And it works fine too.
THX

User avatar
mikeyww
Posts: 29718
Joined: 09 Sep 2014, 18:38

Re: Different keyboard layouts in AutoHotKey

Post by mikeyww » 10 Dec 2024, 08:01

Beautiful!

Post Reply

Return to “Ask for Help (v2)”