【问题标题】:How to detect a keystroke in the Window Procedure method?如何检测窗口过程方法中的击键?
【发布时间】:2020-05-27 19:32:36
【问题描述】:

我对 c++ 有点陌生,我正在尝试创建一个 gui 应用程序来告诉我我的大写锁定是否处于活动状态。我已经设置了基本 UI,它按计划启动(通过颜色向我显示我的锁定状态),但我无法在运行时更改窗口颜色。

这是我的代码:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
bool state = false;
switch (uMsg) {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        // All painting occurs here, between BeginPaint and EndPaint.
        if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0) {
            FillRect(hdc, &ps.rcPaint, CreateSolidBrush(RGB(0, 255, 0)));
        }
        else {
            FillRect(hdc, &ps.rcPaint, CreateSolidBrush(RGB(255, 0, 0)));
        }

        EndPaint(hwnd, &ps);
    }
    case WM_KEYUP:
    {

        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        // All painting occurs here, between BeginPaint and EndPaint.
        if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0) {
            FillRect(hdc, &ps.rcPaint, CreateSolidBrush(RGB(0, 255, 0)));
        }
        else {
            FillRect(hdc, &ps.rcPaint, CreateSolidBrush(RGB(255, 0, 0)));
        }

        EndPaint(hwnd, &ps);
    }
    return 0;
}

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

提前致谢。

【问题讨论】:

  • 不是那种给用户很大启发的app,只有窗口有焦点才能得到WM_KEYxxx通知。使用 SetTimer()。

标签: c++ win32gui


【解决方案1】:

不要在WM_KEYUP 处理程序中调用(Begin/End)Paint(),也不要在WM_PAINT 处理程序中调用GetKeyState()。让WM_KEY(DOWN|UP) 将所需的颜色保存到一个变量中,然后在该变量更改值以触发重新绘制窗口时调用InvalidateRect()。让WM_PAINT 根据需要使用该变量的当前值绘制窗口。

此外,您的 case 块缺少 break 语句。你正在泄漏CreateSolidBrush()返回的HBRUSH

试试这样的:

COLORREF color;

void UpdateColorForCapsLock()
{
    if (GetKeyState(VK_CAPITAL) & 0x0001) {
        color = RGB(0, 255, 0);
    }
    else {
        color = RGB(255, 0, 0);
    }
}

RESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
        case WM_CREATE:
        {
            UpdateColorForCapsLock();
            break;
        }

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            HBRUSH hBrush = CreateSolidBrush(color);
            FillRect(hdc, &ps.rcPaint, hBrush);
            DeleteObject(hBrush);
            EndPaint(hwnd, &ps);
            return 0;
        }

        case WM_KEYDOWN:
        case WM_KEYUP:
        {
            if (wParam == VK_CAPITAL)
            {
                UpdateColorForCapsLock();
                InvalidateRect(hwnd, NULL, TRUE);
            }
            break;
        }
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

【讨论】:

  • 谢谢,但问题是这只有在我拥有用户的焦点时才有效,而如果我在文本输入中输入内容则无法获得
  • 要在窗口不在焦点时捕获击键,您需要使用 1) 通过SetWindowsHookEx()WH_KEYBOARD(_LL) 挂钩,或2) 通过RegisterRawInputDevices()WM_INPUT 消息
【解决方案2】:

捕获WM_KEYDOWN 消息。如果我是 Caps Lock 按键(检查参数),请通过调用 InvalidateRect 使您的窗口自行重绘。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    相关资源
    最近更新 更多