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",按下键时达到"0xC02C001"的公式是什么?我想为所有密钥复制它是否可以创建两个函数,例如CreateLPARAM_KeyDown()和CreateLPARAM _KeyUp(),在这两个函数中,您只需传递扫描代码,或者更好的是,传递与设备无关的虚拟密钥代码,它们就会返回LPARAM
使用keybd_event()要容易得多,只需将dwFlags参数0保留为向下键,并使用KEYEVENTF_KEYUP保留为向上键,但窗口必须有焦点,并且我要发送的窗口在后台,所以keybd_eevent()和SendInput()在我的情况下没有用。
LPARAM
和WPARAM
的含义因处理的特定消息而异。这就是为什么PostMessage
的文档不能对这些参数过于具体,只说明:
其他特定于消息的信息。
在两者上。要确切地知道它们对每条消息意味着什么,您需要查看该消息的文档。
在您询问的消息WM_KEYUP
和WM_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_KEYDOWN
LPARAM
的比特:
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结构,该结构已被充分记录。
- C++为构建时间获取QDateTime的可靠方法
- 无法在 CLion 中构建 C++ 项目
- 函数向量_指针有不同的原型,我可以构建一个吗
- 如何使用ndk-build.cmd构建Android.so文件
- libssh 的函数在构建 libssh 时无法在 Qt 和 cmake 错误中找到
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- VSCode-有一个红色下划线,但程序构建和运行正确,并且出现配音错误
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 无法使用Qt Creator在Windows中构建yaml-cpp
- 构建一个由C和C++文件组成的库
- llvm构建器向基本块添加终止符
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- 如何跨平台将二进制资源构建到程序中?
- 将 OpenCV 与 CMAKE 中的项目一起构建为第三方库的正确方法
- Arch Linux.AUR 包 mysql 不能用 makepkg 构建.错误:构建 () 中出现故障
- 使用 Unity 构建加快C++构建速度,并减少标头依赖项
- 使用Bazel构建系统构建具有循环依赖性的C++代码
- 如何在 qtcreator for MAC 中构建.app构建
- 在Windows上使用SSL和预构建Boost构建Mongo-Cpp驱动程序
- Qt保持构建共享构建无论我选择什么选项