摘要 在家裡,嬰兒和其它動物可能會重擊你的計算機鍵盤,致使出現各種無法預言的結果。本文中的這個C#示例應用程序將向你展示如何基於Windows鉤子API來實現在擊鍵造成任何危害之前捕獲它們。
一. 簡介
貓和嬰兒有很多共同之處。他們都喜歡吃家中養植的植物,都非常討厭關門。他們也都愛玩弄你的鍵盤,結果是,你正發送給你的老板的電子郵件可能是以半截句子發送出去的,你的Excel帳戶也被加入了一些亂七八糟的內容,並且你還沒有注意到,當打開Windows資源管理器時,若干文件已經被移到了回收站!
其解決方案是,開發一個應用程序實現如下功能:只要鍵盤處於"威脅狀態"你就可以進行切換,並確保任何鍵盤輸入活動都不會造成危害。本文想展示如何使用一種低級Windows API鉤子在一個C#應用程序中實現鍵盤"控制"。下圖是本文示例程序的一個運行快照。
二. 背景
其實,已經存在許多有關於Windows鉤子的文章和示例代碼,並且已經有人編寫過與本文幾乎一樣的C++示例程序。然而,當我搜索相應的C#應用程序的源碼時,卻找到極少的.NET示例,而且沒有一個程序能夠提供一個方便的自包含的C#類。
.NET框架能夠使你以托管方式來存取你最常使用的鍵盤事件(通過KeyPress,KeyUp和KeyDown)。遺憾的是,這些事件都不能被用來停止Windows組合鍵(如Alt+Tab或Windows"開始"鍵),從而允許用戶"遠離"某一個應用程序。
本文的想法在操作系統級上捕獲鍵盤事件而不是通過框架級來實現。為此,應用程序需要使用Windows API函數來把它自身添加到應用程序"鉤子鏈"中以監聽來自操作系統的鍵盤消息。當它收到這種類型的消息時,該應用程序能夠選擇性地傳遞消息,或者進行正常處理,或者"鎮壓"它以便不再有其它應用程序(包括Windows)來影響它。本文正是想解釋其實現機理。
然而,請注意,本文中的代碼僅適用於基於NT版本的Windows(NT,2000和XP),並且無法使用這個方法來停用Ctrl+Alt+Delete。有關於如何實現這一點,你可以參考MSDN有關資料。
三. 使用代碼
為了易於使用,我在本文中提供了兩個獨立的zip文件。一個僅包含KeyboardHook類,這是本文介紹的重點。另一個是一個完整的微軟Visual C# 2005 Express Edition應用程序工程,名叫"Baby Keyboard Bash",它實現顯示擊鍵的名字或彩色的形狀以響應於擊鍵。
四. 實例化類
鍵盤鉤子是通過keyboard.cs中的KeyboardHook類來建立和管理的。這個類實現了IDisposable接口,因此,實例化它的最簡單的方法是在應用程序的Main()方法中使用using關鍵字來封裝Application.Run()調用。這將確保只要該應用程序開始即建立鉤子並且,更重要的是,當該應用程序結束時立即使這個鉤子失效。
這個類引發一個事件來警告應用程序已經有鍵被按下,因此主表單能夠存取在Main()方法中創建的KeyboardHook實例就顯得非常重要;最簡單的方法是把這個實例存儲在一個公共成員變量中。
KeyboardHook提供了三種構造器來啟用或禁用某些設置:
· KeyboardHook():捕獲所有擊鍵,沒有任何內容傳遞到Windows或另外的應用程序。
· KeyboardHook(string param):把參數串轉換為Parameters枚舉中的值之一,然後調用下面的構造器:
· KeyboardHook(KeyboardHook.Parameters enum):根據從Parameters枚舉中選擇的值的不同,分別啟動下列設置:
o Parameters.AllowAltTab:允許用戶使用Alt+Tab切換到另外的應用程序。
o Parameters.AllowWindowsKey:允許用戶使用Ctrl+Esc或一種Windows鍵存取任務欄和開始菜單。
o Parameters.AllowAltTabAndWindows:啟用Alt+Tab,Ctrl+Esc和Windows鍵。
o Parameters.PassAllKeysToNextApp:如果該參數為true,那麼所有的擊鍵將被傳遞給任何其它監聽應用程序(包括Windows)。
當擊鍵繼續被鍵盤鉤子捕獲時,啟用Alt+Tab和/或Windows鍵允許實際使用該計算機者切換到另一個應用程序並且使用鼠標與之交互。PassAllKeysToNextApp設置有效地禁用了擊鍵捕獲;這個類也是建立一個低級鍵盤鉤子並且引發它的KeyIntercepted事件,但是它還負責把鍵盤事件傳遞到另一個監聽程序。