Skip to content

Instantly share code, notes, and snippets.

@DJm00n
Created April 17, 2026 20:13
Show Gist options
  • Select an option

  • Save DJm00n/0a28b2a05cde27ffe3e745633ff119e4 to your computer and use it in GitHub Desktop.

Select an option

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).
#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

DJm00n commented Apr 17, 2026

Copy link
Copy Markdown
Author
case WM_INPUTLANGCHANGE:
{
    HKL hkl = (HKL)lParam;

    std::wstring tag = GetLanguageTagFromHKL(hkl);
    // → "en-US", "uk-UA", "jv-Java", etc.
}
break;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment