时间:2019-02-11 20:36:51

标签: c++ winapi postmessage

我在处理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(),您只需在其中传递扫描代码(或者更好的是,独立于设备的虚拟密钥代码),然后它们返回LPARAM?

使用keybd_event()会容易得多,您只需将dwFlags参数保留为0即可,而将KEYEVENTF_KEYUP保留为向上键,但是该窗口必须具有焦点,而我要发送的窗口位于后台,因此keybd_event ()和SendInput()在我的情况下没有用。

3 个答案:

答案 0 :(得分:3)

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

  

其他特定于消息的信息。

在两者上。要确切了解每条消息的含义,您需要查看该消息的文档。

对于您要询问的消息,WM_KEYUPWM_KEYDOWNLPARAM的值表示:

重复计数,扫描代码,扩展键标志,上下文代码,先前的键状态标志和过渡状态标志,如下表所示。 (来源#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,仅在最高有效字节时有所不同,从而给我们:

0b1100000000101100000000000001

因此,这里唯一的区别是先前状态和过渡状态位均为1,无论如何,这保证了WM_KEYUP消息。

关于您的其他问题:

  

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

好的。查看MapVirtualKey以确定如何从键控代码中获取扫描代码,并使用位操作从中构造一个32位LPARAM以及您从上表中了解的有关位的所有其他信息必须为这些消息设置。您将需要使用移位和其他位操作来完成此操作,因为扫描代码是作为8位字节LPARAM的一部分存储的单个8位字节。

答案 1 :(得分:0)

我建议为此目的使用SendInput API。

因此,您只需要填写相应的KEYBDINPUT结构即可。

答案 2 :(得分:0)

  

是否可以创建两个函数,例如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);
}