简体   繁体   中英

Can't handle WM_KEYDOWN message

I'm trying to handle WM_KEYDOWN message using following wndproc and winmain but when I press a key(ie arrow keys which ascii value 24, 25, 26, 27) it doesn't handled.

WndProc

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    /*TO CHECK uMsg message*/
    char buff[256];
    _itoa_s(uMsg, buff, 10);
    SetWindowText(hEdit, buff);
    /**********************/
    switch (uMsg)
        case WM_CREATE:
            hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "", WS_CHILD | WS_VISIBLE |ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL, 735, 5, 150, 100, hWnd, NULL, hInst, NULL);
            HButton1 = CreateWindowEx(NULL, "BUTTON", "START", WS_CHILD | WS_VISIBLE | SS_CENTER, 2, 2, 80, 20, hWnd, (HMENU)IDC_BUTTON1, hInst, NULL);
            HButton2 = CreateWindowEx(NULL, "BUTTON", "B", WS_CHILD | WS_VISIBLE | SS_CENTER, 82, 2, 80, 20, hWnd, (HMENU)IDC_BUTTON2, hInst, NULL);
            HButton3 = CreateWindowEx(NULL, "BUTTON", "STOP", WS_CHILD | WS_VISIBLE | SS_CENTER, 162, 2, 80, 20, hWnd, (HMENU)IDC_BUTTON3, hInst, NULL);
            Hmainbmp = CreateWindowEx(NULL, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_BITMAP | WS_THICKFRAME, 1, 23, 600, 500, hWnd, NULL, hInst, NULL);
            break;
        case WM_KEYDOWN:
            PRESSED_KEY = wParam;
            break;
        case WM_COMMAND:
                    break;
            case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return(DefWindowProc(hWnd, uMsg, wParam, lParam));
    return(0L);
}

WinMain

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){
    MSG      msg;
    WNDCLASSEX wc;
    HMENU MainMenu, FileMenu;
    MainMenu = CreateMenu();
    FileMenu = CreatePopupMenu();
    AppendMenu(FileMenu, MF_STRING, IDC_OPEN, "Open");
    AppendMenu(MainMenu, MF_POPUP, (UINT_PTR)FileMenu, "FILE");

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC)WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    wc.lpszMenuName = lpszAppName;
    wc.lpszClassName = lpszAppName;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.hIconSm = (HICON)LoadImage(hInstance, lpszAppName, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

    if (!RegisterClassEx(&wc)) return(FALSE);

    hInst = hInstance;
    hWnd = CreateWindowEx(0, lpszAppName, lpszTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 600, NULL, MainMenu, hInstance, NULL);


    if (!hWnd) return(FALSE);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

Why below case doesn't work? And how can I handle WM_KEYDOWN?

case WM_KEYDOWN:
    PRESSED_KEY = wParam;
    break;

UPDATE

When I minimize and maximize window again, WM_KEYDOWN processed but if I click any button, it isn't working.

According to the WM_KEYDOWN document:

Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.

However, there are other buttons and edit boxes in your window. So when you press other buttons or click on the edit box, the focus will be on that window.which causes the WndProc function to be unable to process the WM_KEYDOWN message.

You can use the SetFocus function to set the keyboard focus window.Then you can get the WM_KEYDOWN message through the main window, and display the value through the Edit control.

Like the following code:

case WM_KEYDOWN:
    PRESSED_KEY = wParam;
    _itoa_s(wParam, buff, 10);
    SetWindowTextA(hEdit, buff);
    break;

Of course, if you don't want to focus on a specific window to get keyboard information, I recommend you use the SetWindowsHookEx function to get the global keyboard message, without focusing on a specific window.

Edit:

If you want to handle all WM_KEYDOWN messages, you can use the SetWindowsHookEx function.

You only need to modify a few parts of your code:

1.Add a function to handle the keyboard:

LRESULT __stdcall KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    char buff[256] = "";
    PKBDLLHOOKSTRUCT key = (PKBDLLHOOKSTRUCT)lParam;
    //a key was pressed
    if (wParam == WM_KEYDOWN && nCode == HC_ACTION)
    {
        _itoa_s(key->vkCode, buff, 10);
        SetWindowTextA(hEdit, buff);
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

2.Set the hook process to the keyboard in the main function:

HHOOK _k_hook;
int WINAPI WinMain(_In_  HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_  LPSTR szCmdLine, _In_  int nCmdShow)
{
    MSG      msg;
    WNDCLASSEX wc;
    HMENU MainMenu, FileMenu;
    _k_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
    ...
}

3.Finally, don't forget to delete the hook process after the program ends:

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    HWND HButton1, HButton2, HButton3, Hmainbmp;
    switch (uMsg)
    {
        ...
    case WM_DESTROY:
        if (_k_hook)
            UnhookWindowsHookEx(_k_hook);
        PostQuitMessage(0);
        break;
        ...
    }
}

In this way, you don't need to process the message of WM_KEYDOWN in WndProc . The message of pressing the key is processed in the KeyboardProc function, and the value of the key is displayed in the Edit control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM