Search code examples
c++winapipostmessage

How is the LPARAM of PostMessage() constructed?


I'm having trouble with the parameter LPARAM of PostMessage().

This is a widely available example of the letter z being typed with PostMessage():

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

What is the formula for arriving at LPARAM "0x002C0001" for key down and "0xC02C0001" for key up? I want to replicate it for all keys. 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?

With keybd_event() it's much easier, you just leave the dwFlags parameter 0 for key down, and use KEYEVENTF_KEYUP for key up, but the window must have focus and the window I'm sending to is in the background, so keybd_event() and SendInput() are of no use in my case.


Solution

  • 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?

    Try something like this:

    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);
    }