利用底层键盘钩子拦载任意按键(回调版)

前段时间我曾经写过一篇《利用底层键盘钩子屏蔽任意按键》,并放到了我的 blog 上。这篇文章的题目中把“屏蔽”改成了“拦截”,显然要比以前的版本强一些了。对于以前写的那个 DLL ,有一个不够理想的地方,就是仅仅能实现屏蔽。如果想在屏蔽之前加入一些“小动作”,就只能修改 DLL ,在 LowLevelKeyboardProc 函数中添加代码,实现新的功能。但这样显然不够灵活,这样的 DLL 也不具备一般性了。所以我自然而然地想到了回调, Windows 中有很多需要回调函数的 API ,我们当然也可以写出这样的 API ,这样做的好处就是可以给 DLL 调用程序留下足够的接口。此时, DLL 就像一个阀门,我们不关心的按键消息就把它放过去,只把我们关心的按键消息拦截下来,然后进一步处理,而这些处理的代码就写在 DLL 调用程序的回调函数中,这样做是最理想不过的了。

相对于前一个版本,修改后的 DLL 源代码如下:

/********************************************************************/

/* 文件名 : MaskKey.cpp */

/* */

/* 功能 : 标准 DLL ---- 利用底层键盘钩子实现拦截键盘任意按键 */

/* */

/* 作者 : 卢培培 (goodname008) 时间 : 2005.1.18 */

/* */

/* BLOG: http://blog.csdn.net/goodname008 */

/********************************************************************/

// 导出函数列表

// StartMaskKey

// StopMaskKey

#define _WIN32_WINNT 0x0500 // 设置系统版本 , 确保可以使用底层键盘钩子

#include "windows.h"

// 回调函数指针

typedef BOOL (CALLBACK* LPFNKEYBOARDPROC)(WPARAM, KBDLLHOOKSTRUCT*);

// 全局变量

LPDWORD g_lpdwVirtualKey = NULL; // Keycode 数组的指针

int g_nLength = 0; // Keycode 数组的大小

BOOL g_bDisableKeyboard = FALSE; // 是否屏蔽整个键盘

HINSTANCE g_hInstance = NULL; // 模块实例句柄

HHOOK g_hHook = NULL; // 钩子句柄

LPFNKEYBOARDPROC g_lpfnKeyboardProc; // 键盘钩子回调函数指针

// DLL 入口函数

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

// 保存模块实例句柄

g_hInstance = (HINSTANCE)hModule;

// 在进程结束或线程结束时卸载钩子

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

break ;

case DLL_THREAD_ATTACH:

break ;

case DLL_PROCESS_DETACH:

case DLL_THREAD_DETACH:

free(g_lpdwVirtualKey);

if (g_hHook != NULL) UnhookWindowsHookEx(g_hHook);

break ;

}

return TRUE;

}

// 底层键盘钩子函数

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

{

// 拦截键盘的某些按键 , 如果 g_bDisableKeyboard 为 TRUE 则拦截整个键盘按键

if (nCode >= HC_ACTION)

{

KBDLLHOOKSTRUCT* pStruct = (KBDLLHOOKSTRUCT*)lParam;

if (g_bDisableKeyboard)

if (g_lpfnKeyboardProc(wParam, pStruct))

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

else

return true ;

LPDWORD tmpVirtualKey = g_lpdwVirtualKey;

for ( int i = 0; i < g_nLength; i++)

{

if (pStruct->vkCode == *tmpVirtualKey++)

if (g_lpfnKeyboardProc(wParam, pStruct))

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

else

return true ;

}

}

// 调用系统中的下一个钩子

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

}

/********************************************************************/

/* 开始拦截键盘按键 */

/* */

/* 参数 : */

/* lpdwVirtualKey Keycode 数组的指针 */

/* nLength Keycode 数组的大小 */

/* bDisableKeyboard 是否拦截整个键盘 */

/* */

/* 返回值 : TRUE 成功 , FALSE 失败 */

/********************************************************************/

BOOL WINAPI StartMaskKey(LPDWORD lpdwVirtualKey, int nLength,

LPFNKEYBOARDPROC lpfnKeyboardProc, BOOL bDisableKeyboard = FALSE)

{

// 如果已经安装键盘钩子则返回 FALSE

if (g_hHook != NULL || nLength == 0) return FALSE;

// 将用户传来的 keycode 数组保存在全局变量中

g_lpdwVirtualKey = (LPDWORD)malloc( sizeof (DWORD) * nLength);

LPDWORD tmpVirtualKey = g_lpdwVirtualKey;

for ( int i = 0; i < nLength; i++)

{

*tmpVirtualKey++ = *lpdwVirtualKey++;

}

g_nLength = nLength;

g_bDisableKeyboard = bDisableKeyboard;

g_lpfnKeyboardProc = lpfnKeyboardProc;

// 安装底层键盘钩子

g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, g_hInstance, NULL);

if (g_hHook == NULL) return FALSE;

return TRUE;

}

/********************************************************************/

/* 停止拦截键盘按键 */

/* */

/* 参数 : ( 无 ) */

/* */

/* 返回值 : TRUE 成功 , FALSE 失败 */

/********************************************************************/

BOOL WINAPI StopMaskKey()

{

// 卸载钩子

if (UnhookWindowsHookEx(g_hHook) == 0) return FALSE;

g_hHook = NULL;

return TRUE;

}


当然了, 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();

}


<SPAN style="mso-tab-cou

Published At
Categories with Web编程
Tagged with
comments powered by Disqus