WINDOWS鍵盤事件監控原理及應用 (轉)

worldblog發表於2007-12-07
WINDOWS鍵盤事件監控原理及應用 (轉)[@more@]鍵盤事件原理及應用
趙桂華 ·逸仙時空
WINDOW的訊息處理機制為了能在應用中監控的各種事件訊息,提供了掛接各種反調(HOOK)的功能。這種掛鉤函式(HOOK)類似擴充中斷程式,掛鉤上可以掛接多個反調函式構成一個掛接函式鏈。系統產生的各種訊息首先被送到各種掛接函式,掛接函式根據各自的功能對訊息進行監視、修改和控制等,然後交還控制權或將訊息傳遞給下一個掛接函式以致最終達到視窗函式。WINDOW系統的這種反調函式掛接方法雖然會略加影響到系統的執行,但在很多場合下是非常有用的,透過合理有效地利用鍵盤事件的掛鉤函式監控機制可以達到預想不到的良好效果。

  一、在WINDOWS鍵盤事件上掛接監控函式的方法WINDOW下可進行掛接的過濾函式包括11種:

  WH_CALLWNDPROC視窗函式的過濾函式WH_CBT培訓過濾函式WH_DE過濾函式WH_GETMESSAGE獲取訊息過濾函式WH_HARDWARE訊息過濾函式WH_JOURNALPLAYBACK訊息重放過濾函式WH_JOURNALRECORD訊息記錄過濾函式WH_MOUSE滑鼠過濾函式WH_MSGFILTER訊息過濾函式WH_SYSMSGFILTER系統訊息過濾函式WH_KEYBOARD鍵盤過濾函式其中鍵盤過濾函式是最常用最有用的過濾函式型別,不管是哪一種型別的過濾函式,其掛接的基本方法都是相同的。

  WINDOW掛接的反調函式時總是先呼叫掛接鏈首的那個函式,因此必須將鍵盤掛鉤函式利用函式SetWindowsHookEx()將其掛接在函式鏈首。至於訊息是否傳遞給函式鏈的下一個函式是由每個具體函式功能確定的,如果訊息需要傳統給下一個函式,可呼叫函式的CallNextHookEx()來實現,如果不傳遞直接返回即可。

  掛接函式可以是用來監控所有執行緒訊息的全域性性函式,也可以是單獨監控某一執行緒的區域性性函式。如果掛接函式是區域性函式,可以將它放到一個.DLL動態連結庫中,也可以放在一個區域性模組中;如果掛接函式是全域性的,那麼必須將其放在一個.DLL 動態連結庫中。掛接函式必須嚴格按照下述格式進行宣告,以鍵盤掛鉤函式為例:

  int FAR PASCAL KeyboardProc( int nCode, wParam,DWORD lParam) 其中KeyboardProc為定義掛接函式名,該函式必須在模組定義中利用EXPORTS命令進行說明;nCode決定掛接函式是否對當前訊息進行處理;wParam和lParam為具體的訊息內容。

  二、鍵盤事件掛接函式的與在程式中可以利用函式SetWindowsHookEx()來掛接過濾函式,在掛接函式時必須指出該掛接函式的型別、函式的入口地址以及函 僑?中緣幕故薔植啃緣模?醫雍??木嚀宓饔酶袷餃縵攏?/p>
  SetWindowsHookEx(iType,iProc,hInst,iCode) 其中iType為掛接函式型別,鍵盤型別為WH_KEYBOARD,iProc為掛接函式地址,hInst 為掛接函式連結庫例項控制程式碼,iCode為監控程式碼-0表示全域性性函式。

  如果掛接函式需要將訊息傳遞給下一個過濾函式,則在該掛接函式返回前還需要呼叫一次CallNextHookEx()函式,當需要下載掛接函式時,只要呼叫一次UnhookWindowsHookEx(iProc)函式即可實現。

  如果函式是全域性性的,那麼它必須放在一個.DLL動態連結庫中,這時該函式呼叫方法可以和其它普通.DLL函式一樣有三種:

  1.在DEF定義檔案中直接用函式名或序號說明:

  EXPORTS WEP @1 RESNTNAME InitHooksDll @2 InstallFilter @3 KeyboardProc @4 用序號說明格式為:連結庫名.函式名(如本例中說明方法為KEYDLL.KeyboardProc)。

  2.在應用程式中利用函式直接呼叫:

  首先在應用程式中利用LoadLibrary(LPSTR "連結庫名")將動態連結庫裝入,並取得裝載庫模組控制程式碼hInst,然後直接利用GetProcAddress(HINSTANCE hInst,LPSTR "函式過程名")獲取函式地址,然後直接呼叫該地址即可,程式結束前利用函式FreeLibrary( )釋放裝入的動態連結庫即可。

  3.利用輸入庫.LIB方法利用IMPLIB.EXE程式在建立動態連結庫的同時建立相應的輸入庫.LIB,然後直接在專案檔案中增加該輸入庫。

  三、WINDOWS掛鉤監控函式的實現步驟WINDOWS掛鉤函式只有放在動態連結庫DLL中才能實現所有事件的監控功能。在.DLL 中形成掛鉤監控函式基本方法及其基本結構如下:

1、首先宣告DLL中的變數和過程;
2、然後編制DLL主模組LibMain(),建立模組例項;
3、建立系統退出DLL機制WEP()函式;
4、完成DLL初始化函式InitHooksDll(),傳遞主視窗程式控制程式碼;
5、編制掛鉤安裝和下載函式InstallFilter();
6、編制掛鉤函式KeyboardProc(),在其中設定監控功能,並確定繼續調下一個鉤子函式還是直接返回WINDOWS應用程式。
7、在WINDOWS主程式中需要初始化DLL並安裝相應掛鉤函式,由掛接的鉤子函式負責與主程式通訊;  
8、在不需要監控時由下載功能卸掉掛接函式。

四、WINDOWS下鍵盤掛鉤監控函式的應用技術

  目前標準的104鍵盤上都有兩個特殊的按鍵,其上分別用WINDOW程式徽標和滑鼠下拉選單標識,本文暫且分別稱為Micro左鍵和Micro右鍵,前者用來模擬滑鼠左鍵啟用開始選單,後者用來模擬滑鼠右鍵啟用屬性選單。這兩個特殊按鍵只有在按下後立即抬起即完成CLICK過程才能實現其功能,並且沒有和其它按鍵進行組合使用。

  由於WINDOWS系統中將按鍵劃分得更加詳細,使應用程式中很難靈活定義自己的專用,比如在開發.IME等應用程式時很難找到不與WORD8.0等其它應用程式衝突的功能按鍵。如果將標準104鍵盤中的這兩個特殊按鍵作為模擬CTRL和ALT等專用按鍵,使其和其它按鍵組合,就可以在自己的應用程式中自由地設定專用功能鍵,為應用程式實現各種功能快捷鍵提供靈活性。正常情況下WINDOWS鍵盤事件驅動程式並不將這兩個按鍵的訊息進行正常解釋,這就必須利用鍵盤事件的掛鉤監控函式來實現其特定的功能。其方法如下:

  1、首先編制如下一個簡單動態連結庫程式,並編譯成DLL檔案。

#include "windows.h"

int FAR PASCAL LibMain(HANDLE hModule,UINT wDataSeg,

UINT cbHeapSize,LPSTR lpszCmdLine);

int WINAPI WEP(int bSystemExit);

int WINAPI InitHooksDll(HWND hwndMainWindow);

int WINAPI InstallFilter(BOOL nCode);

LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam);

static HANDLE hInstance; // 全域性控制程式碼

static HWND hWndMain; // 主視窗控制程式碼

static int InitCalled=0; // 初始化標誌

static HHOOK hKeyHook;

FROC lpfnKeyHook=(FARPROC)KeyHook;

BOOL HookStates=FALSE;

int FAR PASCAL LibMain(

HANDLE hModule,

UINT wDataSeg,

UINT cbHeapSize,

LPSTR lpszCmdLine)

{

if (cbHeapSize!=0) UnlockData(0);

hInstance = hModule;

return 1;

}

int WINAPI WEP (int bSystemExit)

{ return 1;}

int WINAPI InitHooksDll(HWND hwndMainWindow)

{ hWndMain = hwndMainWindow;

InitCalled = 1;

return (0);

}

int WINAPI InstallFilter(BOOL nCode)

{ if (InitCalled==0) return (-1);

if (nCode==TRUE) {

hKeyHook=SetWindowsHookEx(WH_KEYBOARD,

(HOOKPROC)lpfnKeyHook,hInstance,0);

HookStates=TRUE;

} else {

UnhookWindowsHookEx(hKeyHook);

HookStates=FALSE;

}

return(0);

}

LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam)

{

static BOOL mlag=FALSE;

if(nCode$#@62;=0) {

if(HookStates==TRUE){

if((wParam==0xff)|| file://WIN3.X下按鍵值

(wParam==0x5b)||(wParam==0x5c)){//WIN95下按鍵值

if((i==0x15b)||(i==0x15c)){ file://按鍵按下處理

msflag=TRUE;

PostMessage(hWndMain,0x7fff,0x1,0x3L);

} else if((i==0xc15b)||(i==0xc15c)){//按鍵抬起處理

msflag=FALSE;

PostMessage(hWndMain,0x7fff,0x2,0x3L);

}

}

}

}

return((int)CallNextHookEx(hKeyHook,nCode,wParam,lParam));

}

  該程式的主要功能是監控鍵盤按鍵訊息,將兩個特殊按鍵Micro按下和抬起訊息轉換成自定義型別的訊息,並將自定義訊息傳送給應用程式主視窗函式。

  2、在應用程式主函式中建立視窗後,呼叫InitHooksDll()函式來初始化動態連結庫,並將應用程式主視窗控制程式碼傳遞給連結庫,然後呼叫InstallFilter()函式掛接鍵盤事件監控回撥函式。

  InitHooksDll(hIMEWnd); file://初始化DLL

  InstallFilter(TRUE); file://安裝鍵盤迴調函式

  3、在應用程式主視窗函式處理自定義訊息時,儲存Micro按鍵的狀態,供組合按鍵處理時判斷使用。

switch (iMessage) {

case 0x7fff: file://自定義訊息型別

if(lParam==0x3L){//設定Micro鍵的狀態

if(wParam==0x1) MicroFlag=TRUE;

else if(wParam==0x2) MicroFlag=FALSE;

}

break;

4、在進行按鍵組合處理時,首先判斷Micro鍵是否按下,然後再進行其它按鍵的判斷處理。

case WM_KEYDOWN: // 按鍵按下處理

if(MicroFlag==TRUE){//Micro鍵按下

if((BYTE)HIBYTE(wParam)==0x5b){

//Micro+"["組合鍵

......//按鍵功能處理

} else if((BYTE)HIBYTE(wParam)==0x5d){

//Micro+"]"組合鍵

......//按鍵功能處理

}

}

break;

  5、當應用程式退出時應注意下載鍵盤監控函式,即呼叫InstallFilter(FALSE)函式一次。

  6、利用本文提供的方法設定自己的應用程式功能按鍵,在保證程式功能按鍵不會與其它系統發生衝突的同時,有效地利用了系統中現有資源,而且在實現應用程式功能的同時靈活應用了系統中提供的各種功能呼叫。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989533/,如需轉載,請註明出處,否則將追究法律責任。

相關文章