程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 利用底層鍵盤鉤子攔載任意按鍵(回調版)

利用底層鍵盤鉤子攔載任意按鍵(回調版)

編輯:關於VC++

前段時間我曾經寫過一篇《利用底層鍵盤鉤子屏蔽任意按鍵》,並放到了我的blog上。這 篇文章的題目中把“屏蔽”改成了“攔截”,顯然要比以前的版本強 一些了。對於以前寫的那個DLL,有一個不夠理想的地方,就是僅僅能實現屏蔽。如果想在屏 蔽之前加入一些“小動作”,就只能修改DLL,在LowLevelKeyboardProc函數中添 加代碼,實現新的功能。但這樣顯然不夠靈活,這樣的DLL也不具備一般性了。所以我自然而 然地想到了回調,Windows中有很多需要回調函數的API,我們當然也可以寫出這樣的API,這 樣做的好處就是可以給DLL調用程序留下足夠的接口。此時,DLL就像一個閥門,我們不關心 的按鍵消息就把它放過去,只把我們關心的按鍵消息攔截下來,然後進一步處理,而這些處 理的代碼就寫在DLL調用程序的回調函數中,這樣做是最理想不過的了。

相對於前一 個版本,修改後的DLL源代碼如下:

/********************************************************************/< br />/* 文件名: MaskKey.cpp                       */
/*                                 */
/* 功能: 標准 DLL ---- 利用底層鍵盤鉤子實現攔截鍵盤任意按鍵     */
/*                                  */
/* 作者: 盧培 培 (goodname008)      

當然了,MaskKey.h頭文件中也要加上:

// 回調函數指針
typedef BOOL (CALLBACK* LPFNKEYBOARDPROC)(WPARAM, KBDLLHOOKSTRUCT*);

 

下面是在VC中調用的例子:(兩個Dialog的成員函數, 對應兩個按鈕,再加上一個回調函數)

// 全局鍵盤鉤子回調函數
// 參數: action 標識鍵盤消息(按下,彈起), keyStruct 包含按鍵信息
BOOL CALLBACK KeyboardProc(WPARAM action, KBDLLHOOKSTRUCT* pKeyStruct)
{
// 判斷按鍵 動作
switch (action)
{
case WM_KEYDOWN:
break;
case WM_KEYUP:
break;
case WM_SYSKEYDOWN:
break;
case WM_SYSKEYUP:
break;
}
// 返回 true 表示繼續傳遞按鍵消息
// 返 回 false 表示結束按鍵消息傳遞
return false;
}
void CMaskKeyAppDlg::OnStartmaskkey()
{
// 屏蔽 A, B, C, 上, 下, 左, 右及兩 個win鍵
DWORD dwVK[] = {'A', 'B', 'C', VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_LWIN, VK_RWIN};
int nLength = sizeof(dwVK) / sizeof(DWORD);
StartMaskKey(dwVK, nLength, KeyboardProc);  
}
void CMaskKeyAppDlg::OnStopmaskkey()
{
StopMaskKey();
}

 

呵呵,這樣是不是讓看到這裡的你很興奮呢?!StartMaskKey加了一個參數 ,是個函數指針,這是我們非常熟悉的回調函數的使用方法。DLL中的StartMaskKey函數收到 這個函數指針後保存在了g_lpfnKeyboardProc變量中,然後在LowLevelKeyboardProc中一旦 發現了要攔截的按鍵,就會通過函數指針調用回調函數,將控制權完全交回給DLL的調用程序 ,由回調函數KeyboardProc進一步處理(播放一小段音樂,還是執行個什麼有意思的程序, 亦或是重啟關機什麼的。呃,隨你便了。:D),action參數用來標識鍵盤消息(按下或彈起 ),pKeyStruct參數包含了豐富的按鍵信息,其實就是系統傳給LowLevelKeyboardProc的 lParam,我又把它原封不動地傳給了KeyboardProc,呵呵。最重要的就是回調函數的返回值 了,它就像閥門的開關一樣,將決定這個按鍵消息的命運。從DLL中的LowLevelKeyboardProc 函數的流程可以看出,如果回調函數KeyboardProc的返回值為true則表示把該按鍵消息繼續 傳遞給系統中的下一個鉤子;如果為false則表示結束該按鍵消息的傳遞,此時將會起到攔截 按鍵的效果。

用VB的人可能有些不耐煩了,別著急,上篇文章在最後給出了VB調用的 例程,此篇當然不能缺少這部分了。下面是在VB中調用的例子:(在窗體上添加2個 CommandButton,並分別改名為cmdStartMask和cmdStopMask)

Option Explicit
Private Declare Function StartMaskKey Lib "MaskKey" (lpdwVirtualKey As Long, ByVal nLength As Long, ByVal lpfnKeyboarProc As Long, Optional ByVal bDisableKeyboard As Boolean = False) As Long
Private Declare Function StopMaskKey Lib "MaskKey" () As Long
Private Sub cmdStartMask_Click()
' 屏蔽 A, B, C, 上, 下, 左, 右及兩個win鍵
Dim key(8) As Long
key(0) = vbKeyA
key(1) = vbKeyB
key(2) = vbKeyC
key(3) = vbKeyLeft
key(4) = vbKeyRight
key(5) = vbKeyUp
key(6) = vbKeyDown
key(7) = &H5B        ' 左邊的win鍵
key(8) = &H5C        ' 右邊的win鍵
StartMaskKey key(0), UBound(key) + 1, AddressOf KeyboardProc
End Sub
Private Sub cmdStopMask_Click()
StopMaskKey
End Sub

 

窗體模塊的代碼和以前的例程幾乎一樣,只是 在調用StartMaskKey函數時加了一個參數:AddressOf KeyboardProc。在VB中用過回調函數 的人對這東西絕不會陌生,AddressOf是一個一元運算符,後面接一個函數名,它的功能就是 獲得指定函數的指針。但有一點必須注意,該回調函數(此例中為KeyboardProc)必須寫在 VB的標准模塊中,標准模塊的代碼如下:

Option Explicit
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
Public Type KBDLLHOOKSTRUCT
vkCode As Long       ' 虛擬按鍵碼(1--254)
scanCode As Long      ' 硬件按鍵掃描碼
flags As Long         ' flags
time As Long        ' 消息時間戳
dwExtraInfo As Long    ' 額外信息
End Type
Public Enum KEYACTION
ACTION_KEYDOWN = WM_KEYDOWN
ACTION_KEYUP = WM_KEYUP
ACTION_SYSKEYDOWN = WM_SYSKEYDOWN
ACTION_SYSKEYUP = WM_SYSKEYUP
End Enum
' 全局 鍵盤鉤子回調函數
' 參數: action 標識鍵盤消息(按下,彈起), keyStruct 包含 按鍵信息
Public Function KeyboardProc(ByVal action As KEYACTION, keyStruct As KBDLLHOOKSTRUCT) As Boolean
Select Case action
Case ACTION_KEYDOWN
Debug.Print keyStruct.vkCode, "按下鍵盤按鍵"
Case ACTION_KEYUP
Debug.Print keyStruct.vkCode, "彈起鍵盤按鍵 "
 
Case ACTION_SYSKEYDOWN
Case ACTION_SYSKEYUP
End Select
' 返回 True 表示繼續傳遞按鍵消息
' 返回 False 表示結束按 鍵消息傳遞
KeyboardProc = False
End Function

 

和VC版的調用 例程差不多,只是把語法翻譯成了VB的,這個VB標准模塊中的KeyboardProc有沒有點MFC消息 映射函數的味道呢?!  :D

需要注意的是,VB的回調函數必須寫在標准模塊中。細 心的人還可能會發現,我對action參數作了一點小手腳,改成了一個枚舉類型,這主要是為 了易於理解。

OK,要寫的就這麼多了,關於全局鍵盤鉤子的內容我也想告一段落了。 利用VC編寫的DLL,VB也可以方便地實現全局鍵盤鉤子了。當然,這不僅僅局限於鍵盤鉤子, 利用這種方法可以實現任何類型的鉤子。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved