开发者

Force GetKeyNameText to english

开发者 https://www.devze.com 2023-04-04 15:49 出处:网络
The Win32 function GetKeyNameText will provide the name of keyboard keys in the current input locale.

The Win32 function GetKeyNameText will provide the name of keyboard keys in the current input locale.

From MSDN:

The key name is translated according to the layout of the currently installed keyboard, thus the function may give different results for different input locales.

Is it possible to force the input locale for a short amount of time? Or is there another alternative to GetKeyNameText that will always return the name in Engl开发者_运维问答ish?


Update: This answer does not work. It actually modifies the keyboard settings of the user. This appear to be a behavior change between Windows versions.

CString csLangId;
csLangId.Format( L"%08X", MAKELANGID( LANG_INVARIANT, SUBLANG_NEUTRAL ) );
HKL hLocale = LoadKeyboardLayout( (LPCTSTR)csLangId, KLF_ACTIVATE );
HKL hPrevious = ActivateKeyboardLayout( hLocale, KLF_SETFORPROCESS );

// Call GetKeyNameText

ActivateKeyboardLayout( hPrevious, KLF_SETFORPROCESS );
UnloadKeyboardLayout( hLocale );


WARNING: GetKeyNameText is broken (it returns wrong A-Z key names for non-english keyboard layouts since it uses MapVirtualKey with MAPVK_VK_TO_CHAR that is broken), keyboard layout dlls pKeyNames and pKeyNamesExt text is bugged and outdated. I cannot recommend dealing with this stuff at all. :)

If you're really-really want to get this info - then you can load and parse it manually from keyboard layout dll file (kbdus.dll, kbdger.dll etc).

There is a bunch of undocumented stuff involved:

  • In order to get proper keyboard layout dll file name first you need to convert HKL to KLID string. You can do this via such code:
// Returns KLID string of size KL_NAMELENGTH
// Same as GetKeyboardLayoutName but for any HKL
// https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values
BOOL GetKLIDFromHKL(HKL hkl, _Out_writes_(KL_NAMELENGTH) LPWSTR pwszKLID)
{
    bool succeded = false;

    if ((HIWORD(hkl) & 0xf000) == 0xf000) // deviceId contains layoutId
    {
        WORD layoutId = HIWORD(hkl) & 0x0fff;

        HKEY key;
        CHECK_EQ(::RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", &key), ERROR_SUCCESS);

        DWORD index = 0;
        while (::RegEnumKeyW(key, index, pwszKLID, KL_NAMELENGTH) == ERROR_SUCCESS)
        {
            WCHAR layoutIdBuffer[MAX_PATH] = {};
            DWORD layoutIdBufferSize = sizeof(layoutIdBuffer);
            if (::RegGetValueW(key, pwszKLID, L"Layout Id", RRF_RT_REG_SZ, nullptr, layoutIdBuffer, &layoutIdBufferSize) == ERROR_SUCCESS)
            {
                if (layoutId == std::stoul(layoutIdBuffer, nullptr, 16))
                {
                    succeded = true;
                    DBGPRINT("Found KLID 0x%ls by layoutId=0x%04x", pwszKLID, layoutId);
                    break;
                }
            }
            ++index;
        }
        CHECK_EQ(::RegCloseKey(key), ERROR_SUCCESS);
    }
    else
    {
        WORD langId = LOWORD(hkl);

        // deviceId overrides langId if set
        if (HIWORD(hkl) != 0)
            langId = HIWORD(hkl);

        std::swprintf(pwszKLID, KL_NAMELENGTH, L"%08X", langId);
        succeded = true;

        DBGPRINT("Found KLID 0x%ls by langId=0x%04x", pwszKLID, langId);
    }

    return succeded;
}
  • Then with KLID string you need to go to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\%KLID% registry path and read Layout File string from it.

  • Load this dll file from SHGetKnownFolderPath(FOLDERID_System, ...) (usually C:\Windows\System32) with LoadLibrary() call.

  • Next you need to do GetProcAddress(KbdDllHandle, "KbdLayerDescriptor") - you're receive pointer that can be casted to PKBDTABLES.

  • There is kbd.h header in Windows SDK that have KBDTABLES struct definition (there is some stuff involved to use proper KBD_LONG_POINTER size for x32 code running on x64 Windows. See my link to Gtk source at the end).

  • You have to look at pKeyNames and pKeyNamesExt in it to get scan code -> key name mapping.

Long story short: The GTK toolkit have the code that doing all this(see here and here). Actually they are building scan code -> printed chars tables from Windows keyboard layout dlls.

0

精彩评论

暂无评论...
验证码 换一张
取 消