PostMessage()的LPARAM是如何构造的?
How is the LPARAM of PostMessage() constructed?
我在使用 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”(按下键)和“0xC02C0001”(按下键)的公式是什么?我想为所有键复制它。 是否可以创建两个函数,比如说,CreateLPARAM_KeyDown() 和 CreateLPARAM_KeyUp(),您只需在其中传递扫描码——或者更好的是,与设备无关的虚拟键码——他们 return LPARAM?
使用 keybd_event() 就容易多了,你只需将 dwFlags 参数 0 保留为按下键,并使用 KEYEVENTF_KEYUP 键,但 window 必须有焦点和我要发送到的 window 在后台,所以 keybd_event() 和 SendInput() 对我来说没有用。
LPARAM
和 WPARAM
的含义因正在处理的特定消息而异。这就是为什么 PostMessage
的文档不能对这些参数过于具体,只说明:
Additional message-specific information.
两者都有。要准确了解它们对每条消息的含义,您需要查看该消息的文档。
对于您询问的消息 WM_KEYUP
和 WM_KEYDOWN
,LPARAM
的值表示:
重复次数、扫描码、扩展键标志、上下文码、前键状态标志、过渡状态标志,如下table。 (来源 #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_KEYDOWN
LPARAM
的位:
0x002C0001
0b0000000000101100000000000001
设置的位是 21、19、18 和 0。这告诉我们:
重复次数为 1
剩下的位是z
的扫描码,明明是0b00101100或0x2C。
WM_KEYUP
消息具有 LPARAM
值 0xC02C0001,仅在最重要的 nybble 不同,给我们:
0b1100000000101100000000000001
所以,这里唯一的区别是前状态和过渡状态位都是 1,这对于 WM_KEYUP
消息是有保证的。
关于你的另一个问题:
Is it possible to create two functions, say, CreateLPARAM_KeyDown() and CreateLPARAM_KeyUp() where you just pass the scan code?
当然可以。查看 MapVirtualKey
以确定如何从键码中获取扫描码,并使用位运算从中构造一个 32 位 LPARAM
以及您从上面的 table 中知道的所有其他内容关于必须为这些消息设置的位。您将需要使用位移位和其他位操作来完成此操作,因为扫描码是作为 32 位 LPARAM
.
的一部分存储的单个 8 位字节
我建议为此目的使用 SendInput API。
所以你只需要填写相应的 KEYBDINPUT 有据可查的结构。
Is it possible to create two functions, say, CreateLPARAM_KeyDown() and CreateLPARAM_KeyUp() where you just pass the scan code — or better yet, the device-independent virtual key code — and they return the 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);
}
我在使用 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”(按下键)和“0xC02C0001”(按下键)的公式是什么?我想为所有键复制它。 是否可以创建两个函数,比如说,CreateLPARAM_KeyDown() 和 CreateLPARAM_KeyUp(),您只需在其中传递扫描码——或者更好的是,与设备无关的虚拟键码——他们 return LPARAM?
使用 keybd_event() 就容易多了,你只需将 dwFlags 参数 0 保留为按下键,并使用 KEYEVENTF_KEYUP 键,但 window 必须有焦点和我要发送到的 window 在后台,所以 keybd_event() 和 SendInput() 对我来说没有用。
LPARAM
和 WPARAM
的含义因正在处理的特定消息而异。这就是为什么 PostMessage
的文档不能对这些参数过于具体,只说明:
Additional message-specific information.
两者都有。要准确了解它们对每条消息的含义,您需要查看该消息的文档。
对于您询问的消息 WM_KEYUP
和 WM_KEYDOWN
,LPARAM
的值表示:
重复次数、扫描码、扩展键标志、上下文码、前键状态标志、过渡状态标志,如下table。 (来源 #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_KEYDOWN
LPARAM
的位:
0x002C0001
0b0000000000101100000000000001
设置的位是 21、19、18 和 0。这告诉我们:
重复次数为 1
剩下的位是z
的扫描码,明明是0b00101100或0x2C。
WM_KEYUP
消息具有 LPARAM
值 0xC02C0001,仅在最重要的 nybble 不同,给我们:
0b1100000000101100000000000001
所以,这里唯一的区别是前状态和过渡状态位都是 1,这对于 WM_KEYUP
消息是有保证的。
关于你的另一个问题:
Is it possible to create two functions, say, CreateLPARAM_KeyDown() and CreateLPARAM_KeyUp() where you just pass the scan code?
当然可以。查看 MapVirtualKey
以确定如何从键码中获取扫描码,并使用位运算从中构造一个 32 位 LPARAM
以及您从上面的 table 中知道的所有其他内容关于必须为这些消息设置的位。您将需要使用位移位和其他位操作来完成此操作,因为扫描码是作为 32 位 LPARAM
.
我建议为此目的使用 SendInput API。
所以你只需要填写相应的 KEYBDINPUT 有据可查的结构。
Is it possible to create two functions, say, CreateLPARAM_KeyDown() and CreateLPARAM_KeyUp() where you just pass the scan code — or better yet, the device-independent virtual key code — and they return the 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);
}