Windows virtual key codes
Solution 1
There is no full answer. Thank you everybody for helping. After more research I wrote complete function that converts virtualKey
to std::string
description.
* std::basic_string < TCHAR > Version: *
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 version:
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;
}
Solution 2
A simple way to convert the VK code to a text representation of the key is to:
- Use
MapVirtualKey
to convert the VK code to a scan code. - Do a bit shift to convert that value into a long where bits 16-23 are the scan code
- Use
GetKeyNameText
to obtain the name of the key.
For example:
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
}
If you're doing this in response to a WM_KEYDOWN
or other message that passes the scan code in the LPARAM
you can skip the first two steps, since those are just there to massage the VK code into a properly formatted input for GetKeyNameText
. For more information about the function and the format of the first parameter to GetKeyNameText
see the documentation at MSDN
Note: I used the W variant on the API calls, so you'd actually need to use a std::wstring
to pass the key name, but you can change it easily to use the A version. Also, if you need to pass a keyboard layout to get the proper scan code, you can use MapVirtualKeyEx
.
Inline
Updated on June 05, 2022Comments
-
Inline almost 2 years
How can I implement a function like
std::string VirtualKeyCodeToStdString(UCHAR key)
which returns virtual keys descriptions?Example: input is
VK_CAPITAL
, return value isstd::string("Caps Lock")
-
IInspectable almost 8 yearsYour std::string version needs to call
GetKeyNameTextA
. -
Inline almost 8 years@IInspectable it depends on settings. But you true.
-
IInspectable almost 8 yearsThose external settings are outside your control. That's why you need to be explicit about the function version, when being explicit about the character type.
-
Zinovy Nis over 6 yearsIt's more clear to use
KF_EXTENDED
instead of hard-coded0x100
.