我嘗試使用MapVirtualKey[A]/[W]/[ExA]/[ExW]APIVK_*通過其MAPVK_VK_TO_CHAR (2)模式將代碼映射到字符。
我發現無論我使用哪種鍵盤布局,它總是回傳'A'..'Z'字符。'VK_A'..'VK_Z'
檔案說:
uCode 引數是一個虛擬鍵碼,在回傳值的低位字中被翻譯成一個未移位的字符值。通過設定回傳值的最高位來指示死鍵(變音符號)。如果沒有翻譯,該函式回傳 0。
但我無法從中獲取unshifted character value非 ASCII 字符。
對于其他按鈕,它按描述作業。考慮到這種行為更加煩人,例如對于美國英語鍵盤布局,它回傳:
VK_Q (0x51) -> `Q` (U 0051 Latin Capital Letter Q)
VK_OEM_PERIOD (0xbe) -> `.` (U 002E Full Stop)
但對于俄語鍵盤布局,它回傳:
VK_Q (0x51) -> `Q` (U 0051 Latin Capital Letter Q)
^- here it should return `й` (U 0439 Cyrillic Small Letter Short I) according to docs
VK_OEM_PERIOD (0xbe) -> `ю` (U 044E Cyrillic Small Letter Yu)
如何正確使用?
uj5u.com熱心網友回復:
MapVirtualKey具有已知的損壞行為。
檔案在撒謊MAPVK_VK_TO_CHAR或2模式。
根據實驗和泄露的 Windows XP 源代碼(在\windows\core\ntuser\kernel\xlate.c檔案中),它包含 'A'..'Z' VK 的不同行為(這些 VK 未在 Win32 API 標頭中明確定義,WinUser.h等效于 'A'..'Z' ASCII 字符):
case 2:
/*
* Bogus Win3.1 functionality: despite SDK documenation, return uppercase for
* VK_A through VK_Z
*/
if ((wCode >= (WORD)'A') && (wCode <= (WORD)'Z')) {
return wCode;
}
不知道為什么 MS 決定從 Win 3.1 中洗掉這個錯誤,但我的 Windows 10 上的當前情況是這樣的。
此外,某些鍵盤布局可以在單次按鍵時發出多個 WCHAR 字符(UTF-16 代理對或可以包含多個 Unicode 代碼點的連字)。MapVirtualKeywithMAPVK_VK_TO_CHAR也無法為這些鍵回傳正確的值。
作為一種解決方法,我可以建議您使用ToUnicode[Ex] API,它可以為您執行此映射:
inline std::string ToUnicodeWrapper(uint16_t vkCode, uint16_t scanCode, bool isShift = false)
{
const uint32_t flags = 1 << 2; // Do not change keyboard state of this thread
static uint8_t state[256] = { 0 };
state[VK_SHIFT] = isShift << 7; // Modifiers set the high-order bit when pressed
wchar_t utf16Chars[10] = { 0 };
// This call can produce multiple UTF-16 code points
// in case of ligatures or non-BMP Unicode chars that have hi and low surrogate
// See examples: https://kbdlayout.info/features/ligatures
int charCount = ::ToUnicode(vkCode, scanCode, state, utf16Chars, 10, flags);
// negative value is returned on dead key press
if (charCount < 0)
charCount = -charCount;
// do not return blank space and control characters
if ((charCount == 1) && (std::iswblank(utf16Chars[0]) || std::iswcntrl(utf16Chars[0])))
charCount = 0;
return utf8::narrow(utf16Chars, charCount);
}
甚至更好:如果您有 Win32 訊息回圈 - 只需使用TranslateMessage()(在后臺呼叫ToUnicode())然后處理WM_CHAR訊息。
PS:同樣適用于GetKeyNameTextAPI,因為它在后臺呼叫MapVirtualKey(vk, MAPVK_VK_TO_CHAR)沒有在鍵盤布局 dll 中設定明確名稱的鍵(通常只有非字符有名稱)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/487591.html
