我愛我的家園!

          成功在于你是否努力,希望在于你是否相信自己!

           

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

          WINDOWS鍵盤事件監控原理及應用
          趙桂華 ·逸仙時空

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

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

            WH_CALLWNDPROC窗口函數的過濾函數WH_CBT計算機培訓過濾函數WH_DEBUG調試過濾函數WH_GETMESSAGE獲取消息過濾函數WH_HARDWARE硬件消息過濾函數WH_JOURNALPLAYBACK消息重放過濾函數WH_JOURNALRECORD消息記錄過濾函數WH_MOUSE鼠標過濾函數WH_MSGFILTER消息過濾函數WH_SYSMSGFILTER系統消息過濾函數WH_KEYBOARD鍵盤過濾函數其中鍵盤過濾函數是最常用最有用的過濾函數類型,不管是哪一種類型的過濾函數,其掛接的基本方法都是相同的。

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

            掛接函數可以是用來監控所有線程消息的全局性函數,也可以是單獨監控某一線程的局部性函數。如果掛接函數是局部函數,可以將它放到一個.DLL動態鏈接庫中,也可以放在一個局部模塊中;如果掛接函數是全局的,那么必須將其放在一個.DLL 動態鏈接庫中。掛接函數必須嚴格按照下述格式進行聲明,以鍵盤掛鉤函數為例:

            int FAR PASCAL KeyboardProc( int nCode,WORD 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 RESIDENTNAME 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;

          FARPROC 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 msflag=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、利用本文提供的方法設置自己的應用程序功能按鍵,在保證程序功能按鍵不會與其它系統發生沖突的同時,有效地利用了系統中現有資源,而且在實現應用程序功能的同時靈活應用了系統中提供的各種功能調用。

          posted on 2008-09-04 14:41 死神 閱讀(325) 評論(0)  編輯  收藏 所屬分類: Windows編程

          導航

          統計

          公告

          歡迎大家來到我的個人世界!

          常用鏈接

          留言簿(3)

          隨筆分類(5)

          隨筆檔案(9)

          文章分類(37)

          文章檔案(41)

          相冊

          語音技術

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 柳江县| 张家港市| 北票市| 桐庐县| 皋兰县| 含山县| 老河口市| 陕西省| 定西市| 犍为县| 双峰县| 屯留县| 台湾省| 万盛区| 秭归县| 清徐县| 筠连县| 库伦旗| 高台县| 阳东县| 车险| 商城县| 大竹县| 鹤庆县| 高台县| 白山市| 铜陵市| 金沙县| 吴堡县| 交城县| 盘山县| 太谷县| 承德市| 河间市| 崇礼县| 富源县| 宁远县| 周口市| 桐柏县| 黄山市| 平罗县|