如何为非字母字符构造WM_CHAR消息的vkCode参数值?
正确构造WM_CHAR消息中非字母字符的参数值
首先明确:WM_CHAR消息的wParam参数直接是字符的ASCII(或Unicode)值,不是虚拟键码(VK_*),你代码里的vkCode << 19操作完全是错误的,属于混淆了WM_CHAR和WM_KEYDOWN的参数规则。
核心问题拆解
原代码的错误逻辑:用VkKeyScan拿到虚拟键码后,错误地对非字母字符做左移操作,然后把这个值传给WM_CHAR的wParam。但WM_CHAR的设计就是直接接收字符本身,而非经过处理的虚拟键码。
正确的实现步骤
- WM_CHAR的wParam直接传字符值:对于ANSI字符串,直接用
str[i]作为wParam;如果是Unicode场景,转成WCHAR即可。 - lParam的扫描码正确生成:需要先通过
VkKeyScan拿到对应字符的虚拟键码(LOBYTE部分),再用MapVirtualKey转成扫描码,这部分逻辑是对的,但不需要修改虚拟键码本身。 - 去掉错误的左移操作:直接删除
vkCode << 19这一行,完全没必要保留。
修正后的代码示例
test("a#b@c&d*ef-g+!h", hWnd); struct extraKeyInfo { unsigned short repeatCount = 1; unsigned char scanCode; bool extendedKey = 0; bool contextCode = 0; bool prevKeyState = 0; bool transitionState = 0; operator unsigned int() { return repeatCount | (scanCode << 16) | (extendedKey << 24) | (contextCode << 29) | (prevKeyState << 30) | (transitionState << 31); } }; void test(const char* str, HWND hWnd) { extraKeyInfo lParam = {}; for (int i = 0; i < strlen(str); i++) { char ch = str[i]; // WM_CHAR的wParam直接传字符的ASCII值 WPARAM wParam = ch; // 仅为生成lParam里的扫描码,获取对应字符的虚拟键码 short vkCode = LOBYTE(VkKeyScan(ch)); lParam.scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC); PostMessage(hWnd, WM_CHAR, wParam, lParam); } }
补充说明
对于!@#$%&*()-=这类需要Shift组合的字符,VkKeyScan会返回包含Shift状态的结果(HIBYTE部分标记Shift是否按下),但WM_CHAR不需要关心这个状态,只需要传递最终的字符值即可,lParam里的扫描码对应基础虚拟键码(比如!对应VK_1,#对应VK_3)就足够。
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

