CEdit 等控件擁有**獨立視窗程序**,鍵盤訊息**不會**傳遞給父對話框的 ON_WM_KEYDOWN。必須在**對話框/視圖層級**攔截訊息迴圈前的 PreTranslateMessage。
PreTranslateMessage → Add Function → Edit Code。.cpp 編輯模式;PreTranslateMessage → 雙擊生成。BOOL CMyDialog::PreTranslateMessage(MSG* pMsg) {
// 1. 攔截 WM_KEYDOWN + Enter
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) {
CWnd* pFocus = GetFocus(); // 取得目前焦點控件
if (pFocus) {
// 例:在帳號欄按 Enter → 移至密碼欄
if (pFocus == GetDlgItem(IDC_EDT_USERNAME)) {
GetDlgItem(IDC_EDT_PASSWORD)->SetFocus();
return TRUE; // 訊息已處理,不再分派
}
// 例:在密碼欄按 Enter → 觸發登入
if (pFocus == GetDlgItem(IDC_EDT_PASSWORD)) {
OnBtnLogin(); // 直接呼叫登入處理
return TRUE;
}
}
}
// 2. 其他訊息交給基類 (含 Tab 鍵切換焦點、Esc 關閉等)
return CDialog::PreTranslateMessage(pMsg);
}
| 場景 | 判斷條件 | 處理動作 |
|---|---|---|
| 多行編輯框 Ctrl+Enter 換行 | pMsg->wParam==VK_RETURN && GetAsyncKeyState(VK_CONTROL)<0 | 插入 \r\n,return TRUE |
| 數字鍵盤 Enter 區分 | pMsg->wParam==VK_RETURN && (pMsg->lParam>>16)&0xFF == 0x1C | 視為主鍵盤 Enter |
| 全域熱鍵 (無焦點也生效) | 在主框架 PreTranslateMessage 判斷 | RegisterHotKey 更標準 |
| 阻止特定按鍵 (如數字鍵) | pMsg->wParam>='0' && pMsg->wParam<='9' | return TRUE 吞掉 |
GetFocus() 取得焦點視窗,**不可**用 pMsg->hwnd (那是訊息目標視窗,可能不同);PreTranslateMessage 極高頻被呼叫,**邏輯必須極簡**,複雜判斷移出函數。CEditEx 衍生 CEdit,覆寫 OnKeyDown,再 SubclassDlgItem;WM_COMMAND。