【问题标题】:Windows virtual key codesWindows 虚拟键码
【发布时间】:2016-11-01 05:23:30
【问题描述】:

如何实现像std::string VirtualKeyCodeToStdString(UCHAR key) 这样返回虚拟键描述的函数?

示例:输入为VK_CAPITAL,返回值为std::string("Caps Lock")

【问题讨论】:

  • 通常,每个问题应该是分开的。考虑在此处删除您的第二个问题,单独提问,然后链接回此问题。
  • @DeathTails 已编辑。
  • GetKeyNameText() 提供内置描述。请注意它需要扫描码,而不是虚拟键码,因此如有必要,请使用 MapVirtualKeyEx()。

标签: c++ winapi keyboard key


【解决方案1】:

将 VK 代码转换为密钥的文本表示的一种简单方法是:

  1. 使用MapVirtualKey将VK码转换为扫描码。
  2. 进行位移以将该值转换为长整数,其中 16-23 位是扫描码
  3. 使用GetKeyNameText获取密钥的名称。

例如:

WCHAR name[1024];
UINT scanCode = MapVirtualKeyW(VK_CAPITAL, MAPVK_VK_TO_VSC);
LONG lParamValue = (scanCode << 16);
int result = GetKeyNameTextW(lParamValue, name, 1024);
if (result > 0)
{
    std::wcout << name << endl; // Output: Caps Lock
}

如果您这样做是为了响应 WM_KEYDOWN 或其他通过 LPARAM 中的扫描代码的消息,您可以跳过前两个步骤,因为这些只是将 VK 代码正确地按摩到GetKeyNameText 的格式化输入。有关GetKeyNameText的第一个参数的功能和格式的详细信息,请参阅documentation at MSDN

注意:我在 API 调用中使用了 W 变体,因此您实际上需要使用 std::wstring 来传递密钥名称,但您可以轻松更改它以使用 A 版本。另外,如果您需要通过键盘布局来获得正确的扫描码,您可以使用MapVirtualKeyEx

【讨论】:

    【解决方案2】:

    没有完整的答案。谢谢大家的帮助。经过更多研究,我编写了将virtualKey 转换为std::string 描述的完整函数。

    * std::basic_string 版本:*

    typedef std::basic_string<TCHAR> tstring;
    
    tstring VirtualKeyCodeToString(UCHAR virtualKey)
    {
        UINT scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
    
        TCHAR szName[128];
        int result = 0;
        switch (virtualKey)
        {
            case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN:
            case VK_RCONTROL: case VK_RMENU:
            case VK_LWIN: case VK_RWIN: case VK_APPS:
            case VK_PRIOR: case VK_NEXT:
            case VK_END: case VK_HOME:
            case VK_INSERT: case VK_DELETE:
            case VK_DIVIDE:
            case VK_NUMLOCK:
                scanCode |= KF_EXTENDED;
            default:
                result = GetKeyNameText(scanCode << 16, szName, 128);
        }
        if(result == 0)
            throw std::system_error(std::error_code(GetLastError(), std::system_category()),
                                    "WinAPI Error occured.");
        return szName;
    }
    

    std::string 版本:

    std::string VirtualKeyCodeToString(UCHAR virtualKey)
    {
        UINT scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
    
        CHAR szName[128];
        int result = 0;
        switch (virtualKey)
        {
            case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN:
            case VK_RCONTROL: case VK_RMENU:
            case VK_LWIN: case VK_RWIN: case VK_APPS:
            case VK_PRIOR: case VK_NEXT:
            case VK_END: case VK_HOME:
            case VK_INSERT: case VK_DELETE:
            case VK_DIVIDE:
            case VK_NUMLOCK:
                scanCode |= KF_EXTENDED;
            default:
                result = GetKeyNameTextA(scanCode << 16, szName, 128);
        }
        if(result == 0)
            throw std::system_error(std::error_code(GetLastError(), std::system_category()),
                                    "WinAPI Error occured.");
        return szName;
    }
    

    【讨论】:

    • 您的 std::string 版本 需要调用GetKeyNameTextA
    • @IInspectable 它取决于设置。但你是真的。
    • 这些外部设置不在您的控制范围内。这就是为什么在明确字符类型时需要明确函数版本的原因。
    • 使用KF_EXTENDED而不是硬编码0x100更清楚。
    猜你喜欢
    • 2013-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多