我的代码无法响应VK_UP按键事件,请求排查问题
问题:Win32程序按下VK_UP按键无响应排查
我编写了一段Win32程序,期望按下VK_UP按键时将hEdit控件的文本设置为“Oops it's up”,但完全没有效果。甚至尝试用MessageBox()替代SetWindowTextW(),依旧没有任何反应,恳请帮忙排查问题。
问题代码片段:
case WM_KEYDOWN: { switch(wp) { case VK_UP: SetWindowTextW(hEdit, L"Oops it's up"); break; } break; }
完整代码:
#include <windows.h> #include <algorithm> #define VK_UP 0x26 using namespace std; LRESULT CALLBACK MyWindowProcedure(HWND, UINT, WPARAM, LPARAM); void AddControls(HWND hWnd); HWND hEdit; int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { MSG msg = { 0 }; WNDCLASSW wc = { 0 }; wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.hCursor = LoadCursor(NULL, IDC_HAND); wc.hInstance = hInst; wc.lpszClassName = L"myWindowClass"; wc.lpfnWndProc = MyWindowProcedure; if (!RegisterClassW(&wc)) return -1; CreateWindowW(L"myWindowClass", L"my Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK MyWindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static bool timerActive = false; switch (msg) { case WM_KEYDOWN: switch (wp) { case VK_UP: MessageBox(NULL, L"key up", L"", MB_OK); break; } break; case WM_LBUTTONDOWN: { if (!timerActive) { wchar_t user_input[100]; GetWindowTextW(hEdit, user_input, 100); POINT mousePos; GetCursorPos(&mousePos); ScreenToClient(hWnd, &mousePos); HDC hdc = GetDC(hWnd); TextOutW(hdc, mousePos.x, mousePos.y, user_input, wcslen(user_input)); ReleaseDC(hWnd, hdc); // Set a timer to erase the text after 500 milliseconds SetTimer(hWnd, 1, 400, NULL); timerActive = true; } break; } case WM_RBUTTONDOWN: { if (!timerActive) { wchar_t user_reverse_input[100]; GetWindowTextW(hEdit, user_reverse_input, 100); reverse(user_reverse_input, user_reverse_input + wcslen(user_reverse_input)); POINT mousePos; GetCursorPos(&mousePos); ScreenToClient(hWnd, &mousePos); HDC hdc = GetDC(hWnd); TextOutW(hdc, mousePos.x, mousePos.y, user_reverse_input, wcslen(user_reverse_input)); ReleaseDC(hWnd, hdc); // Set a timer to erase the reversed text after 500 milliseconds SetTimer(hWnd, 1, 400, NULL); break; } } case WM_TIMER: { if (wp == 1) { KillTimer(hWnd, 1); InvalidateRect(hWnd, NULL, TRUE); timerActive = false; } break; } case WM_CREATE: AddControls(hWnd); SetFocus(hEdit); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProcW(hWnd, msg, wp, lp); } return 0; } void AddControls(HWND hWnd) { HWND hStatic = CreateWindowW(L"Static", L"Enter text here:", WS_VISIBLE | WS_CHILD, 10, 10, 220, 30, hWnd, NULL, NULL, NULL); if (hStatic == NULL) { MessageBoxW(NULL, L"Static control creation failed!", L"Error", MB_ICONERROR); return; } hEdit = CreateWindowW(L"Edit", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, 10, 45, 170, 100, hWnd, NULL, NULL, NULL); if (hEdit == NULL) { MessageBoxW(NULL, L"Edit control creation failed!", L"Error", MB_ICONERROR); return; } }
问题原因与修复方案
核心原因
程序启动后调用了SetFocus(hEdit);,导致输入焦点落在Edit控件上。Win32机制中,当子控件拥有焦点时,键盘消息会直接发送给子控件,不会传递给父窗口的窗口过程,所以父窗口的WM_KEYDOWN消息根本接收不到VK_UP的按键事件。
修复方案
方式1:给Edit控件子类化,直接在控件内部处理键盘消息
修改AddControls函数,给Edit控件设置自定义窗口过程:
// 先声明子类窗口过程 LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); void AddControls(HWND hWnd) { // 原有创建Static控件代码不变 hEdit = CreateWindowW(L"Edit", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, 10, 45, 170, 100, hWnd, NULL, NULL, NULL); if (hEdit == NULL) { MessageBoxW(NULL, L"Edit control creation failed!", L"Error", MB_ICONERROR); return; } // 给Edit控件子类化 SetWindowSubclass(hEdit, EditSubclassProc, 0, 0); } // 实现子类窗口过程 LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { switch (msg) { case WM_KEYDOWN: if (wp == VK_UP) { SetWindowTextW(hWnd, L"Oops it's up"); return 0; // 返回0表示已处理消息,不再传递给原窗口过程 } break; case WM_NCDESTROY: // 销毁控件时移除子类,避免内存泄漏 RemoveWindowSubclass(hWnd, EditSubclassProc, 0); break; } // 未处理的消息交给原窗口过程处理 return DefSubclassProc(hWnd, msg, wp, lp); }
注意:使用子类化需要包含commctrl.h头文件,并编译时链接comctl32.lib(添加编译参数/link comctl32.lib)。
方式2:让父窗口接收子控件的键盘消息
在父窗口的窗口过程中处理WM_GETDLGCODE消息,告诉系统父窗口要接收方向键类消息:
LRESULT CALLBACK MyWindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static bool timerActive = false; switch (msg) { // 添加这个case case WM_GETDLGCODE: // 让父窗口接收方向键消息 return DLGC_WANTARROWS | DefWindowProcW(hWnd, msg, wp, lp); case WM_KEYDOWN: switch (wp) { case VK_UP: SetWindowTextW(hEdit, L"Oops it's up"); MessageBox(NULL, L"key up", L"", MB_OK); break; } break; // 原有其他case代码不变 } return 0; }
这种方式下,父窗口会收到原本发送给Edit控件的方向键消息,WM_KEYDOWN的处理代码就能正常生效。
内容的提问来源于stack exchange,提问作者tetiana.mlk
相关产品推荐
相关产品推荐

