天天看點

python keyboard hook_鍵盤監控的實作Ⅰ——Keyboard Hook API函數

在實際應用中,鍵盤監控是一種很常見的技術,它包括按鍵的記錄、按鍵的過濾、按鍵的修改(映射)等。比方說,我們想統計使用者的擊鍵情況,這個就是按鍵的記錄;我們想屏蔽某些系統鍵(例如Alt鍵、Win鍵),這個是按鍵的過濾;我們想改變按鍵的值,例如按下A,出來的是Z,在例如按下A,出來按鍵的組合SDFG等(貌似這個在遊戲中比較多,有些遊戲的大絕招都比較難按,用這個一勞永逸),這個是按鍵的修改。

鍵盤監控的具體實作,用的是微軟的Keyboard Hook API函數。

首先解釋下,什麼是Hook函數。

WINDOW的消息處理機制為了能在應用程式中監控系統的各種事件消息,提供了挂接各種反調函數(HOOK)的功能。這種挂鈎函數(HOOK)類似擴充中斷驅動程式,挂鈎上可以挂接多個反調函數構成一個挂接函數鍊。系統産生的各種消息首先被送到各種挂接函數,挂接函數根據各自的功能對消息進行監視、修改和控制等,然後交還控制權或将消息傳遞給下一個挂接函數以緻最終達到視窗函數。WINDOW系統的這種反調函數挂接方法雖然會略加影響到系統的運作效率,但在很多場合下是非常有用的,通過合理有效地利用鍵盤事件的挂鈎函數監控機制可以達到預想不到的良好效果。

簡單的說,就是在消息到達Window之前,系統允許你安裝Hook函數來攔截消息,并對消息進行處理。Hook函數也是有類别的,不同的函數實作不同的功能。

先看下函數的申明:

Private Declare FunctionSetWindowsHookEx Lib "user32"Alias "SetWindowsHookExA" ( _

ByVal idHook As Integer,  _       '安裝的鈎子的類型

ByVal lpfn As HookProc,  _       '消息的處理函數

ByVal hMod As IntPtr, _        '應用程式事例句柄

ByVal dwThreadId As Integer _     '線程ID

) As Integer

鈎子解除安裝函數

Private Declare Function UnhookWindowsHookEx Lib "user32" ( _

ByVal idHook As Integer_      '要解除安裝的HOOK函數的句柄

) As Integer

調用下一個HOOK函數

Private Declare Function CallNextHookEx Lib "user32" ( _

ByVal idHook As Integer,  _      '本HOOK函數的句柄

ByVal nCode As Integer,  _      '消息的類型

ByVal wParam As Integer,  _      '消息的參數

ByVal lParam As IntPtr _        '消息的參數

) As Integer

消息函數的委托

Private Delegate Function HookProc( _

ByVal nCode As Integer,  _      '消息的類型

ByVal wParam As Integer, _      '消息的參數

ByVal lParam As IntPtr _        '消息的參數

) As Integer

鈎子類型的常數

Private Const WH_KEYBOARD_LL  As  Integer= 13    '全局鍵盤鈎子(又稱為底層)Private Const WH_KEYBOARD As  Integer = 2      '普通鍵盤鈎子

按鍵資訊結構

Public Structure KeyboardHookStructDim vkCode As IntegerDim ScanCode As IntegerDim FlagsAs IntegerDim Time As IntegerDim DwExtraInfo As IntegerEnd Structure

我們用一個類來實作鍵盤的監控。

首先定義兩個變量

Private hKeyboardHook As IntegerPrivate KeyboardHookProcedure As HookProc

裝載鈎子的函數

Public Sub Hook()If hKeyboardHook = 0 ThenKeyboardHookProcedure = NewHookProc(AddressOf KeyboardHookProc)hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly.GetModules()(0)), 0)

If hKeyboardHook = 0 ThenUnHook()Throw New Win32Exception(Marshal.GetLastWin32Error)End If         End IfEnd Sub

注:函數執行後,會安裝Hook,所有的按鍵消息在到達window前都會被函數KeyboardHookProc攔截到。我們在後面的KeyboardHookProc函數中處理攔截的消息。

解除安裝鈎子的函數

Public Sub UnHook()If hKeyboardHook <> 0 ThenDim retKeyboard As Integer = UnhookWindowsHookEx(hKeyboardHook)hKeyboardHook = 0IfretKeyboard = 0 Then Throw NewWin32Exception(Marshal.GetLastWin32Error)End IfEnd Sub

按鍵消息的處理函數

Private Function KeyboardHookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer      Dim MyKeyboardHookStruct As KeyboardHookStruct = DirectCast(Marshal.PtrToStructure(lParam, GetType(KeyboardHookStruct)), KeyboardHookStruct)

自己處理的一些代碼,例如:記錄、屏蔽、映射等

Return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)End Function

以上就是基本的按鍵監控類的代碼。不過要注意以下幾點:

1、Keyboard的HOOK函數分為兩種,WH_KEYBOARD_LL和WH_KEYBOARD。我們一般用第一種,全局的鍵盤鈎子,能攔截所有的鍵盤按鍵的消息。

2、網上有人說,全局的鈎子要放在單獨的DLL中才能使用。我試了一下,不放在單獨的DLL中,在XP+VS2005下,調試和運作都沒有問題;在XP+VS2008下,調試會出錯,不過編譯後能運作;在WIN7+VS2010下,調試會出錯,編譯後能運作。這方面有研究的網友,望不吝賜教。

3、WH_KEYBOARD_LL和WH_KEYBOARD,這是兩種不同的鈎子,雖然最後都是KeyboardHookProc函數處理攔截的消息,但是具體的每個參數的意義卻完全不一樣。

WH_KEYBOARD鈎子。KeyboardHookProc函數的各個參數意義如下:

nCode    消息的類型,分HC_ACTION和HC_NOREMOVE

wParam    按鍵的虛拟鍵碼

lParam    按鍵的相關參數資訊,包括重複時間、按鍵的狀态(按下或彈起)等

WH_KEYBOARD_LL鈎子。KeyboardHookProc函數的各個參數意義如下:

nCode    消息的類型,有HC_ACTION

wParam    按鍵的狀态(按下或彈起)WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP

lParam    指向KeyboardHookStruct結構的指針,該結構包含了按鍵的詳細資訊。

可以看出,這兩種鈎子的參數的定義是完全不一樣的。而在之前的代碼中:Dim MyKeyboardHookStruct As KeyboardHookStruct = DirectCast(Marshal.PtrToStructure(lParam, GetType(KeyboardHookStruct)), KeyboardHookStruct)就是将該指針指向的内容複制到指定的結構中。

本文介紹了全局鍵盤鈎子的實作中的一些基本的HOOK API函數的介紹。具體的實作留待後文詳解。

本文轉自萬倉一黍部落格園部落格,原文連結:http://www.cnblogs.com/grenet/archive/2020年12月15日/1898840.html,如需轉載請自行聯系原作者