核心 API:RegisterHotKey / UnregisterHotKey
BOOL RegisterHotKey(
HWND hWnd, // 接收 WM_HOTKEY 的視窗
int id, // 熱鍵 ID (應用程式內唯一)
UINT fsModifiers, // 修飾鍵組合
UINT vk // 虛擬鍵碼
);
修飾鍵常數
| 常數 | 值 | 按鍵 |
| MOD_ALT | 0x0001 | Alt |
| MOD_CONTROL | 0x0002 | Ctrl |
| MOD_SHIFT | 0x0004 | Shift |
| MOD_WIN | 0x0008 | Win 徽標鍵 |
| MOD_NOREPEAT | 0x4000 | 不重複觸發 (Win7+) |
完整實作代碼
標頭檔 (Unit1.h)
class TMainForm : public TForm
{
__published:
// IDE 管理元件...
private:
// 1. 訊息處理函數宣告
void __fastcall OnHotKey(TMessage &Message);
protected:
// 2. 訊息映射表
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_HOTKEY, TMessage, OnHotKey)
END_MESSAGE_MAP(TForm)
public:
__fastcall TMainForm(TComponent* Owner);
__fastcall ~TMainForm();
};
實作檔 (Unit1.cpp)
__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner)
{
// 建構子中註冊熱鍵:Ctrl + F12
if (!RegisterHotKey(Handle, 2000, MOD_CONTROL, VK_F12)) {
ShowMessage("熱鍵註冊失敗,可能已被其他程式佔用");
}
}
__fastcall TMainForm::~TMainForm()
{
// 解構子註銷熱鍵
UnregisterHotKey(Handle, 2000);
}
void __fastcall TMainForm::OnHotKey(TMessage &Message)
{
// Message.WParam = 熱鍵 ID (2000)
// Message.LParam 低字 = 修飾鍵, 高字 = 虛擬鍵碼
if (Message.WParam == 2000) {
// 切換視窗顯示/隱藏
if (!Visible) {
Show();
BringToFront(); // 置頂並激活
} else {
Hide();
}
}
// 必須傳遞給基類處理其他可能的熱鍵
TForm::Dispatch(&Message);
}
進階應用模式
多組熱鍵管理
enum HotKeyIDs {
HKID_TOGGLE_VISIBILITY = 1000,
HKID_SHOW_SETTINGS = 1001,
HKID_QUICK_CAPTURE = 1002
};
__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner)
{
RegisterHotKey(Handle, HKID_TOGGLE_VISIBILITY, MOD_CONTROL | MOD_SHIFT, 'H');
RegisterHotKey(Handle, HKID_SHOW_SETTINGS, MOD_CONTROL | MOD_ALT, 'S');
RegisterHotKey(Handle, HKID_QUICK_CAPTURE, MOD_WIN, VK_SNAPSHOT);
}
void __fastcall TMainForm::OnHotKey(TMessage &Message)
{
switch (Message.WParam) {
case HKID_TOGGLE_VISIBILITY: ToggleVisibility(); break;
case HKID_SHOW_SETTINGS: ShowSettings(); break;
case HKID_QUICK_CAPTURE: DoScreenCapture(); break;
}
TForm::Dispatch(&Message);
}
熱鍵衝突處理
RegisterHotKey 失敗返回 FALSE,GetLastError() 可能為 ERROR_HOTKEY_ALREADY_REGISTERED (1409)。
- 策略:嘗試替代組合、提示使用者自訂、或使用
RegisterWindowMessage 配合鉤子實現更靈活的全域熱鍵。
常見問題排查
| 現象 | 可能原因 | 解決 |
| 熱鍵不觸發 | 視窗無焦點、Handle 無效、ID 衝突 | 確保 Handle 有效、ID 唯一、視窗已建立 |
| 重複觸發 | 鍵盤自動重複、未設 MOD_NOREPEAT | Win7+ 加上 MOD_NOREPEAT |
| 程式退出後熱鍵仍生效 | 未呼叫 UnregisterHotKey | 在 FormDestroy/解構子中註銷 |
| 無法註冊 Win+鍵 | 系統保留 (Win+L, Win+D 等) | 避開系統保留組合 |
替代方案對比
| 方案 | 優點 | 缺點 | 適用場景 |
| RegisterHotKey | 簡單、無需 DLL、系統級 | 組合鍵有限、易衝突、無法攔截系統保留鍵 | 應用內部快捷鍵、單一實例切換 |
| WH_KEYBOARD_LL 鉤子 | 完全控制、可攔截任意鍵、可修改/吞噬 | 需 DLL、效能影響、UAC 限制 | 系統級熱鍵、鍵盤記錄、輸入法 |
| Raw Input | 區分多鍵盤、無鉤子副作用 | 需註冊裝置、僅接收不攔截 | 遊戲/多鍵盤應用 |

RegisterHotKey 是實現應用級全域熱鍵最輕量、最標準的方式,配合 WM_HOTKEY 訊息映射,幾行代碼即可賦予程式「隱身喚醒」能力。