强制 GetKeyNameText 为英文

发布于 2024-12-04 16:14:19 字数 368 浏览 1 评论 0 原文

Win32 函数 GetKeyNameText 将提供当前输入区域设置中键盘按键的名称。

来自 MSDN:

按键名称根据当前的布局进行翻译 安装的键盘,因此该函数可能会给出不同的结果 不同的输入区域设置。

是否可以在短时间内强制输入区域设置?或者是否有另一个替代 GetKeyNameText 的方法,始终返回英文名称?

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 English?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云裳 2024-12-11 16:14:19

更新:这个答案不起作用。它实际上修改了用户的键盘设置。这似乎是 Windows 版本之间的行为变化。

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 );

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 );
酒与心事 2024-12-11 16:14:19

警告:GetKeyNameText 已损坏(它会为非英语键盘布局返回错误的 AZ 键名称,因为它使用 MapVirtualKey 与MAPVK_VK_TO_CHAR 已损坏)。我根本不建议使用这种方法。 :)

您可以使用此表< /a> 将扫描代码映射到 HID 使用代码和 HID 使用名称:

扫描代码 HID 使用 HID 使用名称
0x00FF 0x0007001 ErrorRollOver
0x001E 0x0007004 键盘 A
0x0030 0x0007005 键盘 B
0x002E 0x0007006 键盘 C
0x0020 0x0007007 键盘 D
0x0012 0x0007008 键盘 E
0x0021 0x0007009 键盘 F
0x0022 0x000700A 键盘 G
0x0023 0x000700B 键盘 H
0x0017 0x000700C 键盘 I
0x0024 0x000700D 键盘 J
0x0025 0x000700E 键盘 K
0x0026 0x000700F 键盘 L
0x0032 0x0007010 键盘 M
0x0031 0x0007011 键盘 N
0x0018 0x0007012 键盘 O
0x0019 0x0007013 键盘 P
0x0010 0x0007014 键盘 Q
0x0013 0x0007015 键盘 R
0x001F 0x0007016 键盘 S
0x0014 0x0007017 键盘 T
0x0016 0x0007018 键盘 U
0x002F 0x0007019 键盘 V
0x0011 0x000701A 键盘 W
0x002D 0x000701B 键盘 X
0x0015 0x000701C 键盘 Y
0x002C 0x000701D 键盘 Z
0x0002 0x000701E 键盘 1 和 Bang
0x0003 0x000701F 键盘 2 和 At
0x0004 0x0007020 键盘 3 和哈希
0x0005 0x0007021 键盘 4和美元
0x0006 0x0007022 键盘 5 和百分比
0x0007 0x0007023 键盘 6 和脱字符号
0x0008 0x0007024 键盘 7 和与号
0x0009 0x0007025 键盘 8 和星号
0x000A 0x0007026 键盘 9 和左括号
0x000B 0x0007027 键盘 0 和右括号
0x001C 0x0007028 键盘回车 Enter
0x0001 0x0007029 键盘转义
0x000E 0x000702A 键盘删除
0x000F 0x000702B 键盘 Tab
0x0039 0x000702C 键盘空格键
0x000C 0x000702D 键盘破折号和下划线
0x000D 0x000702E 键盘等于和加号
0x001A 0x000702F 键盘左大括号
0x001B 0x0007030 键盘右大括号
0x002B 0x0007031 键盘管道和斜杠
0x002B 0x0007032 键盘非美国
0x0027 0x0007033 键盘分号和冒号
0x0028 0x0007034 键盘左撇号和双精度
0x0029 0x0007035 键盘重音和波形符
0x0033 0x0007036 键盘逗号
0x0034 0x0007037 键盘句点
0x0035 0x0007038 键盘问号
0x003A 0x0007039 键盘大写锁定
0x003B 0x000703A 键盘 F1
0x003C 0x000703B 键盘 F2
0x003D 0x000703C 键盘 F3
0x003E 0x000703D 键盘 F4
0x003F 0x000703E 键盘 F5
0x0040 0x000703F 键盘 F6
0x0041 0x0007040 键盘 F7
0x0042 0x0007041 键盘F8
0x0043 0x0007042 键盘 F9
0x0044 0x0007043 键盘 F10
0x0057 0x0007044 键盘 F11
0x0058 0x0007045 键盘 F12
0xE037
0x54
0x0007046 键盘打印屏幕
0x0046 0x0007047 键盘滚动锁定
0xE11D45
0xE046
0x45
0x0007048 键盘暂停
0xE052 0x0007049 键盘插入
0xE047 0x000704A 键盘主页
0xE049 0x000704B 键盘 PageUp
0xE053 0x000704C 键盘向前删除
0xE04F 0x000704D 键盘结束
0xE051 0x000704E 键盘向下翻页
0xE04D 0x000704F 键盘向右箭头
0xE04B 0x0007050 键盘向左箭头
0xE050 0x0007051 键盘向下箭头
0xE048 0x0007052 键盘向上箭头
0x0045
0xE045
0x0007053 键盘数字锁定和清除
0xE035 0x0007054 键盘正斜杠
0x0037 0x0007055 键盘星号
0x004A 0x0007056 键盘破折号
0x004E 0x0007057 键盘 Plus
0xE01C 0x0007058 键盘 ENTER
0x004F 0x0007059 键盘 1 和结尾
0x0050 0x000705A 键盘 2 和向下箭头
0x0051 0x000705B 键盘 3 和 PageDn
0x004B 0x000705C 键盘 4 和向左箭头
0x004C 0x000705D 键盘 5
0x004D 0x000705E 键盘 6 和向右箭头
0x0047 0x000705F 键盘 7 和 Home
0x0048 0x0007060 小键盘 8 和向上箭头
0x0049 0x0007061 小键盘 9 和 PageUp
0x0052 0x0007062 小键盘 0 和插入
0x0053 0x0007063 小键盘句号
0x0056 0x0007064 键盘非美国斜杠
0xE05D 0x0007065 键盘应用
0xE05E 0x0007066 键盘电源
0x0059 0x0007067 键盘等于
0x0064 0x0007068 键盘 F13
0x0065 0x0007069 键盘 F14
0x0066 0x000706A 键盘 F15
0x0067 0x000706B 键盘 F16
0x0068 0x000706C 键盘 F17
0x0069 0x000706D 键盘 F18
0x006A 0x000706E 键盘 F19
0x006B 0x000706F 键盘 F20
0x006C 0x0007070 键盘 F21
0x006D 0x0007071 键盘 F22
0x006E 0x0007072 键盘 F23
0x0076 0x0007073 键盘 F24
0x007E 0x0007085 键盘逗号
0x0073 0x0007087 键盘国际 1
0x0070 0x0007088 国际键盘 2
0x007D 0x0007089 国际键盘 3
0x0079 0x000708A 国际键盘 4
0x007B 0x000708B 国际键盘 5
0x005C 0x000708C 国际键盘 6
0x0072 0x0007090 键盘LANG1
0x0071 0x0007091 键盘 LANG2
0x0078 0x0007092 键盘 LANG3
0x0077 0x0007093 键盘 LANG4
0x0076 0x0007094 键盘 LANG5
0x001D 0x00070E0 键盘 LeftControl
0x002A 0x00070E1 键盘 LeftShift
0x0038 0x00070E2 键盘 LeftAlt
0xE05B 0x00070E3 键盘左侧 GUI
0xE01D 0x00070E4 键盘 RightControl
0x0036 0x00070E5 键盘 RightShift
0xE038 0x00070E6 键盘 RightAlt
0xE05C 0x00070E7 Keyboard Right GUI

OR 如果您真的非常想从键盘布局获取此信息 - 那么您可以从布局 dll 文件(kbdus.dll、kbdger.dll 等)手动加载和解析它)。

这里涉及到一堆未记录的内容:

  • 为了首先获得正确的键盘布局 dll 文件名,您需要获取 KLID 字符串(键盘布局 id,请参阅 此处查看列表)。美国英语是 00000409。如果您有 HKL(来自 GetKeyboardLayout 或 WM_INPUTLANGCHANGE),则可以使用以下代码将其转换为 KLID 字符串:
// 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;
}
  • 然后使用 KLID 字符串,您需要转到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\%KLID%注册表路径并从中读取布局文件字符串。

  • 使用 LoadLibrary()SHGetKnownFolderPath(FOLDERID_System, ...)(通常 C:\Windows\System32)加载此 dll 文件打电话。

  • 接下来您需要执行GetProcAddress(KbdDllHandle, "KbdLayerDescriptor") - 您将收到可以转换为PKBDTABLES的指针。

  • Windows SDK 中有一个 kbd.h 标头,其中包含 KBDTABLES 结构定义(涉及到为在 x64 Windows 上运行的 x32 代码使用正确的 KBD_LONG_POINTER 大小的一些内容。请参阅最后我的 Gtk 源代码链接)。

  • 您必须查看其中的pKeyNamespKeyNamesExt才能获取扫描代码 -> 键名映射。

长话短说:GTK 工具包具有完成所有这些操作的代码(请参阅此处此处)。实际上他们正在构建扫描码 ->从 Windows 键盘布局 dll 打印字符表。

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). I cannot recommend dealing with this method at all. :)

You can use this table to map scan code to HID Usage codes and HID Usage Names:

Scan code HID Usage HID Usage Name
0x00FF 0x0007001 ErrorRollOver
0x001E 0x0007004 Keyboard A
0x0030 0x0007005 Keyboard B
0x002E 0x0007006 Keyboard C
0x0020 0x0007007 Keyboard D
0x0012 0x0007008 Keyboard E
0x0021 0x0007009 Keyboard F
0x0022 0x000700A Keyboard G
0x0023 0x000700B Keyboard H
0x0017 0x000700C Keyboard I
0x0024 0x000700D Keyboard J
0x0025 0x000700E Keyboard K
0x0026 0x000700F Keyboard L
0x0032 0x0007010 Keyboard M
0x0031 0x0007011 Keyboard N
0x0018 0x0007012 Keyboard O
0x0019 0x0007013 Keyboard P
0x0010 0x0007014 Keyboard Q
0x0013 0x0007015 Keyboard R
0x001F 0x0007016 Keyboard S
0x0014 0x0007017 Keyboard T
0x0016 0x0007018 Keyboard U
0x002F 0x0007019 Keyboard V
0x0011 0x000701A Keyboard W
0x002D 0x000701B Keyboard X
0x0015 0x000701C Keyboard Y
0x002C 0x000701D Keyboard Z
0x0002 0x000701E Keyboard 1 and Bang
0x0003 0x000701F Keyboard 2 and At
0x0004 0x0007020 Keyboard 3 And Hash
0x0005 0x0007021 Keyboard 4 and Dollar
0x0006 0x0007022 Keyboard 5 and Percent
0x0007 0x0007023 Keyboard 6 and Caret
0x0008 0x0007024 Keyboard 7 and Ampersand
0x0009 0x0007025 Keyboard 8 and Star
0x000A 0x0007026 Keyboard 9 and Left Bracket
0x000B 0x0007027 Keyboard 0 and Right Bracket
0x001C 0x0007028 Keyboard Return Enter
0x0001 0x0007029 Keyboard Escape
0x000E 0x000702A Keyboard Delete
0x000F 0x000702B Keyboard Tab
0x0039 0x000702C Keyboard Spacebar
0x000C 0x000702D Keyboard Dash and Underscore
0x000D 0x000702E Keyboard Equals and Plus
0x001A 0x000702F Keyboard Left Brace
0x001B 0x0007030 Keyboard Right Brace
0x002B 0x0007031 Keyboard Pipe and Slash
0x002B 0x0007032 Keyboard Non-US
0x0027 0x0007033 Keyboard SemiColon and Colon
0x0028 0x0007034 Keyboard Left Apos and Double
0x0029 0x0007035 Keyboard Grave Accent and Tilde
0x0033 0x0007036 Keyboard Comma
0x0034 0x0007037 Keyboard Period
0x0035 0x0007038 Keyboard QuestionMark
0x003A 0x0007039 Keyboard Caps Lock
0x003B 0x000703A Keyboard F1
0x003C 0x000703B Keyboard F2
0x003D 0x000703C Keyboard F3
0x003E 0x000703D Keyboard F4
0x003F 0x000703E Keyboard F5
0x0040 0x000703F Keyboard F6
0x0041 0x0007040 Keyboard F7
0x0042 0x0007041 Keyboard F8
0x0043 0x0007042 Keyboard F9
0x0044 0x0007043 Keyboard F10
0x0057 0x0007044 Keyboard F11
0x0058 0x0007045 Keyboard F12
0xE037
0x54
0x0007046 Keyboard PrintScreen
0x0046 0x0007047 Keyboard Scroll Lock
0xE11D45
0xE046
0x45
0x0007048 Keyboard Pause
0xE052 0x0007049 Keyboard Insert
0xE047 0x000704A Keyboard Home
0xE049 0x000704B Keyboard PageUp
0xE053 0x000704C Keyboard Delete Forward
0xE04F 0x000704D Keyboard End
0xE051 0x000704E Keyboard PageDown
0xE04D 0x000704F Keyboard RightArrow
0xE04B 0x0007050 Keyboard LeftArrow
0xE050 0x0007051 Keyboard DownArrow
0xE048 0x0007052 Keyboard UpArrow
0x0045
0xE045
0x0007053 Keypad Num Lock and Clear
0xE035 0x0007054 Keypad Forward Slash
0x0037 0x0007055 Keypad Star
0x004A 0x0007056 Keypad Dash
0x004E 0x0007057 Keypad Plus
0xE01C 0x0007058 Keypad ENTER
0x004F 0x0007059 Keypad 1 and End
0x0050 0x000705A Keypad 2 and Down Arrow
0x0051 0x000705B Keypad 3 and PageDn
0x004B 0x000705C Keypad 4 and Left Arrow
0x004C 0x000705D Keypad 5
0x004D 0x000705E Keypad 6 and Right Arrow
0x0047 0x000705F Keypad 7 and Home
0x0048 0x0007060 Keypad 8 and Up Arrow
0x0049 0x0007061 Keypad 9 and PageUp
0x0052 0x0007062 Keypad 0 and Insert
0x0053 0x0007063 Keypad Period
0x0056 0x0007064 Keyboard Non-US Slash Bar
0xE05D 0x0007065 Keyboard Application
0xE05E 0x0007066 Keyboard Power
0x0059 0x0007067 Keypad Equals
0x0064 0x0007068 Keyboard F13
0x0065 0x0007069 Keyboard F14
0x0066 0x000706A Keyboard F15
0x0067 0x000706B Keyboard F16
0x0068 0x000706C Keyboard F17
0x0069 0x000706D Keyboard F18
0x006A 0x000706E Keyboard F19
0x006B 0x000706F Keyboard F20
0x006C 0x0007070 Keyboard F21
0x006D 0x0007071 Keyboard F22
0x006E 0x0007072 Keyboard F23
0x0076 0x0007073 Keyboard F24
0x007E 0x0007085 Keypad Comma
0x0073 0x0007087 Keyboard International1
0x0070 0x0007088 Keyboard International2
0x007D 0x0007089 Keyboard International3
0x0079 0x000708A Keyboard International4
0x007B 0x000708B Keyboard International5
0x005C 0x000708C Keyboard International6
0x0072 0x0007090 Keyboard LANG1
0x0071 0x0007091 Keyboard LANG2
0x0078 0x0007092 Keyboard LANG3
0x0077 0x0007093 Keyboard LANG4
0x0076 0x0007094 Keyboard LANG5
0x001D 0x00070E0 Keyboard LeftControl
0x002A 0x00070E1 Keyboard LeftShift
0x0038 0x00070E2 Keyboard LeftAlt
0xE05B 0x00070E3 Keyboard Left GUI
0xE01D 0x00070E4 Keyboard RightControl
0x0036 0x00070E5 Keyboard RightShift
0xE038 0x00070E6 Keyboard RightAlt
0xE05C 0x00070E7 Keyboard Right GUI

OR if you're really-really want to get this info from keyboard layout - then you can load and parse it manually from 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 get KLID string (keyboard layout id, see here for the list). US English is 00000409. If you have HKL (from GetKeyboardLayout or WM_INPUTLANGCHANGE) then you can convert it to KLID string with 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文