RegisterHotKey 是 Windows API,用於註冊**系統級全局熱鍵**(即快捷鍵)。當用戶按下組合鍵時,系統向指定窗口發送 WM_HOTKEY 消息,實現「任意位置觸發應用功能」。
BOOL RegisterHotKey(
HWND hWnd, // 接收 WM_HOTKEY 的窗口句柄,NULL 則投遞到調用線程消息隊列
int id, // 熱鍵標識符(應用程序:0x0000~0xBFFF;共享 DLL:0xC000~0xFFFF)
UINT fsModifiers, // 修飾鍵組合:MOD_ALT | MOD_CONTROL | MOD_SHIFT | MOD_WIN
UINT vk // 虛擬鍵碼(如 0x46 = 'F')
);
GlobalAddAtom 生成唯一 id 避免衝突。MOD_CONTROL | MOD_SHIFT 表示 Ctrl+Shift。GetLastError() 獲取錯誤碼(常見:ERROR_HOTKEY_ALREADY_REGISTERED 1409)。void CRegisterHotKeyDemoDlg::OnBnClickedOk()
{
// 使用 GlobalAddAtom 生成唯一 ID(共享 DLL 範圍 0xC000~0xFFFF)
const wchar_t* wsHotKey = L"HotKeyDemo_Unique_String";
m_iHotKeyId = GlobalAddAtom(wsHotKey) - 0xC000; // 映射到應用程序範圍
if (m_iHotKeyId <= 0) return;
// 註冊 Ctrl+F (0x46)
m_bRet = RegisterHotKey(m_hWnd, m_iHotKeyId, MOD_CONTROL, 0x46);
if (!m_bRet) {
DWORD err = GetLastError();
// 處理錯誤:熱鍵被佔用、id 衝突等
return;
}
}
void CRegisterHotKeyDemoDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
if (nHotKeyId == m_iHotKeyId) {
MessageBox(L"熱鍵觸發:Ctrl+F", L"RegisterHotKey Demo", MB_OK | MB_ICONINFORMATION);
}
CDialogEx::OnHotKey(nHotKeyId, nKey1, nKey2);
}
消息映射別忘了: ON_MESSAGE(WM_HOTKEY, OnHotKey) 或重寫 OnHotKey 虛函數(MFC 已封裝)。
CRegisterHotKeyDemoDlg::~CRegisterHotKeyDemoDlg()
{
if (m_bRet) {
UnregisterHotKey(m_hWnd, m_iHotKeyId);
m_bRet = FALSE;
}
if (m_iHotKeyId > 0) {
GlobalDeleteAtom(m_iHotKeyId + 0xC000); // 還原原子 ID
m_iHotKeyId = 0;
}
}
WM_HOTKEY 放入對應線程消息隊列**隊頭**,下一輪循環優先處理。hWnd 必須屬於調用線程)。hWnd+id 已註冊,新參數 fsModifiers/vk 將覆蓋舊值。id 衝突(未用 GlobalAddAtom)。hWnd 無效或不屬於當前線程。將熱鍵組合存儲於配置文件/註冊表,運行時解析註冊:
struct HotKeyConfig {
UINT modifiers; // MOD_CONTROL | MOD_SHIFT ...
UINT vk; // VK_F1, 'S' ...
};
bool RegisterConfiguredHotKey(HWND hWnd, int id, const HotKeyConfig& cfg) {
return RegisterHotKey(hWnd, id, cfg.modifiers, cfg.vk);
}
RegisterHotKey 實現全局熱鍵看似簡單,實則涉及**原子 ID 管理、線程消息泵、系統熱鍵衝突、資源嚴格清理**等工程細節。掌握「註冊→處理→註銷」完整生命週期,配合 GlobalAddAtom 避免 ID 衝突,才能構建穩健的熱鍵功能。記住:每個 RegisterHotKey 必須配對 UnregisterHotKey,每個 GlobalAddAtom 必須配對 GlobalDeleteAtom。