對話方塊中按 Enter,Windows 發送 WM_GETDEFID 取得預設按鈕 ID (通常為 IDOK),再轉發 WM_COMMAND 模擬點擊該按鈕。即使移除按鈕 BS_DEFPUSHBUTTON 樣式,系統仍會嘗試取得預設 ID 並觸發關閉。
重載 WM_GETDEFID,回傳 MAKELONG(0, DC_HASDEFID) 表示「有預設 ID 但為 0」,系統找不到對應控制項,Enter 失效。
// MyDialog.h
class CMyDialog : public CDialog {
// ...
afx_msg LRESULT OnGetDefId(WPARAM, LPARAM);
DECLARE_MESSAGE_MAP()
};
// MyDialog.cpp
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_MESSAGE(WM_GETDEFID, OnGetDefId)
END_MESSAGE_MAP()
LRESULT CMyDialog::OnGetDefId(WPARAM, LPARAM) {
return MAKELONG(0, DC_HASDEFID); // 高字 DC_HASDEFID=1,低字 ID=0
}
此法最簡潔,Enter 完全無反應,但滑鼠點擊 OK 按鈕仍正常運作 (因點擊發送 BN_CLICKED 而非 WM_GETDEFID)。
若希望 Enter 執行特定動作 (如查詢、換行、送出表單),使用加速鍵表是正規途徑,避免處理 WM_KEYDOWN/OnChar 等低層訊息。
ID_MY_ENTER、Key: VK_RETURN、Type: VIRTKEYvoid CMyDialog::OnMyEnter() {
// 任意自訂邏輯:焦點移動、資料送出、搜尋...
GotoNextControl(); // 例如模擬 Tab
}
MFC 對話方塊預設不處理加速鍵,必須在 CWinApp::ProcessMessageFilter 或覆寫 PreTranslateMessage 中手動呼叫 TranslateAccelerator。
// MyApp.cpp
BOOL CMyApp::ProcessMessageFilter(int code, LPMSG lpMsg) {
if (m_hAccelTable && ::TranslateAccelerator(m_pMainWnd->GetSafeHwnd(), m_hAccelTable, lpMsg))
return TRUE; // 已處理
return CWinApp::ProcessMessageFilter(code, lpMsg);
}
// 或在 Dialog 中
BOOL CMyDialog::PreTranslateMessage(MSG* pMsg) {
if (m_hAccel && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
return TRUE;
return CDialog::PreTranslateMessage(pMsg);
}
// 初始化載入加速鍵表
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
m_hAccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCEL1));
return TRUE;
}
void CMyDialog::OnMyEnter() {
// 取得目前焦點控制項
CWnd* pFocus = GetFocus();
if (pFocus) {
// 發送 WM_NEXTDLGCTL 移動焦點
SendMessage(WM_NEXTDLGCTL, 0, 0L); // 下一個控制項
// 或指定方向:SendMessage(WM_NEXTDLGCTL, (WPARAM)pFocus->GetNextDlgTabItem(), TRUE);
}
}
若需在 OnOK 中區分來源:
void CMyDialog::OnOK() {
const MSG* pMsg = GetCurrentMessage();
if (pMsg && pMsg->message == WM_COMMAND) {
WORD ctrlId = LOWORD(pMsg->wParam);
WORD notifyCode = HIWORD(pMsg->wParam);
if (ctrlId == IDOK && notifyCode == BN_CLICKED) {
// 滑鼠點擊 OK
DoRealOkLogic();
return;
}
}
// Enter 鍵或其他來源觸發
// 可選:忽略、或執行替代邏輯
}
| 需求 | 推薦方案 | 優點 | 缺點 |
|---|---|---|---|
| 完全禁用 Enter | WM_GETDEFID 回傳 0 | 代碼極少、無副作用 | Enter 完全失效 |
| Enter 執行自訂命令 | 加速鍵 + TranslateAccelerator | 標準機制、支援多鍵組合、可擴充 | 需手動掛載訊息迴圈 |
| Enter 模擬 Tab | 加速鍵映射 ID_MY_ENTER → WM_NEXTDLGCTL | 符合資料輸入習慣 | 同上 |
| 區分點擊 vs Enter | OnOK 中檢查 GetCurrentMessage | 精確控制 | 僅適用於 OK 按鈕預設行為 |
PreTranslateMessageSetFocus 或視覺樣式引導使用者掌握 WM_GETDEFID 攔截與 TranslateAccelerator 兩大核心技巧,對話方塊鍵盤交互行為將完全掌握在您手中。