MFC 對話框默認行為:
BN_CLICKED,若無 IDOK 則關閉對話框 (OnOK)。BN_CLICKED,關閉對話框 (OnCancel)。若需自定義鍵盤邏輯 (如編輯控件中 Enter 換行、遊戲按鍵處理),必須攔截消息。
PreTranslateMessagePreTranslateMessage 是 CWinThread 虛函數,消息分發前調用,返回 TRUE 表示已處理,不再分發。
// MyDlg.h
class CMyDlg : public CDialog {
// ...
virtual BOOL PreTranslateMessage(MSG* pMsg);
};
// MyDlg.cpp
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) {
// 1. 過濾鍵盤消息
if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN) {
switch (pMsg->wParam) {
case VK_RETURN: // Enter 鍵
// 可選:檢查焦點控件類型,僅在特定控件攔截
// CWnd* pFocus = GetFocus();
// if (pFocus && pFocus->GetDlgCtrlID() == IDC_EDIT_MULTILINE) {
// return FALSE; // 不攔截,允許編輯控件換行
// }
// 攔截 Enter,防止觸發默認按鈕
pMsg->wParam = 0x998; // 修改虛擬鍵碼為無效值
// 或直接返回 TRUE 吞噬消息
// return TRUE;
break;
case VK_ESCAPE: // Esc 鍵
// 攔截 Esc,防止觸發取消按鈕
pMsg->wParam = 0x999;
// return TRUE;
break;
// 可擴展:其他鍵 (F1-F12, Tab, 方向鍵...)
}
}
// 2. 必須調用基類實現,保持其他消息處理 (如快捷鍵、工具提示)
return CDialog::PreTranslateMessage(pMsg);
}
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) {
if (pMsg->message == WM_KEYDOWN) {
CWnd* pFocus = GetFocus();
if (pFocus) {
int nID = pFocus->GetDlgCtrlID();
// 多行編輯框:允許 Enter 換行
if (nID == IDC_EDIT_LOG && (pMsg->wParam == VK_RETURN)) {
return FALSE; // 不攔截
}
// ComboBox 下拉列表:允許 Enter 確認選擇
if (nID == IDC_COMBO_SEARCH && (pMsg->wParam == VK_RETURN)) {
return FALSE;
}
// 通用攔截 Enter/Esc
if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
// 可選:發送自定義消息給特定處理器
// PostMessage(WM_USER_KEY, pMsg->wParam);
return TRUE; // 吞噬
}
}
}
return CDialog::PreTranslateMessage(pMsg);
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
PreTranslateMessage | 統一攔截、靈活、不影響控件子類化 | 需小心調用基類 | 全局鍵盤邏輯、遊戲/編輯器 |
重寫 OnOK/OnCancel 為空 | 簡單 | 無法區分 Enter/Esc 來源,其他調用仍觸發 | 僅需禁用關閉 |
| 修改按鈕 ID (非 IDOK/IDCANCEL) | 無代碼 | 失去默認按鈕視覺提示 (黑框) | 無默認按鈕場景 |
控件子類化處理 WM_KEYDOWN | 精確到控件 | 每個控件需單獨處理 | 特定控件特殊行為 |
CDialog::PreTranslateMessage → 快捷鍵 (Alt+F4 等)、工具提示、滾動條鍵盤導航失效。TRUE 吞噬所有按鍵 → 整個對話框鍵盤無響應。pMsg->wParam 但未返回 TRUE → 消息仍分發,修改可能無效。WM_CHAR 而非 WM_KEYDOWN → 虛擬鍵碼 (VK_RETURN) 不在 WM_CHAR 中。禁止對話框按鈕響應 Enter/Esc 的標準做法是重寫 PreTranslateMessage,檢查 WM_KEYDOWN 中的 VK_RETURN/VK_ESCAPE,根據焦點控件類型決定是否吞噬 (返回 TRUE) 或修改虛擬鍵碼。務必調用基類實現保持系統功能。此模式同樣適用於攔截 Tab、方向鍵、功能鍵等全局鍵盤邏輯。