Коды виртуальных клавиш Windows

Как я могу реализовать такую ​​функцию, как std::string VirtualKeyCodeToStdString(UCHAR key), которая возвращает описания виртуальных ключей?

Пример: ввод VK_CAPITAL, возвращаемое значение std::string("Caps Lock")


person Inline    schedule 29.06.2016    source источник
comment
Как правило, каждый вопрос должен быть отдельным. Попробуйте удалить свой второй вопрос здесь, задать его отдельно и сослаться на этот вопрос.   -  person DeathTails    schedule 29.06.2016
comment
@DeathTails отредактировано.   -  person Inline    schedule 29.06.2016
comment
GetKeyNameText() предоставляет встроенное описание. Остерегайтесь, что для этого требуется код сканирования, а не код виртуального ключа, поэтому при необходимости используйте MapVirtualKeyEx().   -  person Hans Passant    schedule 29.06.2016
comment


Ответы (2)


Простой способ преобразовать код ВК в текстовое представление ключа:

  1. Используйте MapVirtualKey, чтобы преобразовать код ВК в скан-код.
  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 см. в документация в MSDN

Примечание. Я использовал вариант W для вызовов API, поэтому вам действительно нужно использовать std::wstring для передачи имени ключа, но вы можете легко изменить его, чтобы использовать версию A. Кроме того, если вам нужно передать раскладку клавиатуры, чтобы получить правильный код сканирования, вы можете использовать MapVirtualKeyEx.

person theB    schedule 29.06.2016

Полного ответа нет. Спасибо всем за помощь. После дополнительных исследований я написал полную функцию, которая преобразует описание 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;
}
person Inline    schedule 29.06.2016
comment
Ваша версия std::string должна вызывать GetKeyNameTextA. - person IInspectable; 29.06.2016
comment
@IInspectable зависит от настроек. Но ты правда. - person Inline; 29.06.2016
comment
Эти внешние настройки находятся вне вашего контроля. Вот почему вам нужно явно указывать версию функции, когда вы явно указываете тип символа. - person IInspectable; 29.06.2016
comment
Более понятно использовать KF_EXTENDED вместо жестко заданного 0x100. - person Zinovy Nis; 24.08.2017