魔兽改键
关键词:dota,hook
作者:BIce 创建时间:2013-03-17 00:06:43
最近实在是受不了之前用的Dota改键器频繁的跳广告了,遂决定自己写个吧,反正也觉得不难。今天就花了大概一天的时间写了个..发现还真不大好写。
要做的事是把正常按键的2,3,4,5键换成小键盘的7,8,4,5即可(我用的改键比较简单),这样做的话就需要对正常的按键进行截获并进行转换。正常的技术方案就是使用hook技术对War3的程序进行挂接,进行WH_KEYBOARD事件的hook,针对具体的按键事件,进行转换并使用PostMessage方法模拟按键即可。
另外由于使用的是全局的Hook所以HookProc需要在DLL中实现,需要做的事也就有两个:一个获取War3线程ID,加载DLL然后获取HookProc函数,最后设置hook的主程序;一个包括HookProc的DLL程序。下面针对这两个方面进行简单的总结:钩子和DLL。
钩子:是Windows事件机制的一个监视点,可以对某个程序的事件在执行过程进行额外的处理,如加工事件或是对事件进行转换屏蔽。而钩子的处理过程中有一个HookChain,新设置的钩子会被加到HookChain的首部,对事件进行处理,正常的钩子处理机制需要在处理事件之后将其传递到下一个钩子中。
钩子又分局部的和全局的,局部的钩子用于挂接到本程序,全局的钩子用于挂接到其他的程序中,而这种全局的钩子由于要把HookProc的地址空间也都加载到目标程序,就需要使用DLL的方式加入到目标程序即可,HookProc代码放入DLL中。
DLL:动态链接库,一般分为.h和实现两种文件,.h作为头文件暴露DLL中的功能函数,实现被编译成DLL文件。需要导出的方法,需要在声明前加上__declspec(dllexport)语句。而作为C++的程序,需要注意加入extern "C" 防止c++编译器将实现的函数名换成其他的内容;也可以使用.def文件来指定接口函数的内容。(使用CodeBlocks编译的DLL在Debug目录中会生成,不知道功能函数名的话可以看这个文件就知道了)。
另外DLL函数的调试实在是很费事,我也没弄明白具体怎么调,最后就用输出日志的方式来做了,反正写惯了脚本程序没有调试器也可以的。
下面将两部分程序主要部分列出:
挂接钩子的主程序:
bool firstFlag=true;
while(true){
war3Hwnd=FindWindow(NULL,"Warcraft III"); //先找到war3窗口句柄
if(war3Hwnd!=NULL){
cout<<"Find War3 Game. Hook Set."<
}
if(firstFlag){
cout<<"War3 is not open. Waiting For the Game!"<
}
Sleep(2000);
}
HWND hwnd=FindWindow(NULL,"Warcraft III");
if(code<0){
//将消息传递给下一个钩子
return ::CallNextHookEx(NULL,code,wParam,lParam);
}
bool up=(lParam>>31)&0x01;//是否为抬起按键.
int mappedKey=0; //转换后的键值
if(mappedKey==0){
}
//logfile<<"isUp"<
switch(wParam){
case 0x32:
//数字2
mappedKey=VK_NUMPAD7;
break;
case 0x33:
//数字3
mappedKey=VK_NUMPAD8;
break;
case 0x34:
//数字4
mappedKey=VK_NUMPAD4;
break;
case 0x35:
//数字5
mappedKey=VK_NUMPAD5;
break;
case 0x36:
//数字6
mappedKey=VK_NUMPAD1;
break;
case 0x37:
//数字7
mappedKey=VK_NUMPAD2;
break;
default:
break;
}
//不是要转换的键
return ::CallNextHookEx(NULL,code,wParam,lParam);
}
//logfile<<"Mappped Key"<
//hwnd=FindWindow(NULL,"Warcraft III"); //先找到war3窗口句柄
if(up){
PostMessage(hwnd,WM_KEYUP,mappedKey,lParam);
}
else{
PostMessage(hwnd,WM_KEYDOWN,mappedKey,lParam);
}
//logfile<<"end.";
//logfile.close();
return 1;//返回非零值,防止系统将事件继续沿Hook链发送