Windows虚拟键码

8

我该如何实现一个类似于std::string VirtualKeyCodeToStdString(UCHAR key)的函数,该函数返回虚拟键的描述信息?

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


通常,每个问题应该是独立的。考虑将您的第二个问题从这里分离出来,单独提问,并链接回这个问题。 - DeathTails
@DeathTails 已编辑。 - Inline
3
GetKeyNameText() 提供了一个内置的描述。请注意,它需要一个扫描码而不是虚拟键码,所以必要时请使用 MapVirtualKeyEx()。 - Hans Passant
2个回答

8

将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的格式化输入。有关该函数以及第一个参数的格式的更多信息,请参见MSDN文档
注意:我在API调用中使用了W变体,因此您实际上需要使用std::wstring来传递键名,但是您可以轻松更改为使用A版本。另外,如果您需要传递键盘布局以获取正确的扫描码,则可以使用MapVirtualKeyEx

8

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

* std::basic_string < TCHAR > 版本:*

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

1
你的 std::string version 需要调用 GetKeyNameTextA - IInspectable
@IInspectable 这取决于设置。但你说得对。 - Inline
1
那些外部设置是你无法控制的。这就是为什么在明确字符类型时,需要明确函数版本的原因。 - IInspectable
1
使用 KF_EXTENDED 要比硬编码的 0x100 更清晰。 - Zinovy Nis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接