所以在我一直在研究的文本编辑器程序中,我使用了WM_CHAR来处理来自键盘的输入。但是,我发现一些角色消息没有被记录下来。例如,如果我使用[shift] +数字键输入符号,例如%或&,则会记录一些符号,而其他字符如[shift] +9(导致')')则不会被记录。所以,我想知道我是否应该使用WM_KEYDOWN / WMKEYUP对来处理键盘输入。我曾经在汇编中编写了一个键盘记录器(实际上它只是我正在尝试的一个教程)并且使用了WM_KEYDOWN / WM_KEYUP对并且效果非常好。那么,我应该继续这个,还是我的程序发生了不寻常的事情?
谢谢,
Devjeet
这对你上面的评论真的是一个很长的回复,但是把它放在一个答案中,因为评论太长了:)
这里要理解的核心问题是键和字符并不完全相同。一些(但不是全部)键生成字符;某些键根据移位或其他键盘状态生成不同的字符。要实现编辑器,您需要处理文本输入和非文本键盘输入,如箭头键。现在是冗长的版本,从似乎不正确的假设中挑选出来:
Apparently, windows works in really strange ways. [...] It seems that when you press [shift]+9, windows sends a VK_LEFT in the wParam of message WM_CHAR
听起来你可能会在这里混合两件事。使用WM_CHAR的是它为你提供了文本字符的字符代码:所以如果有人按下9键,你就会得到'9'。如果有人按下SHIFT + 9,Windows将考虑转换状态 - 你得到'('(如果使用美国键盘)。但你不会得到一个WM_CHAR用于箭头键,HOME,END等,因为它们不是文本字符。另一方面,WM_KEYDOWN不处理字符,而是处理VK_代码;所以按9给出VK_9而不管移位状态;左箭头给你VK_LEFT - 再次调整移位状态。
事情是WM_CHAR和WM_KEYDOWN都给你整个输入图片的两个部分 - 但你真的必须处理两个部分才能得到完整的图片。并且必须要注意,在两种情况下,wParam都是一个非常不同的东西。它是WM_CHAR的字符代码,但是WM_KEYDOWN的VK_代码。不要混淆两者。
为了使事情更加混乱,VK_值与有效字符共享相同的值。打开WinUser.h(它位于编译器安装目录下的include dir中),然后查找VK_LEFT:
#define VK_LEFT 0x25
事实证明,0x25也是'%'字符的代码(有关详细信息,请参阅任何ascii / unicode表)。因此,如果WM_CHAR变为0x25,则表示按下shift-5(假设使用美国键盘)来创建'%';但如果WM_KEYDOWN变为0x25,则表示已按下左箭头(VK_LEFT)。而且为了增加一点混淆,AZ键和0-9键的虚拟键码恰好与'A' - 'Z'和'0' - '9'字符相同 - 这使它看起来像chars和VK_是可互换的。但它们不是:小写'a'的代码,0x61,是VK_NUMPAD1! (因此在WM_CHAR中获取0x61确实意味着'a',在WM_KEYDOWN中获取它意味着NUMPAD1。如果用户确实在未移位状态下击中'A'键,实际获得的是VK_A(与'A'相同的值)在WM_KEYDOWN中,它被转换为'a'的WM_CHAR。)
因此将所有这些结合在一起,处理键盘的典型方法是使用以下所有方法:
我认为有些键可能会出现在两者中 - Enter可能同时显示为VK_RETURN的WM_KEYDOWN和\ r或\ n \ n WM_CHAR - 但我的偏好是在WM_KEYDOWN中处理它,以便将编辑键处理分开从文本键。
Spy++将向您显示发送到窗口的消息,因此您可以试验并查看适合您的应用程序的消息。
如果安装了Visual Studio,它应该位于“开始”菜单中的“程序” - >“Microsoft Visual Studio” - >“Visual Studio工具” - >“Spy ++”下。
上面的有用信息激发了我创建这个片段,它为您提供了一个人类可读的指示,指示从任何WM_KEYDOWN / WM_KEYUP / WM_SYSKEYDOWN / WM_SYSKEYUP按下的键是什么,与修饰键的状态无关。
// get the keyboard state
BYTE keyState[256];
GetKeyboardState(keyState);
// clear all of the modifier keys so ToUnicode will ignore them
keyState[VK_CONTROL] = keyState[VK_SHIFT] = keyState[VK_MENU] = 0;
keyState[VK_LCONTROL] = keyState[VK_LSHIFT] = keyState[VK_LMENU] = 0;
keyState[VK_RCONTROL] = keyState[VK_RSHIFT] = keyState[VK_RMENU] = 0;
// convert the WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP to characters
UINT scanCode = (inLParam >> 16) & 0xFF;
int i = ToUnicode(inWParam, scanCode, keyState, outBuf, inOutBufLenCharacters, 0);
outBuf[i] = 0;
通过修改keyState数组以便清除所有修饰键,ToUnicode将始终输出您按下的未移位键。 (所以,在英语键盘上你永远不会得到'%'但总是'5'),只要它是一个人类可读的键。但是,您仍然必须执行VK_XXX检查以检测箭头和其他非人类可读的键。
(我试图在我的应用程序中安装用户可编辑的“热键”系统,WM_KEYXXX和WM_CHAR之间的区别让我疯了。上面的代码解决了这个问题。)