(注意:本章没有用到DLL,而是直接钩住当前程序!!)
首先列举 一下WindowsHOOK基本的函数(主要关于键盘…):
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);
LRESULT WINAPI CallNextHookEx(
_In_opt_ HHOOK hhk,
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
BOOL WINAPI UnhookWindowsHookEx(
_In_ HHOOKhhk
);
LRESULT CALLBACK KeyboardProc(
_In_ int code,
_In_ WPARAMwParam,
_In_ LPARAMlParam
);
LRESULT CALLBACK LowLevelKeyboardProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
注意 上面的 KeyboardProc 和 LowLevelKeyboardProc 函数,前者是普通的钩子函数,而后者是一个低级的钩子函数,这两个函数的参数不同,所以要获取的值也不同!!
摘自MSDN:
KeyboardProc的函数参数(wparam和lparam)使用
wParam [in]
Type: WPARAM
The virtual-key code of the key thatgenerated the keystroke message.
lParam [in]
Type: LPARAM
The repeat count, scan code, extended-key flag, contextcode, previous key-state flag, and transition-state flag. For more informationabout thelParam parameter, seeKeystroke Message Flags. The following table describes the bits of this value.
由此可看出 ,wparam主要是键盘的虚拟键代码,lparam主要是:
The lParam parameter of a keystroke message containsadditional information about the keystroke that generated the message. Thisinformation includes therepeat count, the scan code, the extended-key flag, thecontext code, the previous key-state flag, and the transition-state flag.The following illustration shows the locations of these flags and values in thelParam parameter.
怎么说呢,这个参数其实主要看16-23位,刚好达到8位,也就是一个扫描码!
那么像这样的参数给我们有什么用啊?其实如果你 用过函数 GetKeyNameText
就知道了,他的第一个参数就是lparam,也就是KeyboardProc 第三个参数!!是不是很巧?就是用他来获取到按下的键盘名,所以这个函数 可以和KeyboardProc 一起使用!
下面就介绍 LowLevelboardProc 函数,参数和KeyboardProc 一样,但是参数所起的作用差距很大,可谓 失之毫厘,差之千里~~
当 SetWindowsHookEx() 参数idHOOK 为WH_KEYBORAD_LL时,这个函数的参数中的wparam 为 键盘消息,如WM_KEYDOMN… 那么lparam 就是一个 LPKBDLLHOOKSTRUCT结构体了!看这个结构体的名字就知道这是一个用于 低级键盘钩子的,“LL”->”LowLevel“,呵呵~这个结构体中 包括了 虚拟键代码 和 扫描码!
如上所述,我们大概就知道LowLevelboardProc 和 KeyboardProc的差别了,
但别忘了还有那个 SetWindowsHookEx()函数,现在在回忆一下那个函数原型:
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);
当IdHook为WH_KEYBOARD 时,lpfn为KeyboardProc(名字自定义),hMod为当前程序实例句柄,MFC 有多种方法获取,如:AfxGetInstanceHandle()
最后一个 dwThreadId为0!!至于为什么,我现在还不是很清楚,希望有大神解答…
所以,当idHook为WH_KEYBOARD_LL时,dwThreadid 必须为当前模块的线程ID!
看下图来对比下:
据此,我把主要代码给出来
HHOOK hHook2;
LRESULT CALLBACK KeyBoradProc(intcode,WPARAMwp,LPARAMlp)
{
if (code<0)
{
return CallNextHookEx(hHook2,code,wp, lp);
}
WCHAR szkeyValue[20]={ 0 };
//wsprintf(szkeyValue, L"%c", wp); //虚拟键代码
//获取按键的名称
GetKeyNameText(lp,szkeyValue, 50);
AfxGetMainWnd()->SetDlgItemText(IDC_EDIT1,szkeyValue);
return CallNextHookEx(hHook2,code,wp, lp);
}
//安装键盘钩子
hHook2 = SetWindowsHookEx(WH_KEYBOARD,KeyBoradProc,AfxGetInstanceHandle(),GetCurrentThreadId()); //注意这里的线程ID为当前程序的线程ID!
//卸载钩子
UnhookWindowsHookEx(hHook2);
下面是关于低级键盘钩子的代码;
//低级的键盘钩子
hHook= ::SetWindowsHookEx(WH_KEYBOARD_LL,myLowLevelKeyboardProc,AfxGetInstanceHandle(),0);//注意这里TID为 0
//卸载低级钩子
UnhookWindowsHookEx(hHook)
//低级钩子函数处理过程
LRESULT CALLBACK LowLevelKeyboardProc(_In_int code,_In_WPARAMwParam,_In_LPARAMlParam)
{
if (code < 0)
{
returnCallNextHookEx(hHook,code,wParam, lParam);
}
// 低级键盘钩子时,wparam参数为 WM键盘消息!!!
//按下的
if (code ==HC_ACTION&&wParam==WM_KEYDOWN)
{
LPKBDLLHOOKSTRUCTpKbs = (LPKBDLLHOOKSTRUCT)lParam;
WCHARszlMsg[100] = { 0 };
wsprintf(szMsg,L"vkCode:%c-scanCode:%02X",pKbs->vkCode,pKbs->scanCode);
//ESC键扫描码
if (pKbs->scanCode==0x01)
{
returnTRUE;
}
}
return CallNextHookEx(hHook,code,wParam, lParam);
}
基本上注释已经说明了,那么本文也就到此结束了…