THotKey 封裝 Windows Common Control HOTKEY_CLASS,提供設計時可視化配置、運行時熱鍵註冊/解註冊、修飾鍵組合驗證的一站式解決方案。本文詳細講解類結構、關鍵屬性、註冊機制、多視窗協調與常見陷阱。
TObject
└── TPersistent
└── TComponent
└── TControl
└── TWinControl
└── TCustomHotKey
└── THotKey
TCustomHotKey 實作核心邏輯,THotKey 僅發佈屬性供 Object Inspector 使用,無新增方法。
| 屬性 | 類型 | 說明 |
|---|---|---|
HotKey | TShortCut | 當前熱鍵組合(虛擬鍵碼 + 修飾鍵位掩碼) |
Modifiers | THKModifiers | 修飾鍵集合:hkShift/hkCtrl/hkAlt/hkExt |
InvalidKeys | THKInvalidKeys | 禁止鍵集合:hkShift/hkCtrl/hkAlt/hkTab/... |
Enabled | Boolean | 控件是否接收輸入 |
__fastcall THotKey(TComponent* Owner); // VCL 視覺化元件
__fastcall THotKey(HWND ParentWindow); // 非 VCL 視窗嵌入(ActiveX 場景)
TShortCut 顯示。HotKey 屬性 → 呼叫 RegisterHotKey(hWnd, id, Modifiers, VK) 註冊系統級熱鍵。WM_HOTKEY 訊息 → 處理業務邏輯。UnregisterHotKey(hWnd, id)。class THotKeyManager {
HWND hWnd;
int nextId = 1;
std::map<int, TShortCut> id2sc;
public:
THotKeyManager(HWND wnd) : hWnd(wnd) {}
int Register(const TShortCut& sc) {
WORD vk = sc & 0xFF;
WORD mod = 0;
if (sc & scShift) mod |= MOD_SHIFT;
if (sc & scCtrl) mod |= MOD_CONTROL;
if (sc & scAlt) mod |= MOD_ALT;
if (sc & scExt) mod |= MOD_EXT; // Win 鍵等擴展修飾鍵
int id = nextId++;
if (::RegisterHotKey(hWnd, id, mod, vk)) {
id2sc[id] = sc;
return id;
}
return 0; // 失敗(衝突/權限)
}
void Unregister(int id) {
::UnregisterHotKey(hWnd, id);
id2sc.erase(id);
}
// 訊息迴路中調用
bool HandleHotKey(MSG& msg, TShortCut& outSc) {
if (msg.message == WM_HOTKEY) {
auto it = id2sc.find(msg.wParam);
if (it != id2sc.end()) { outSc = it->second; return true; }
}
return false;
}
};
hkShift | hkCtrl | hkAlt | hkTab,防止用戶輸入純修飾鍵或保留鍵。Ctrl+Alt+字母,設 hkCtrl | hkAlt 強制最少兩修飾鍵。THotKeyManager 統一分配 id,避免不同模組 RegisterHotKey 衝突。PostMessage 或介面回調分發。Enabled=false 時控件不接收輸入,但已註冊系統熱鍵仍生效;需同步呼叫 Unregister/Register 實現真正啟停。| 現象 | 原因 | 對策 |
|---|---|---|
| 熱鍵不觸發 | 其他進程已註冊相同組合 | 嘗試不同組合;RegisterHotKey 返回 FALSE 時提示用戶 |
| Alt+Tab 被攔截 | 未設 InvalidKeys = hkTab | 必加 hkTab 進 InvalidKeys |
| 數字鍵盤與主鍵盤區分 | VK_NUMPAD0 ≠ '0' | 用 MapVirtualKey 統一翻譯或明確區分 |
| 高 DPI 下控件繪製異常 | Common Control 版本過舊 | Manifest 指定 comctl32.dll v6;專案選項啟用 High DPI Aware |
// 在外部視窗建立 THotKey
THotKey* hk = new THotKey(externalHwnd);
hk->ParentWindow = externalHwnd; // 內部調用 SetParent
hk->HotKey = ShortCut(VK_F5, scCtrl); // 程式化設定
// 訊息迴路需手動分發 WM_HOTKEY 給 hk 所屬視窗
THotKey 以極簡 API 隱藏了 RegisterHotKey 的錯綜細節,配合 InvalidKeys/Modifiers 守護用戶輸入質量,是桌面端「全域快捷鍵」功能的首選元件。