C++ PostMessage()的LPRAM是如何构造的?
PostMessage()的参数LPARAM有问题 这是一个广泛使用的使用PostMessage()键入字母z的示例: 按下键时到达LPRAM“0x002C00001”和向上键时到达LPRAM“0xC02C0001”的公式是什么?我想为所有密钥复制它是否可以创建两个函数,例如CreateLPARAM_KeyDown()和CreateLPARAM_keydup(),在这两个函数中,您只需传递扫描代码,或者更好的是,传递与设备无关的虚拟密钥代码,然后返回LPARAM?C++ PostMessage()的LPRAM是如何构造的?,c++,winapi,postmessage,C++,Winapi,Postmessage,PostMessage()的参数LPARAM有问题 这是一个广泛使用的使用PostMessage()键入字母z的示例: 按下键时到达LPRAM“0x002C00001”和向上键时到达LPRAM“0xC02C0001”的公式是什么?我想为所有密钥复制它是否可以创建两个函数,例如CreateLPARAM_KeyDown()和CreateLPARAM_keydup(),在这两个函数中,您只需传递扫描代码,或者更好的是,传递与设备无关的虚拟密钥代码,然后返回LPARAM? 使用keybd_event()
使用keybd_event()更容易,只需将dwFlags参数0保留为key down,并使用KEYEVENTF_KEYUP保留为key up,但窗口必须具有焦点,并且我要发送到的窗口位于后台,因此keybd_event()和SendInput()是在我的情况下没有任何用处。对于正在处理的特定消息,
LPARAM
和WPARAM
的含义有所不同。这就是为什么针对这些参数的文档不能太具体,只说明:
其他特定于消息的信息
两者都有。要确切了解它们对每条消息的含义,您需要查看该消息的文档
对于您询问的消息,WM_KEYUP
和WM_keyudown
,LPARAM的值表示:
重复计数、扫描代码、扩展密钥标志、上下文代码、上一个密钥状态标志和转换状态标志,如下表所示。(资料来源)
让我们看一下WM_键下的位
LPARAM
:
0x002C0001
0b0000000000101100000000000001
设置的位为21、19、18和0。这告诉我们:
重复计数为1
剩余的位是z
的扫描代码,显然是0b00101100或0x2C
WM_KEYUP
消息具有LPARAM
值0xC02C0001,该值仅在最显著的nyble处不同,为我们提供:
0b1100000000101100000000000001
因此,这里唯一的区别是前一个状态和转换状态位都是1,这对于WM_KEYUP
消息是有保证的
关于你的另一个问题:
是否可以创建两个函数,例如CreateLPARAM_KeyDown()和CreateLPARAM_keydup(),在其中传递扫描代码
当然。查看以确定如何从键代码中获取扫描代码,并使用位操作从中构造32位LPARAM
,以及从上表中了解的有关必须为这些消息设置的位的所有信息。您需要使用位移位和其他位操作来完成此操作,因为扫描代码是作为32位LPRAM的一部分存储的单个8位字节,我建议为此使用API
所以,您只需要填写相应的结构,这些结构都有很好的文档记录
有没有可能创建两个函数,比如CreateLPARAM_KeyDown()和CreateLPARAM_keydup(),您只需在其中传递扫描代码,或者更好的是,传递与设备无关的虚拟密钥代码,然后返回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);
}
std::对VirtualKeyToScanCode(UINT VirtualKey)
{
USHORT扫描代码=(USHORT)映射VirtualKey(VirtualKey,映射VK_VK_至_VSC);
bool IsExtended=false;
//因为MapVirtualKey会为某些键去掉扩展位
交换机(VirtualKey)
{
案例VK\u RMENU:案例VK\u控制:
case VK_LEFT:case VK_UP:case VK_RIGHT:case VK_DOWN://箭头键
case VK_PRIOR:case VK_NEXT://上下翻页
案例VK_结束:案例VK_主页:
案例VK_插入:案例VK_删除:
案例VK_DIVIDE://numpad slash
案例VK_NUMLOCK:
{
IsExtended=true;
打破
}
}
返回std::make_pair(扫描码,扩展);
}
LPARAM createlparamu keyuptown(UINT VirtualKey、USHORT RepeatCount、bool TransitionState、bool PreviousKeyState、bool ContextCode)
{
std::pair ScanCode=VirtualKey-toscancode(VirtualKey);
返回(
(LPARAM(TransitionState)我正在考虑使用MapVirtualKey()将虚拟键代码(与设备无关)映射到键盘的扫描代码(可能会有所不同),并使用获得的扫描代码创建LPRAM以进行向下键和向上键操作。看起来很简单,但我仍然不知道如何为给定的扫描代码创建向下键和向上键操作的LPRAM。@John这将需要位移位和其他位操作。如果您对如何操作有疑问,最好再问一个有关的问题我编辑了我的问题SendInput()无法使用,因为它需要关注。您不能通过发布此类消息来可靠地伪造输入。SendInput是您所需要的。无论这个问题在这里被问多少次,这始终是答案。David Heffernan这是一个常见的观点,但它是一个有缺陷的概括。我发布到的窗口接收消息没有问题,我测试过您甚至可以发送组合键,例如shift键向下、letter键向下/向上、shift键向上,您将获得所需的输出。这些API(PostMessage和SendMessage)如果它们没有用处,就不会存在。再说一遍,这取决于接收消息的应用程序。我没有说这些函数没有用处。我只是说它们不是用于伪造输入的。事实上,你不能将它们用于伪造输入并不意味着它们没有其他用途。你的论点很愚蠢。你似乎声称,因为se函数存在,因此它们必须放在那里解决您的问题。它工作得非常好,包括[CTRL | SHIFT | ALT]+组合键,谢谢!只是一个问题:我读到一些键盘甚至不产生扫描码,所以如果我选择一个虚拟键码,而我的键盘没有该键,Windows还会生成扫描码吗?据我所知,Windows可以做到这一点,所以理论上使用PostMessage和您提供的功能,并且唱的方式永远是w
0b1100000000101100000000000001
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);
}