PostMessage()的LPARAM是如何构建的

How is the LPARAM of PostMessage() constructed?

本文关键字:构建 何构建 LPARAM PostMessage      更新时间:2023-10-16

PostMessage()的参数LPARAM有问题。

这是一个广泛使用的使用PostMessage()键入字母z的示例:

PostMessage(handle, WM_KEYDOWN, 0x5A, 0x002C0001) // key down for z
PostMessage(handle, WM_KEYUP, 0x5A, 0xC02C0001) // key up for z

按下键时到达LPARAM"0x002C0001",按下键时达到"0xC02C001"的公式是什么?我想为所有密钥复制它是否可以创建两个函数,例如CreateLPARAM_KeyDown()和CreateLPARAM _KeyUp(),在这两个函数中,您只需传递扫描代码,或者更好的是,传递与设备无关的虚拟密钥代码,它们就会返回LPARAM

使用keybd_event()要容易得多,只需将dwFlags参数0保留为向下键,并使用KEYEVENTF_KEYUP保留为向上键,但窗口必须有焦点,并且我要发送的窗口在后台,所以keybd_eevent()和SendInput()在我的情况下没有用。

LPARAMWPARAM的含义因处理的特定消息而异。这就是为什么PostMessage的文档不能对这些参数过于具体,只说明:

其他特定于消息的信息。

在两者上。要确切地知道它们对每条消息意味着什么,您需要查看该消息的文档。

在您询问的消息WM_KEYUPWM_KEYDOWN的情况下,LPARAM的值表示:

重复计数、扫描代码、扩展密钥标志、上下文代码、上一个密钥状态标志和转换状态标志,如下表所示。(来源#1、#2)

Bits    Meaning
0-15    The repeat count for the current message. The value is the number of times the keystroke is autorepeated as a result of the user holding down the key. 
16-23   The scan code. The value depends on the OEM.
24      Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25-28   Reserved; do not use.
29      The context code. 
30      The previous key state. 
31      The transition state.

让我们看看你的WM_KEYDOWNLPARAM的比特:

0x002C0001
0b0000000000101100000000000001

所设置的位为21、19、18和0。这告诉我们:

重复计数为1

剩下的位是z的扫描码,它显然是0b00101100或0x2C。

WM_KEYUP消息具有LPARAM值0xC02C001,该值仅在最重要的nybble处不同,从而给出:

0b1100000000101100000000000001

因此,这里唯一的区别是,先前状态和转换状态位都是1,这对于WM_KEYUP消息来说是有保证的。

关于你的另一个问题:

是否可以创建两个函数,例如,CreateLPARAM_KeyDown()和CreateLPARAM _KeyUp(),您只需在其中传递扫描代码?

当然。查看MapVirtualKey以确定如何从密钥代码中获取扫描代码,并使用位运算从中构造32位LPARAM,以及您从上表中了解到的关于必须为这些消息设置的位的所有其他信息。由于扫描代码是作为32位LPARAM的一部分存储的单个8位字节,因此需要使用位移位和其他位操作来实现这一点。

是否可以创建两个函数,例如CreateLPARAM_KeyDown()和CreateLPARAM _KeyUp(),在这两个函数中,您只需传递扫描代码,或者更好的是,传递与设备无关的虚拟密钥代码,它们就会返回LPARAM?

试试这样的东西:

std::pair<USHORT, bool> VirtualKeyToScanCode(UINT VirtualKey)
{
USHORT ScanCode = (USHORT) MapVirtualKey(VirtualKey, MAPVK_VK_TO_VSC);
bool IsExtended = false;
// because MapVirtualKey strips the extended bit for some keys
switch (VirtualKey)
{
case VK_RMENU: case VK_RCONTROL:
case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: // arrow keys
case VK_PRIOR: case VK_NEXT: // page up and page down
case VK_END: case VK_HOME:
case VK_INSERT: case VK_DELETE:
case VK_DIVIDE: // numpad slash
case VK_NUMLOCK:
{
IsExtended = true;
break;
}
}
return std::make_pair(ScanCode, IsExtended);
}
LPARAM CreateLPARAM_KeyUpDown(UINT VirtualKey, USHORT RepeatCount, bool TransitionState, bool PreviousKeyState, bool ContextCode)
{
std::pair<USHORT, bool> ScanCode = VirtualKeyToScanCode(VirtualKey);
return (
(LPARAM(TransitionState) << 31) |
(LPARAM(PreviousKeyState) << 30) |
(LPARAM(ContextCode) << 29) |
(LPARAM(ScanCode.second) << 24) |
(LPARAM(ScanCode.first) << 16) |
LPARAM(RepeatCount)
);
}
LPARAM CreateLPARAM_KeyDown(UINT VirtualKey, USHORT RepeatCount = 1)
{
return CreateLPARAM_KeyUpDown(VirtualKey, RepeatCount, false, RepeatCount > 1, false);
}
LPARAM CreateLPARAM_KeyUp(UINT VirtualKey)
{
return CreateLPARAM_KeyUpDown(VirtualKey, 1, true, true, false);
}

我建议使用SendInput API来达到这个目的。

因此,您只需要填充相应的KEYBDINPUT结构,该结构已被充分记录。