<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    happyfish

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      38 Posts :: 1 Stories :: 62 Comments :: 0 Trackbacks

    重定義鍵盤的兩種實(shí)現(xiàn)方法

    聯(lián)系方式:大連理工大學(xué)電子系995班孫宇哲

                                              Email:sunyuzhe@263.net

                                              主頁:http://sunyuzhe.363.net

                                              Tel:0411-4702214

    windows操作系統(tǒng)中,如果我們想對鍵盤進(jìn)行重定義,比如說按某鍵就可發(fā)直接上網(wǎng),按某鍵可以直接關(guān)閉窗口等等,如何實(shí)現(xiàn)呢!在Visual C++中用常規(guī)class wizard方法是不可以實(shí)現(xiàn)的,這里我們用兩種方法去實(shí)現(xiàn)它。

    方法1:利用RegisterHotKey函獲數(shù)實(shí)現(xiàn)

    程序?qū)崿F(xiàn)原理:首先用戶預(yù)定一個熱鍵,無論該程序是前臺程序還是后臺程序,只
    要用戶按了這個鍵,就執(zhí)行我們定義好的函數(shù)。程序中要對熱鍵消息WM_HOTKEY進(jìn)行
    捕獲,并通過消息參數(shù)了解哪一個鍵被按下。 
        因?yàn)?/SPAN>VC中的CLASSWIZARD中沒有對消息WM_HOTKEY進(jìn)行封裝,我們只有通過手工加入代碼實(shí)現(xiàn)。該消息的映射及處理。

      具體實(shí)現(xiàn)步驟如下:

    l         1 MFC AppWizard建立一個工程名為:HotKey基于Dialog base的對話框程序,點(diǎn)擊finish

    l         2 聲明熱鍵消息處理函數(shù)原型 
      在HotKeyDlg.h中消息映射聲明處(AFX_mSG字樣之后)加入如下語句(其中畫線部分是加入的代碼)

    // Generated message map functions

           //{{AFX_MSG(CHotKeyDlg)

           virtual BOOL OnInitDialog();

           afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

           afx_msg void OnPaint();

           afx_msg HCURSOR OnQueryDragIcon();

           LRESULT OnHotKey(WPARAM wParam,LPARAM lParam);

           //}}AFX_MSG

               DECLARE_MESSAGE_MAP()

    l         3 消息與相應(yīng)處理函數(shù)相關(guān)聯(lián) HotKeyDlg.Cpp中加入消息映射宏,使消息與相應(yīng)處理函數(shù)發(fā)生關(guān)系,加入如下語句(其中畫線部分是加入的代碼)

    BEGIN_MESSAGE_MAP(CHotKeyDlg, CDialog)

           //{{AFX_MSG_MAP(CHotKeyDlg)

           ON_WM_SYSCOMMAND()

           ON_WM_PAINT()

           ON_WM_QUERYDRAGICON()

           ON_MESSAGE(WM_HOTKEY,OnHotKey)

           //}}AFX_MSG_MAP

    END_MESSAGE_MAP()

    l         4 為方便以后的操作預(yù)先在CHotKeyDlg類中利用CLASSWIZARD實(shí)現(xiàn)一個響應(yīng)WM_CREATEWM_DESTROY消息的函數(shù)OnCreate( )OnDestroy( )的框架,(利用CLASSWIZARD很容易實(shí)現(xiàn),請參考有關(guān)VC的書籍,在此不再贅述)。 

    l         5 向系統(tǒng)登記熱鍵

      在OnCreate()函數(shù)中加入如下代碼以向系統(tǒng)登記熱鍵,本例子的熱鍵設(shè)為ESC.    

    RegisterHotKey(m_hWnd,1001,NULL, VK_ESCAPE); 

    //函數(shù)參數(shù)請參考有關(guān)VC的書籍,在此不再贅述

    l         6 處理熱鍵 

    在消息處理函數(shù)OnHotKey()中對熱鍵進(jìn)行處理,并可加入用戶希望運(yùn)行的程序代碼等:
         (
    注下面代碼是在HotKeyDlg.cpp中完全用手工加入的代碼)

         LRESULT CHotKeyDlg::OnHotKey(WPARAM wParam,LPARAM lParam)

    {

           HWND hwnd;

           hwnd=::GetForegroundWindow();

           ::PostMessage(hwnd,WM_CLOSE,0,0);

           return 0;

    }

    l         7 程序運(yùn)行完畢后解除熱鍵 

    OnDestroy()中通過UnRegisterHotKey()解除熱鍵登記,釋放系統(tǒng)資源

      UnregisterHotKey( m_hWnd, 1001); 

    l         8 編譯并運(yùn)行程序 
      運(yùn)行程序后,無論何時只要按下熱鍵Esc后本程序便立關(guān)閉當(dāng)前的窗口。

    方法2:利用鍵盤鉤子函獲數(shù)實(shí)現(xiàn)

    說到鉤子函數(shù),可能對許多初學(xué)編程的人很陌生,我這里就多說幾句:

    WINDOW的消息處理機(jī)制為了能在應(yīng)用程序中監(jiān)控系統(tǒng)的各種事件消息,提供了掛接

    各種反調(diào)函數(shù)(HOOK)的功能。這種掛鉤函數(shù)(HOOK)類似擴(kuò)充中斷驅(qū)動程序,掛鉤

    可以掛接多個反調(diào)函數(shù)構(gòu)成一個掛接函數(shù)鏈。系統(tǒng)產(chǎn)生的各種消息首先被送到各種

    掛接函數(shù),掛接函數(shù)根據(jù)各自的功能對消息進(jìn)行監(jiān)視、修改和控制等,然后交還控

    制權(quán)或?qū)⑾鬟f給下一個掛接函數(shù)以致最終達(dá)到窗口函數(shù)。WINDOW系統(tǒng)的這種反

    調(diào)函數(shù)掛接方法雖然會略加影響到系統(tǒng)的運(yùn)行效率,但在很多場合下是非常有用

    的,通過合理有效地利用鍵盤事件的掛鉤函數(shù)監(jiān)控機(jī)制可以達(dá)到預(yù)想不到的良好效果。

    l         1 WINDOW下可進(jìn)行掛接的過濾函數(shù)包括11種:

    WH_CALLWNDPROC 窗口函數(shù)的過濾函數(shù)

    WH_CBT 計(jì)算機(jī)培訓(xùn)過濾函數(shù)

    WH_DEBUG 調(diào)試過濾函數(shù)

    WH_GETMESSAGE 獲取消息過濾函數(shù)

    WH_HARDWARE 硬件消息過濾函數(shù)

    WH_JOURNALPLAYBACK 消息重放過濾函數(shù)

    WH_JOURNALRECORD 消息記錄過濾函數(shù)

    WH_MOUSE 鼠標(biāo)過濾函數(shù)

    WH_MSGFILTER 消息過濾函數(shù)

    WH_SYSMSGFILTER 系統(tǒng)消息過濾函數(shù)

    WH_KEYBOARD 鍵盤過濾函數(shù)

    WH_KEYBOARD_LLWindowsNt4.0以上可用的鍵盤過濾函數(shù)

    WH_MOUSE_LL WindowsNt4.0以上可用的鼠標(biāo)過濾函數(shù)

    l           2 其中鍵盤過濾函數(shù)是最常用最有用的過濾函數(shù)類型,不管是哪一種類型的過濾函

    數(shù),其掛接的基本方法都是相同的。

    WINDOW調(diào)用掛接的反調(diào)函數(shù)時總是先調(diào)用掛接鏈?zhǔn)椎哪莻€函數(shù),因此必須將鍵盤掛

    鉤子函數(shù)利用函數(shù)SetWindowsHookEx()將其掛接在函數(shù)鏈?zhǔn)?。至于消息是否傳遞給函

    數(shù)鏈的下一個函數(shù)是由每個具體函數(shù)功能確定的,如果消息需要傳統(tǒng)給下一個函

    數(shù),可調(diào)用API函數(shù)的CallNextHookEx()來實(shí)現(xiàn),如果不傳遞直接返回即可。

    l         在程序中可以利用函數(shù)SetWindowsHookEx()來掛接過濾函數(shù),在掛接函數(shù)時必須指

    出該掛接函數(shù)的類型、函數(shù)的入口地址以及函數(shù)是全局性的還是局部性的,掛接函

    數(shù)的具體調(diào)用格式如下:

    HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);

    其中,第一個參數(shù)是鉤子的類型;第二個參數(shù)是鉤子函數(shù)的地址;第三個參數(shù)是包

    含鉤子函數(shù)的模塊句柄;第四個參數(shù)指定監(jiān)視的線程。如果指定確定的線程,即為

    線程專用鉤子;如果指定為空,即為全局鉤子。其中,全局鉤子函數(shù)必須包含在DLL

    (動態(tài)鏈接庫)中,而線程專用鉤子還可以包含在可執(zhí)行文件中。得到控制權(quán)的鉤子

    函數(shù)在完成對消息的處理后,如果想要該消息繼續(xù)傳遞,那么它必須調(diào)用另外一個

    SDK中的API函數(shù)CallNextHookEx來傳遞它。鉤子函數(shù)也可以通過直接返回TRUE來丟

    棄該消息,并阻止該消息的傳遞。

    的確如果函數(shù)是全局性的,那么它必須放在一個DLL(動態(tài)鏈接庫)中,但是我發(fā)現(xiàn)在

    window 2000以上的版本中,不用寫 DLL(動態(tài)鏈接庫)就可以作出全局性的鍵盤函數(shù)。用它可以做很多事情。

    UnhookWindowsHookEx(int idHook)函數(shù)即可實(shí)現(xiàn)對掛接鉤子的卸載。

    l         我們開始寫程序吧!用MFC AppWizard建立一個工程名為: KBoardHook基于Dialog base的對話框程序,點(diǎn)擊finish

    l         KBoardHookDlg.cpp的最上邊加上

    HHOOK hhkLowLevelKybd2000;

    hhkLowLevelKybd2000為全局變量。

    l         為方便以后的操作預(yù)先在CKBoardHookDlg類中利用CLASSWIZARD實(shí)現(xiàn)一個響應(yīng)WM_CREATEWM_DESTROY消息的函數(shù)OnCreate( )OnDestroy( )的框架,

    l         OnCreate()函數(shù)中通過SetWindowsHookEx與系統(tǒng)掛起鉤子代碼如下

    hhkLowLevelKybd2000  = SetWindowsHookEx(WH_KEYBOARD_LL,

           LowLevelKeyboardProc,      AfxGetApp()->m_hInstance, 0);

    l         OnDestroy()中通過UnhookWindowsHookEx ()解除已經(jīng)掛起鉤子,釋放系統(tǒng)資源, 代碼如下:        UnhookWindowsHookEx(hhkLowLevelKybd2000);

    l         這時在KBoardHookDlg.h中聲明LowLevelKeyboardProc ,在class CKBoardHookDlg : public Cdialog的上面加入如下代碼

    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);

    // 當(dāng)nCode0(在winuser.h中有如下定義:#define HC_ACTION  0)時wParam, lParam才包含所應(yīng)有的鍵盤信息,wParam的值代表了鍵盤的消息可以為WM_KEYDOWN

    WM_KEYUP, lParam為指向KBDLLHOOKSTRUCT的指針。

     

    l         再在KBoardHookDlg.cpp的最后加入如下代碼(這此代碼都是手工加入的,不能用ClassWzrd

     

     

     

     

     

     

    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)

    {

                  PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;

                  if (nCode == HC_ACTION) {

                         int vKey=LOBYTE(p->vkCode);

                         switch (wParam)

                         {

                         case WM_KEYDOWN:

                                {

                                       if(vKey==27)

                                       {

                                              HWND hwnd;

                                              hwnd=::GetForegroundWindow();

                                              ::PostMessage(hwnd,WM_CLOSE,0,0);

                                       }

                                }

                         }

                        

                  }

                  return CallNextHookEx(NULL, nCode, wParam, lParam);

    }

    這時編譯程序,一共出了6

    其中前兩個錯是

    error C2065: 'WH_KEYBOARD_LL' : undeclared identifier

    error C2065: 'PKBDLLHOOKSTRUCT' : undeclared identifier

    看看msdn 明明說可以有而且在winuser.h中定義了,我試著在KBoardHookDlg.cpp 的前面加入#include "winuser.h" ,但是結(jié)果還是一樣的,我們再追根到底再看看winuser.h,發(fā)現(xiàn)里面明明定義了WH_KEYBOARD_LLPKBDLLHOOKSTRUCT,但是就是不好用,怎么辦呢?把它們找到,復(fù)制到KBoardHookDlg.h中原先手工加入的定義LowLevelKeyboardProc函數(shù)上面(下面就是我們要復(fù)制的代碼)

    #define WH_KEYBOARD_LL     13

    typedef struct tagKBDLLHOOKSTRUCT {

        DWORD   vkCode;

        DWORD   scanCode;

        DWORD   flags;

        DWORD   time;

        DWORD   dwExtraInfo;

    } KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

    這時再編譯程序,程序就可以運(yùn)行了。這樣我們就同樣實(shí)現(xiàn)了改變鍵盤的目的。

     

    小結(jié),上述兩種方法是不同的原理,其加載方法也不盡相同,對于第一種方法其實(shí)現(xiàn)可以在win98/win2000/winXP中都能通用,但對于第兩種方法,其只能在win2000/winXP中應(yīng)用,如果相在win98中應(yīng)用就要寫成dll進(jìn)行調(diào)用,較為繁瑣,但是其功能是強(qiáng)大的,因?yàn)樗桥c系統(tǒng)進(jìn)行了掛鉤,所以用戶在任何窗口下按鍵盤都會觸發(fā)它,例如我們想屏蔽鍵盤,只要把LowLevelKeyboardProc函數(shù)中的

    return CallNextHookEx(NULL, nCode, wParam, lParam);

    改為 return true;

    就可以屏蔽除Ctrl+Alt+Del以外的所有按鍵。

    至于為什么么在winuser.h中定義了那兩個量編譯時卻說沒定義,我也是百思不得其解,希望我寫這篇文章能拋磚引玉,激發(fā)大家學(xué)習(xí)vc的興趣。

     

     

     

     

    (作者同意作品進(jìn)刊盤和網(wǎng)絡(luò)版)

     

                                              聯(lián)系方式:大連理工大學(xué)電子系995班孫宇哲

                                              Email:sunyuzhe@263.net

                                              主頁:http://sunyuzhe.363.net

                                              Tel:0411-4702214

    posted on 2005-05-19 11:35 小魚兒 閱讀(4046) 評論(0)  編輯  收藏 所屬分類: encoding
    主站蜘蛛池模板: 久久久久噜噜噜亚洲熟女综合| 日韩精品视频在线观看免费| 久久91亚洲人成电影网站| 国产精品va无码免费麻豆| 精品国产免费人成电影在线观看| 一级黄色片免费观看| 亚洲精品美女久久久久久久| 亚洲第一区视频在线观看| 亚洲国产精彩中文乱码AV| 免费又黄又爽的视频| 免费特级黄毛片在线成人观看| jjizz全部免费看片| 亚洲a一级免费视频| 青柠影视在线观看免费| CAOPORM国产精品视频免费| 美女羞羞喷液视频免费| 最新亚洲人成网站在线观看| 亚洲码欧美码一区二区三区| 亚洲国产精品一区二区三区在线观看 | 亚洲精品无码久久不卡| 国产成人精品123区免费视频| 日韩毛片免费无码无毒视频观看| 最近免费2019中文字幕大全| 日本免费在线观看| 嫩草在线视频www免费观看| 成人免费区一区二区三区| 中国内地毛片免费高清| 久久免费视频一区| 两个人看的www免费视频中文| 国产特黄一级一片免费 | 国产精品亚洲аv无码播放| 三上悠亚亚洲一区高清| 久久亚洲高清综合| 亚洲无线码一区二区三区| 亚洲一级Av无码毛片久久精品| 久久久久亚洲精品无码网址| 国产亚洲精品无码成人| 国产成人精品日本亚洲网站| 亚洲av无码专区在线播放| 亚洲美女大bbbbbbbbb| 亚洲 欧洲 日韩 综合在线|