KeyboardProc 回調函數概述
KeyboardProc 是 Windows 鍵盤鉤子(WH_KEYBOARD 或 WH_KEYBOARD_LL)的核心回調函數。當應用程式安裝鍵盤鉤子後,系統會在每次鍵盤輸入事件發生時呼叫此函數,讓開發者能夠攔截、監控或修改鍵盤訊息。
函數原型
LRESULT CALLBACK KeyboardProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
參數詳細說明
| 參數 | 類型 | 說明 |
| nCode | int | 鉤子處理代碼。若小於 0,表示不應處理該訊息,需直接呼叫 CallNextHookEx。常見值:
HC_ACTION (0):正常處理訊息
HC_NOREMOVE (3):訊息已被 PeekMessage 移除但未從佇列中刪除 |
| wParam | WPARAM | 鍵盤訊息類型:
WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP |
| lParam | LPARAM | 指向 KBDLLHOOKSTRUCT 結構的指標(低階鉤子)或包含鍵盤掃描碼、擴展鍵標誌、上下文碼等資訊的位域(標準鉤子) |
返回值
- 若
nCode < 0,必須返回 CallNextHookEx 的結果
- 若處理了該訊息且不想傳遞給下一個鉤子,返回非零值
- 若繼續傳遞,返回
CallNextHookEx(hHook, nCode, wParam, lParam)
鍵盤鉤子類型比較
| 特性 | WH_KEYBOARD (標準) | WH_KEYBOARD_LL (低階) |
| 安裝方式 | SetWindowsHookEx 需 DLL 注入 | 同進程即可,無需 DLL |
| 效能影響 | 較高(跨進程上下文切換) | 較低(同進程) |
| 攔截範圍 | 僅當前執行緒/進程 | 全系統所有鍵盤輸入 |
| 適用場景 | 應用程式內部快捷鍵 | 全域熱鍵、鍵盤記錄器、螢幕鎖定 |
實戰範例:全域熱鍵實現 (Delphi)
unit KeyboardHookUnit;
interface
uses Windows, Messages;
type
TKeyboardHook = class
private
FHook: HHOOK;
FHotKeyPressed: TNotifyEvent;
class var FInstance: TKeyboardHook;
class function HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
public
constructor Create;
destructor Destroy; override;
procedure Install;
procedure Uninstall;
property OnHotKeyPressed: TNotifyEvent read FHotKeyPressed write FHotKeyPressed;
end;
implementation
{ TKeyboardHook }
constructor TKeyboardHook.Create;
begin
inherited;
FInstance := Self;
end;
destructor TKeyboardHook.Destroy;
begin
Uninstall;
FInstance := nil;
inherited;
end;
class function TKeyboardHook.HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
KbdStruct: PKBDLLHOOKSTRUCT;
begin
Result := 0;
if (nCode = HC_ACTION) and Assigned(FInstance) then
begin
if (wParam = WM_KEYDOWN) or (wParam = WM_SYSKEYDOWN) then
begin
KbdStruct := PKBDLLHOOKSTRUCT(lParam);
// 偵測 Ctrl+Alt+H 組合鍵
if (KbdStruct.vkCode = Ord('H')) and
(GetAsyncKeyState(VK_CONTROL) and $8000 <> 0) and
(GetAsyncKeyState(VK_MENU) and $8000 <> 0) then
begin
if Assigned(FInstance.FHotKeyPressed) then
FInstance.FHotKeyPressed(FInstance);
Result := 1; // 攔截該按鍵
Exit;
end;
end;
end;
Result := CallNextHookEx(FInstance.FHook, nCode, wParam, lParam);
end;
procedure TKeyboardHook.Install;
begin
if FHook = 0 then
FHook := SetWindowsHookEx(WH_KEYBOARD_LL, @HookProc, HInstance, 0);
end;
procedure TKeyboardHook.Uninstall;
begin
if FHook <> 0 then
begin
UnhookWindowsHookEx(FHook);
FHook := 0;
end;
end;
end.
最佳實踐與注意事項
- 低階鉤子超時機制:Windows 會監控
WH_KEYBOARD_LL 回調執行時間,若超過 300 毫秒(可透過 LowLevelHooksTimeout 登錄值調整),系統會自動移除鉤子。回調中務必避免耗時操作。
- 執行緒安全:回調在系統執行緒內容中執行,若需與主執行緒通訊,請使用
PostMessage 或執行緒安全佇列。
- 權限考量:低階鉤子需要應用程式具備相同或更高的完整性等級(UAC)。管理員權限程式可攔截所有輸入;標準權限僅能攔截同等或較低權限視窗的輸入。
- 除錯技巧:使用
OutputDebugString 或寫入記憶體對應檔案進行日誌記錄,避免在回調中呼叫可能阻塞的 API(如檔案 I/O、MessageBox)。
常見應用場景
- 全域熱鍵註冊(如螢幕截圖工具、推播記事本)
- 鍵盤巨集錄製與回放
- 輸入法編輯器(IME)開發
- 安全性軟體的鍵盤記錄防護
- 遊戲外掛/輔助工具的按鍵模擬
相關 API 快速查閱
SetWindowsHookEx - 安裝鉤子
UnhookWindowsHookEx - 移除鉤子
CallNextHookEx - 傳遞給下一個鉤子
GetAsyncKeyState - 即時查詢按鍵狀態
GetKeyState - 查詢訊息佇列中的按鍵狀態
MapVirtualKey - 虛擬鍵碼與掃描碼轉換