处理对话框上的键盘输入 - Windows

Handling keyboard input on a dialog - Windows

本文关键字:输入 Windows 键盘 对话框 处理      更新时间:2023-10-16

我正在编写一个基于非模态对话框的应用程序。我正在使用Visual Studio资源编辑器来构建对话框并创建应用程序。到目前为止,一切都很顺利。但是,在处理键盘输入时,我已经达到了一堵砖墙。我的研究表明,Windows在到达对话框回调过程之前捕获键盘输入,以实现使用键盘移动焦点的功能。

创建了一个基本的对话框来测试这一点,当我有一个没有任何控件的对话框时,一切都按照我预期的那样工作。当我添加控件时,它停止工作。

以下是裸露项目的代码:

#include <Windows.h>
#include <CommCtrl.h>
#include <tchar.h>
#include "resource.h"
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM  lParam);
HWND dlghandle;
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow)
{
HWND hDlg;
MSG msg;
BOOL ret;

hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
ShowWindow(hDlg, nCmdShow);
dlghandle = hDlg;
while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if (ret == -1)
        return -1;
    if (!IsDialogMessage(hDlg, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
return 0;
}
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
    switch (uMsg)
{
case WM_KEYDOWN:
    MessageBox(NULL, L"Test", L"Test", MB_OK);
    break;
case WM_CLOSE:
    DestroyWindow(hDlg);
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
    break;
}
return 0;
}

我有哪些选择?

键盘输入出现的第一个位置是您的消息循环,因此只需检查您要查找的按键,然后再将其传递给 IsDialogMessage()/TranslateMessage()/DispatchMessage() 。例如:

while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if (ret == -1)
        return -1;
    if (msg.message == WM_KEYDOWN && msg.wParam == 'Q')
    {
        // trap and handle the Q key no matter which control has focus
    }
    else
    if (!IsDialogMessage(hDlg, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

如果你愿意,你甚至可以把它包装在一个函数中,使其更整洁,例如:

#define MYMSG_DOSOMETHING   (WM_APP + 1)
BOOL MyIsDialogMessage(HWND hDlg, MSG* pMsg)
{
    if (pMsg->message == WM_KEYDOWN && pMsg->wParam == 'Q')
    {
        PostMessage(hDlg, MYMSG_DOSOMETHING, 0, 0);
        return TRUE;
    }
    return IsDialogMessage(hDlg, pMsg);
}

// then your message loop would be:
while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if (ret == -1)
        return -1;
    if (!MyIsDialogMessage(hDlg, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

您也可以使用 SetWindowsHook 创建低级键盘进程。请注意,这看起来有点复杂和高级,但它适用于对话框,而无需对消息循环进行任何额外的努力。

HHOOK g_hLowLevelKeyHook;
//windows Main.
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    g_hLowLevelKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
........
....... 
}
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *)lParam;
    if (nCode == HC_ACTION && wParam == WM_KEYUP)
    {
        if (pkbhs->vkCode == VK_F1)
            MessageBoxA(NULL"F1 Pressed","INFO",MB_ICONINFORMATION);
    }
    return CallNextHookEx(g_hLowLevelKeyHook, nCode, wParam, lParam);
}