Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BCP-47 for keyboard language on Windows #20

Open
PastaJ36 opened this issue Jun 24, 2020 · 6 comments
Open

BCP-47 for keyboard language on Windows #20

PastaJ36 opened this issue Jun 24, 2020 · 6 comments

Comments

@PastaJ36
Copy link

Thanks for this library, it makes cross platform keyboard stuff a lot easier.

I was wondering if it's possible to switch to CurrentInputMethodLanguageTag. It's a little painful to write the conversion from the hex identifiers.

Is there anything holding back from using this API? I'm not too familiar with the WinRT API's. Thanks!

@DJm00n
Copy link
Contributor

DJm00n commented Apr 12, 2022

You can easily convert HKL/LANG/LCID to language tag with a call to LCIDToLocaleName.

HKL hkl = GetKeyboardLayout();
WORD lgid = LOWORD(hkl);
DWORD lcid = MAKELCID(lgid, SORT_DEFAULT);

// Locale names should follow the BCP47 recommendations and typically
// include language, script, regional variant, and perhaps additional specifiers.
// BCP47 allows some variation, eg: en-US is preferred to en-Latn-US.
WCHAR localeName[LOCALE_NAME_MAX_LENGTH];
LCIDToLocaleName(lcid, localeName, LOCALE_NAME_MAX_LENGTH, 0);

WCHAR name[255];
GetLocaleInfoEx(localeName, LOCALE_SENGLISHDISPLAYNAME, name, 255); // Display name (language + country/region usually) in English, eg "German (Germany)"

WCHAR lang[9];
GetLocaleInfoEx(localeName, LOCALE_SISO639LANGNAME2, lang, 9); // 3 character ISO abbreviated language name, eg "eng"

@beldenfox
Copy link

Just ran across this same problem and did some test code. Turns out CurrentInputMethodLanguageTag isn't what you want and the sample code @DJm00n provided isn't either. The Microsoft docs are really not helpful here.

On my Windows 11 system I'm running English with three keyboards installed (U.S. English, French, and German). No matter which keyboard I've chosen the LANGID in the HKL is English and CurrentInputMethodLanguageTag is always en-US. The reliable way to track the keyboard language is to call GetKeyboardLayoutName and parse the resulting hex codes. The LANGID in the HKL only changes if I install another language (say, Hebrew or Japanese) and switch to one of those keyboard layouts.

@DJm00n
Copy link
Contributor

DJm00n commented Nov 1, 2023

@beldenfox you're right LOWORD(hkl) - will return input language, and it will not distinguish between several installed keyboards under this language. If you need to extract keyboard layout id then GetKeyboardLayoutName() will help. Or you can try to parse HKL by yourself to extract keyboard layout id from it like I did here.

But please, do not try to parse value returned from GetKeyboardLayoutName() - just threat it as KLID (keyboard layout id) string. This is because newer keyboards does not have associated LCID (LCIDs are obsolete and not assigned anymore) and have 0x0c00 (LOCALE_CUSTOM_USER_DEFAULT) value in lower word of their KLID. Here is the list of keyboard layouts with their KLIDs.

If you need to get display name of the keyboard layout then you can get it from registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\{KLID}. This is documented here and implemented here.

Get-WinUserLanguageList PowerShell command can help you understand how this works in modern Windows:
image

@beldenfox
Copy link

@DJm00n Thanks for writing all this up! I was specifically tasked with querying the current keyboard layout and mapping that to an ISO language code (like "en" or "fr"). It looks like there's no good way of doing that without using undocumented behavior. I will push back on the request. In the end I suspect what the client really wants to know if any right-to-left keyboard layouts are installed in order to enable some specific shortcuts. I should be able to determine that by looking at the HKL list.

@DJm00n
Copy link
Contributor

DJm00n commented Nov 1, 2023

@beldenfox AFAIK you can only install Arabic keyboards under user language with corresponding ScriptName (seen on my PowerShell screenshot):

image

So to detect RTL language you can do something like this:

HKL hkl = GetKeyboardLayout();

WCHAR localeName[LOCALE_NAME_MAX_LENGTH];
LCIDToLocaleName(MAKELCID(LOWORD(hkl), SORT_DEFAULT), localeName, LOCALE_NAME_MAX_LENGTH, 0);

DWORD value;
GetLocaleInfoEx(localeName, LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, (LPWSTR)&value, sizeof(value) / sizeof(WCHAR));
if (value == 1) // see possible values here: https://learn.microsoft.com/windows/win32/intl/locale-ireadinglayout
   return true;

@beldenfox
Copy link

@DJm00n I dropped it into my test app and verified that it works correctly for Hebrew on my Win 11 system. So thanks again, you just saved me a lot of work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants