A Control to Read all WM_KEYDOWN Messages in Modal Dialog

Anne Wilcoxen 46 Reputation points
2020-12-01T21:47:54.497+00:00

I am not going to make a Windows hook or anything over-the-top for such a simple need.
In order to allow the user to type the hotkey he or she wants to assign, I have (currently) a button that when clicked gets its routine replaced with this custom one:

    LRESULT CALLBACK COptionsPageHotkeys::ButtonOverride( HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam ) {
        COptionsPageHotkeys * pophThis = reinterpret_cast<COptionsPageHotkeys *>(::GetPropW( _hWnd, m_szProp ));
        WNDPROC wpOrig = pophThis->m_wpOrigProc;
        switch ( _uMsg ) {
            case WM_KEYDOWN : {
                UINT uiTmp = ::MapVirtualKeyW( _wParam, MAPVK_VK_TO_VSC_EX );
                std::wstring wTmp = CHotkeyManager::ScanCodeToString( _lParam );
                ::OutputDebugStringW( L"Pressing: \"" );
                ::OutputDebugStringW( wTmp.c_str() );
                ::OutputDebugStringW( L" " );
                wTmp.clear();
                CUtilities::ToHex( _lParam, wTmp, 4 );
                ::OutputDebugStringW( wTmp.c_str() );
                ::OutputDebugStringW( L" " );
                wTmp.clear();
                CUtilities::ToHex( ::MapVirtualKeyW( _lParam >> 16, MAPVK_VSC_TO_VK_EX ), wTmp, 4 );
                ::OutputDebugStringW( wTmp.c_str() );

                ::OutputDebugStringW( L" " );
                wTmp.clear();
                CUtilities::ToHex( ::MapVirtualKeyW( (_lParam >> 16), MAPVK_VSC_TO_VK ), wTmp, 4 );
                ::OutputDebugStringW( wTmp.c_str() );
                ::OutputDebugStringW( L"\".\r\n" );
                break;
            }
        }
        return ::CallWindowProc( wpOrig, _hWnd, _uMsg, _wParam, _lParam );
    }

Pressing: "\ 2B0001h 00DCh 00DCh".
Pressing: "Space 390001h 0020h 0020h".
Pressing: "Backspace E0001h 0008h 0008h".
Pressing: "\ 2B0001h 00DCh 00DCh".
Pressing: "Right Ctrl 11D0001h 0000h 0000h".
Pressing: "Z 2C0001h 005Ah 005Ah".
Pressing: "Shift 2A0001h 00A0h 0010h".
Pressing: "Z 2C0001h 005Ah 005Ah".
Pressing: "Shift 2A0001h 00A0h 0010h".
Pressing: "1 20001h 0031h 0031h".

The only problem is that this does not catch the Alt key or Enter key or etc. There are just some keys getting bypassed above this procedure.

Creating a hook procedure is definitely overkill for what I want to do.
How can I simply let the user press a button and then log the next key the user presses (handling Alt. Ctrl. and Shift separately) before returning back to normal operations?

L. Spiro

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,634 questions
0 comments No comments
{count} votes

5 answers

Sort by: Most helpful
  1. Anne Wilcoxen 46 Reputation points
    2020-12-02T06:32:03.007+00:00

    I added this to my code:

            switch ( _uMsg ) {
                case WM_GETDLGCODE : {
                    return DLGC_WANTALLKEYS;
                }
                case WM_KEYDOWN : {
    

    It seems to work now. Thank you.

    L. Spiro

    1 person found this answer helpful.

  2. Strive Sun-MSFT 426 Reputation points
    2020-12-02T02:40:21.96+00:00

    Hello @Anne Wilcoxen ,

    The only problem is that this does not catch the Alt key or Enter key or etc.

    I can catch Enter key in WM_KEYDOWN message, and Alt key belong to WM_SYSKEYDOWN message.

    WM_SYSKEYDOWN : Posted to the window with the keyboard focus when the user presses the F10 key (which activates the menu bar) or holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.

    How can I simply let the user press a button and then log the next key the user presses (handling Alt. Ctrl. and Shift separately) before returning back to normal operations?

    Alt. Ctrl. and Shift are extended keys,

    #define VK_LSHIFT         0xA0  
    #define VK_RSHIFT         0xA1  
    #define VK_LCONTROL       0xA2  
    #define VK_RCONTROL       0xA3  
    #define VK_LMENU          0xA4  
    #define VK_RMENU          0xA5  
    

    We can judge according to the value of lparam,

    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.

    Refer: WM_KEYDOWN lParam

    This is part of my test code:

     case WM_KEYDOWN:  
        {  
            wParam = MapLeftRightKeys(wParam, lParam);  
        }  
        break;  
     case WM_SYSKEYDOWN:  
        {  
            wParam = MapLeftRightKeys(wParam, lParam);  
        }  
        break;  
      
    ...  
      
      
    WPARAM MapLeftRightKeys(WPARAM vk, LPARAM lParam)  
    {  
        WPARAM new_vk = vk;  
        UINT scancode = (lParam & 0x00ff0000) >> 16;  
        int extended = (lParam & 0x01000000) != 0;  
        switch (vk) {  
        case VK_SHIFT:  
            new_vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);  
            break;  
        case VK_CONTROL:  
            new_vk = extended ? VK_RCONTROL : VK_LCONTROL;  
            break;  
        case VK_MENU:  
            new_vk = extended ? VK_RMENU : VK_LMENU;  
            break;  
        default:  
            // not a key we map from generic to left/right specialized  
            //  just return it.  
            new_vk = vk;  
            break;  
        }  
      
        return new_vk;  
    }  
    

    Thank you!

    ----------

    If the answer is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  3. Anne Wilcoxen 46 Reputation points
    2020-12-02T05:05:35.293+00:00

    I can catch Enter key in WM_KEYDOWN message

    Care to explain how?
    Sorry but you seem to have gone into detail where I know what to do and glossed over the part I needed to know how to do.
    My whole problem is in getting all the keys sent to my button, which currently rejects all kinds of characters, including VK_RETURN, VK_TAB, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, and on and on.

    I am glad it worked for you, but the whole point of my question was how to make it work for me. I need it to stop rejecting buttons so I can log them in WM_KEYDOWN (and WM_SYSKEYDOWN later). I press Enter, WM_KEYDOWN is not sent to the button. This is what I need fixed.

    L. Spiro


  4. Anne Wilcoxen 46 Reputation points
    2020-12-02T06:02:57.29+00:00

    44180-image.png

    It is a standard WC_BUTTONW with “WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT” and “WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY”.

    Spy++ reveals nothing. It describes the button just as I already have (with all the same styles) and—regardless of the target—I get nothing but a blank white screen when listening for messages. It doesn’t do anything (I repeat: Regardless of the control).

    Windows 7 Ultimate Service Pack 1.

    L. Spiro

    0 comments No comments

  5. Anne Wilcoxen 46 Reputation points
    2020-12-02T06:27:39.23+00:00

    I used another Spy++ and it prints this on VK_RETURN:
    S WM_GETDLGCODE
    P WM_KEYUP nVirtKey:VK_RETURN

    L. Spiro

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.