首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

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

     編輯:關於VC++

前陣子曾撰寫《利用底層鍵盤鉤子屏蔽任意按鍵》並發表於部落格。本文標題將「屏蔽」改為「攔截」,功能更強大。舊版 DLL 僅能實現屏蔽,若想在屏蔽前加入「小動作」,必須修改 DLL 在 LowLevelKeyboardProc 中添加程式碼,缺乏彈性與通用性。因此引入回調機制:Windows 許多 API 需回調函式,我們也可撰寫此類 API,給 DLL 呼叫程式保留充足介面。DLL 如同閥門,不關心的按鍵訊息放行,只攔截關心的按鍵訊息進一步處理,處理程式碼寫在 DLL 呼叫程式的回調函式中,最理想不過。

修改後的 DLL 原始碼

/********************************************************************/
/* 檔案名: 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 呼叫程式。action 參數標識鍵盤訊息,pKeyStruct 包含豐富按鍵資訊(實際為系統傳給 LowLevelKeyboardProc 的 lParam)。最重要的是回調函式回傳值:如閥門開關決定按鍵訊息命運。若回傳 true 則繼續傳遞給系統下一個鉤子;若 false 則結束傳遞,達到攔截效果。

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

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。對 action 參數改用列舉型別以利理解。VB 回調函式必須寫在標準模組中。

結語

關於全域鍵盤鉤子內容告一段落。利用 VC 撰寫的 DLL,VB 也能方便實現全域鍵盤鉤子。當然不僅限於鍵盤鉤子,此方法可實現任何類型鉤子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved