好久没写博客了,呵呵。今天再来写一篇。再次申明:菜鸟言论仅供娱乐。
最近一直在准备一个比赛,所以进度就慢了下来。突然于几天前突发奇想想自己做一个魔兽的改建,而且自己觉得也挺简单的,有现成的钩子模版,随便写写就行了,哪知道遇到了困难。正应了那就话啊:当你轻视它的时候,他就会轻视你。
错误的原因来自于我对windows消息机制的理解错误。我一开始以为消息是在钩子链中一级一级传递的,直到传递到最后一级钩子,最后一级的钩子函数通过调用CallNextHookEx将消息传递给焦点窗口。所以自己在搞的时候发现无论如何都改不了键。“列宁”说,消息在第一个钩子的时候就已经将消息发给焦点窗口了,说我的理解有问题,呵呵,看来我还得去查查windows消息在钩子间的传递原理,这篇博客就不写了,我会在弄清楚以后写在另一篇博客中。
于是上网找了找魔兽改键的开源代码,发现上面使用的是keybd_event来合成一个键盘的按建消息。于是做了一下,中间虽然出了一些小问题(全局变量的共享问题,一开始没发现“列宁”发现的,呵呵,本菜鸟总是在这边判断错),但是最终还是成功了。
按照大神的说法keybd_event是已经废弃的API函数,可以使用热键+SendInput函数简单的解决这个问题,SendInput函数实际上就是调用了keybd_event函数来实现相应的功能。代码也给了我看了一下,确实很简单,因为本菜鸟经验有限,想要实现将消息传给焦点窗口但又不知道有什么函数能实现这样的功能,知道有SendInput这种神器之前已经写好代码了。所以就贴出了我的代码,至于用SendInput实现上述功能的代码,虽然有,但是未经大神同意也不能乱贴,其基本思想是RegisterHotKey+SendInput,有兴趣的人可以自己做。
废话我就不多说了,下面贴出我的部分核心代码,主要是动态链接库的,MFC的代码我就不贴了,很容易的。而且我只做了能改一个键的改建,想改很多键只要将所有存储字符的变量改成字符数组就行了,也很简单。
#include "Windows.h" #define KEYHOOKLIB_EXPORTS #include "winuser.h" #include "Keydll.h" HHOOK g_hHook=NULL; #pragma data_seg("MyShared") //注意此处数据要共享 char old=0; #pragma data_seg() HMODULE WINAPI ModuleFromAddress(PVOID pv) { MEMORY_BASIC_INFORMATION mbi; if(::VirtualQuery(pv,&mbi,sizeof(mbi))!=0) return (HMODULE)mbi.AllocationBase; else return NULL; } LRESULT CALLBACK KeyHookProc(int nCode,WPARAM wParam,LPARAM IParam) { if ((int)old==wParam) { keybd_event(VK_NUMPAD8,0,0,0); // keybd_event(VK_NUMPAD1,0,KEYEVENTF_KEYUP,0); return 1; } return CallNextHookEx(g_hHook,nCode,wParam,IParam); } BOOL WINAPI SetKeyHook(BOOL bInstall,DWORD dwThreadId,TCHAR Left) { BOOL bOk; old=(char)Left; if(bInstall) { g_hHook=::SetWindowsHookEx(WH_KEYBOARD,KeyHookProc,ModuleFromAddress(KeyHookProc),dwThreadId); bOk=(g_hHook!=NULL); } else { bOk=::UnhookWindowsHookEx(g_hHook); g_hHook=NULL; } return bOk; }
头文件:
#ifdef KEYHOOKLIB_EXPORTS #define KEYHOOKLIB_API __declspec(dllexport) #else #define KEYHOOKLIB_API __declspec(dllimport) #endif BOOL KEYHOOKLIB_API WINAPI SetKeyHook(BOOL bInstall,DWORD dwThreadId,TCHAR Left);
效果如下图:
另外朋友们如果有关于消息(特别是键盘消息)如何在钩子间传递以及如何传递到焦点窗口的消息机制的资料,如果愿意的话,还请和我这个菜鸟分享一下,谢谢了。