using the WM_KEYUP, can i see if the shift\control\alt keys was uped too?

Dani AI

Generated

Short summary and practical tips. already showed the two common approaches: parse the keyboard lParam in the WM_KEY* messages, or query the key state APIs. Both are valid, but they have different guarantees and edge cases — use lParam when you need per-message details (scan code, extended flag, left/right), and use key-state queries when you just need to know "is this modifier down right now".

Important lParam bits to use when parsing WM_KEYDOWN/WM_KEYUP:

  • bits 0–15: repeat count
  • bits 16–23: scan code (use this to distinguish left vs right SHIFT)
  • bit 24: extended-key flag (helps distinguish right-control/right-alt on many keyboards)
  • bit 29: context code (set when ALT is down)
  • bit 30: previous key state
  • bit 31: transition state (set on key up)
    These let you reliably detect left/right and whether the message is an ALT-system key (WM_SYS*).

GetKeyState vs GetAsyncKeyState: use them correctly. The high bit (0x8000) indicates the key is currently down; the low bit indicates it was pressed since the last call. For “is down” checks use & 0x8000. Inside a message handler GetKeyState is usually preferable; GetAsyncKeyState is global and is for polling outside normal message flow. Watch for race conditions if you mix message parsing with polling — storing modifier state on key down/up messages is the simplest robust approach.

Other practical notes: ALT combinations generate WM_SYSKEY* messages, so handle those if you care about ALT. Don’t cast wParam straight to char for characters; use TranslateMessage/ToUnicodeEx or the text-message path if you need the actual character for the current layout. For app-level shortcuts prefer RegisterHotKey; for low-level or global capture use a keyboard hook (WH_KEYBOARD_LL) or Raw Input.

There's multiple ways to do it.. First the manual way:

1:

union KeyState
{
    LPARAM lparam;

    struct
    {
        unsigned nRepeatCount : 16;
        unsigned nScanCode : 8;
        unsigned nExtended : 1;
        unsigned nReserved : 4;
        unsigned nContext : 1;
        unsigned nPrev : 1;
        unsigned nTrans : 1;
    };
};


LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int special = 0;

    switch(message)
    {
        case WM_KEYUP:
        {
            bool stored = false;
            KeyState state;
            state.lparam = lParam;
            if(state.nExtended)
            {
                special = wParam;
                stored = true;
            }

            switch(wParam)
            {
                case VK_CONTROL:
                case VK_RCONTROL:
                case VK_SHIFT:
                case VK_RSHIFT:
                case VK_MENU:
                    special = wParam;
                    stored = true;
                    break;
            }

            if(!stored)
            {
                switch(special)
                {
                    case VK_CONTROL:
                    case VK_RCONTROL:
                        std::cout<<"CONTROL + "<<(char)(wParam)<<"\n";
                        special = 0;
                        break;
                    case VK_SHIFT:
                    case VK_RSHIFT:
                        std::cout<<"SHIFT + "<<(char)(wParam)<<"\n";
                        special = 0;
                        break;
                    case VK_MENU:
                        std::cout<<"ALT + "<<(char)(wParam)<<"\n";
                        special = 0;
                        break;

                    default:
                        std::cout<<(char)wParam<<"\n";
                        special = 0;
                        break;
                }
                break;
            }
        }
        break;

        case WM_SYSKEYDOWN:
        {
            special = wParam;
        }
        break;

    }
}

and then the easy way:

2:

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        case WM_KEYUP:
        {
            bool is_special = false;
            if((GetAsyncKeyState(VK_LCONTROL) & 1) || (GetAsyncKeyState(VK_CONTROL) & 1) || (GetAsyncKeyState(VK_RCONTROL) & 1))
            {
                std::cout<<"CONTROL";
                is_special = true;
            }

            if((GetAsyncKeyState(VK_LSHIFT) & 1) || (GetAsyncKeyState(VK_SHIFT) & 1) || (GetAsyncKeyState(VK_RSHIFT) & 1))
            {
                if(is_special)
                    std::cout<<" + ";
                std::cout<<"SHIFT";
                is_special = true;
            }

            if(GetAsyncKeyState(VK_MENU) & 1)
            {
                if(is_special)
                    std::cout<<" + ";
                std::cout<<"ALT";
                is_special = true;
            }

            switch(wParam)
            {
                case VK_CONTROL:
                case VK_LCONTROL:
                case VK_RCONTROL:
                case VK_SHIFT:
                case VK_LSHIFT:
                case VK_RSHIFT:
                case VK_MENU:
                    std::cout<<"\n";
                    break;

                default:
                {
                    if(is_special)
                        std::cout<<" + ";
                    std::cout<<(char)tolower(wParam)<<"\n";
                }
                break;
            }
        }
        break;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.