Created
April 17, 2026 20:13
-
-
Save DJm00n/0a28b2a05cde27ffe3e745633ff119e4 to your computer and use it in GitHub Desktop.
Returns a BCP-47 language tag (e.g. "en-US", "uk-UA", "jv-Java") for the given HKL (keyboard layout handle).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <windows.h> | |
| #include <string> | |
| #include <vector> | |
| /* | |
| * Returns a BCP-47 language tag (e.g. "en-US", "uk-UA", "jv-Java") | |
| * for the given HKL (keyboard layout handle). | |
| * | |
| * WM_INPUTLANGCHANGE provides HKL, whose low word is LANGID. However, | |
| * for transient keyboard layouts (LOCALE_TRANSIENT_KEYBOARD*), LANGID | |
| * does not map correctly via LCID APIs. | |
| * | |
| * In such cases, the function resolves the tag via: | |
| * HKCU\Control Panel\International\User Profile | |
| * matching TransientLangId → language tag. | |
| * | |
| * Falls back to LCIDToLocaleName for regular LANGIDs. | |
| * | |
| * This matches the approach used in WinForms and recommended by Microsoft. | |
| */ | |
| std::wstring GetLanguageTagFromHKL(HKL hkl) | |
| { | |
| LANGID langId = LOWORD((ULONG_PTR)hkl); | |
| if (langId == LOCALE_TRANSIENT_KEYBOARD1 || | |
| langId == LOCALE_TRANSIENT_KEYBOARD2 || | |
| langId == LOCALE_TRANSIENT_KEYBOARD3 || | |
| langId == LOCALE_TRANSIENT_KEYBOARD4) | |
| { | |
| HKEY key; | |
| if (RegOpenKeyExW(HKEY_CURRENT_USER, | |
| L"Control Panel\\International\\User Profile", | |
| 0, KEY_READ, &key) == ERROR_SUCCESS) | |
| { | |
| DWORD size = 0; | |
| if (RegGetValueW(key, nullptr, L"Languages", | |
| RRF_RT_REG_MULTI_SZ, nullptr, nullptr, &size) == ERROR_SUCCESS) | |
| { | |
| std::vector<wchar_t> buf(size / sizeof(wchar_t)); | |
| if (RegGetValueW(key, nullptr, L"Languages", | |
| RRF_RT_REG_MULTI_SZ, nullptr, | |
| buf.data(), &size) == ERROR_SUCCESS) | |
| { | |
| for (const wchar_t* p = buf.data(); *p; p += wcslen(p) + 1) | |
| { | |
| HKEY sub = nullptr; | |
| DWORD val, cb = sizeof(val); | |
| if (RegOpenKeyExW(key, p, 0, KEY_READ, &sub) == ERROR_SUCCESS && | |
| RegGetValueW(sub, nullptr, L"TransientLangId", | |
| RRF_RT_REG_DWORD, nullptr, | |
| &val, &cb) == ERROR_SUCCESS && | |
| (LANGID)val == langId) | |
| { | |
| RegCloseKey(sub); | |
| RegCloseKey(key); | |
| return p; | |
| } | |
| if (sub) RegCloseKey(sub); | |
| } | |
| } | |
| } | |
| RegCloseKey(key); | |
| } | |
| } | |
| wchar_t locale[LOCALE_NAME_MAX_LENGTH]; | |
| return LCIDToLocaleName(MAKELCID(langId, SORT_DEFAULT), | |
| locale, | |
| ARRAYSIZE(locale), | |
| 0) | |
| ? locale | |
| : L""; | |
| } |
DJm00n
commented
Apr 17, 2026
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment