почему WM_KEYDOWN не работает при запуске WM_COMMAND?

#c #user-interface #winapi

#c #пользовательский интерфейс #winapi

Вопрос:

Когда я нажимаю кнопку в окне моего клиента, а затем нажимаю клавишу со стрелкой вниз, WM_KEYDOWN не отправляется в мою процедуру Windows, но в других случаях всегда работает, поэтому, чтобы решить эту проблему, я должен щелкнуть за пределами моего клиентского окна, а затем щелкнуть в моем клиентском окне (но не на кнопке), тогда WM_KEYDOWN будет работать, есть ли лучший способ остановить фокусировку моей кнопки?

вот код:

 #include <iostream>
#define _WIN32_WINNT 0x0501
#include <Windows.h>
#include <winuser.h>
#include <vector>
#include<string>
using namespace std;

const char* className = "MyCLASSNAME!";

HWND hButton;
RECT rect;
POINT p = {0, 0};

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{


    switch(msg)
    {
    case WM_CREATE:

        hButton = CreateWindow(TEXT("BUTTON"), TEXT("1"), WS_VISIBLE | WS_CHILD, 8, 41, 50, 50, hWnd, (HMENU)1, NULL, NULL);
        break;

    case WM_KEYDOWN:

        switch (wParam)
        {

        case VK_DOWN:

            if(GetWindowRect(hButton, amp;rect))
            {
                POINT p1 = {rect.left, rect.top};
                ScreenToClient(hWnd, amp;p1);
                SetWindowPos(hButton, NULL, p1.x, p1.y, rect.right - rect.left   1, rect.bottom - rect.top   1, SWP_SHOWWINDOW);

            }

            break;
        }

        break;
    case WM_LBUTTONDOWN:
        GetCursorPos( amp;p );


        GetClientRect(hButton, amp;rect);
        SetWindowPos(hButton, NULL, p.x, p.y - 22, rect.right, rect.bottom, SWP_SHOWWINDOW);
        break;
    case WM_COMMAND:


        switch(LOWORD(wParam))
        {
        case 1:
            break;
        }

        break;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }

    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{

    WNDCLASSEXA wc;
    HWND hWnd;
    MSG msg;

    wc.cbClsExtra = 0;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.cbWndExtra = 0;
    wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wc.hInstance = hInstance;
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = className;
    wc.lpszMenuName = "MENU!";
    wc.style = NULL;

    RegisterClassEx(amp;wc);

    hWnd = CreateWindowEx(WS_EX_LAYERED, className, "hello", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
    SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);

    ShowWindow(hWnd, nShowCmd);
    UpdateWindow(hWnd);

    while(GetMessage(amp;msg, hWnd, 0, 0) > 0)
    {
        TranslateMessage(amp;msg);
        DispatchMessage(amp;msg);


    }


    return msg.wParam;
}
  

Комментарии:

1. Кнопки проглатывают некоторые нажатия клавиш. Вы можете подклассировать их и переопределить WM_GETDLGCODE , чтобы изменить это поведение.

Ответ №1:

Причина в том, что при нажатии кнопки вы фокусируетесь на текущей кнопке, поэтому ваше WM_KEYDOWN сообщение отправляется на эту кнопку.

Итак, вам нужно подклассировать кнопку и обработать WM_KEYDOWN сообщение кнопки.Вы можете обратиться к документу.

Вот измененный пример:

 #include <iostream>
#define _WIN32_WINNT 0x0501
#include <Windows.h>
#include <winuser.h>
#include <vector>
#include <string>
#include <CommCtrl.h>
using namespace std;

const char* className = "MyCLASSNAME!";
HWND hWnd;
HWND hButton;
RECT rect;
POINT p = { 0, 0 };
WNDPROC ButtonOldProc;

LRESULT CALLBACK ButtonProcNew(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (message)
    {
    case WM_KEYDOWN:
        switch (wParam)
        {
        case VK_DOWN:

            if (GetWindowRect(hButton, amp;rect))
            {
                POINT p1 = { rect.left, rect.top };
                ScreenToClient(hWnd, amp;p1);
                SetWindowPos(hButton, NULL, p1.x, p1.y, rect.right - rect.left   1, rect.bottom - rect.top   1, SWP_SHOWWINDOW);
            }
            break;
        }
        break;
    default:
        return DefSubclassProc(hwnd, message, wParam, lParam);
    }
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:

        hButton = CreateWindow(TEXT("BUTTON"), TEXT("1"), WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 8, 41, 50, 50, hWnd, (HMENU)1, NULL, NULL);
        SetWindowSubclass(hButton, ButtonProcNew, 0, 0);
        break;

    case WM_KEYDOWN:
        switch (wParam)
        {
        case VK_DOWN:

            if (GetWindowRect(hButton, amp;rect))
            {
                POINT p1 = { rect.left, rect.top };
                ScreenToClient(hWnd, amp;p1);
                SetWindowPos(hButton, NULL, p1.x, p1.y, rect.right - rect.left   1, rect.bottom - rect.top   1, SWP_SHOWWINDOW);
            }
            break;
        }

        break;
    case WM_LBUTTONDOWN:
        GetCursorPos(amp;p);
        GetClientRect(hButton, amp;rect);
        SetWindowPos(hButton, NULL, p.x, p.y - 22, rect.right, rect.bottom, SWP_SHOWWINDOW);
        break;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case 1:
            break;
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }

    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{

    WNDCLASSEXA wc;
    MSG msg;
    wc.cbClsExtra = 0;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.cbWndExtra = 0;
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wc.hInstance = hInstance;
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = className;
    wc.lpszMenuName = "MENU!";
    wc.style = NULL;
    RegisterClassEx(amp;wc);
    hWnd = CreateWindowEx(WS_EX_LAYERED, className, "hello", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
    SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);
    ShowWindow(hWnd, nShowCmd);
    UpdateWindow(hWnd);

    while (GetMessage(amp;msg, hWnd, 0, 0) > 0)
    {
        TranslateMessage(amp;msg);
        DispatchMessage(amp;msg);
    }
    return msg.wParam;
}
  

Примечание: Вам нужно связать Comctl32.lib

И это работает для меня:

введите описание изображения здесь

Комментарии:

1. Как уже сказал вам ваш компилятор, не все пути управления в вашей процедуре button возвращают значение. Кроме того, у нас уже более десяти лет есть надлежащие инструменты для создания подклассов элементов управления .

2. Привет @Astoach167, если этот ответ вам помог, пожалуйста, не стесняйтесь отмечать его, чтобы помочь людям с той же проблемой, и дайте мне знать, если у вас возникнут какие-либо проблемы. Спасибо.