主要原理:通过线程钩子截获魔兽进程的键盘消息,然后模拟我们所需要的按键。软件设计基于MFC和用到的一些windowsAPI。

1.     界面布局和要求功能


软件界功能少见面简单,主要有小键盘和自定义的改键。(玩dota的都知道)

要求:编辑框只能显示一个键的字符且大写,按空格键时最好显示“空”,按键定义不能重复,显示改键开启状态。

2.     动态链接库

软件的核心是键盘钩子。先要写个动态链接库DLL。主要函数SetWindowsHookEx,参见MSDN。DLL主要有cpp文件和def输出函数定义文件。

将用户界面设置的改建前和改建后的按键字符保存在两个字符数组中。

由于钩子的回调函数LRESULTCALLBACK KeyboardProc在dll中,而用户的改键设置保存在主程序中,所以我们在启动改键时需要将改键的设置传入dll中,通过共享数据块保存。

Dll中的函数在主函数中的声明,否则无法调用

在主程序StdAfx.h中:

_declspec(dllimport) void setHook(HWND hwnd,char *pre,char *fin);
_declspec(dllimport) void deleHook();
_declspec(dllimport) void chat(int flag);
#pragma comment(lib,"War3hook.lib")//链接dll编译生成的lib文件

war3hook.def:主要是输出这三个函数然后在主程序中调用

LIBRARY War3hook
EXPORTS
setHook @2
deleHook @3
chat @4

war3hook.cpp:

#include <windows.h>#pragma   data_seg("MYSEC")
char prek[11]={0};
char fink[11]={0};//改键设置保存
HWND g_hWnd=NULL;//保存魔兽窗口句柄
int chaton=0;//监听聊天状态
#pragma   data_seg()
#pragma   comment(linker, "/section:MYSEC,rws")
//共享数据块定义HHOOK g_hKeyboard;//钩子句柄
char flag=NULL;//用来保存返回的该键字符void chat(int chflag)//主程序中调用将聊天状态传入dll中
{chaton=chflag;
}
char findkey(char ch)//知道需要改建的ch返回改建后的键字符,如果没有则返回’*’
{int index=0;for (index=0;index<11;index++){if (prek[index]==ch){if (fink[index]!='*'){if (fink[index]>=0x31&&fink[index]<=0x38){return (fink[index]+0x30);}return fink[index];}}}return '*';
}
void deleHook()//卸载钩子
{UnhookWindowsHookEx(g_hKeyboard);
}
LRESULT CALLBACK KeyboardProc(int code,       // hook codeWPARAM wParam,  // virtual-key codeLPARAM lParam   // keystroke-message information&&((lParam>>30&1)==0))//键盘钩子的回调函数
{if (1==chaton)//如果聊天取消改键{return CallNextHookEx(g_hKeyboard,code,wParam,lParam);}flag=findkey((char)wParam);//获取改键,若不许改建则返回‘*’if (flag!='*'&&((lParam>>31&1)==0))//判断是否改键和键盘的按下状态,否则按键弹起时也执行,造成按两次键{keybd_event(flag,0,0,0 );keybd_event(flag,0,KEYEVENTF_KEYUP,0);//模拟改键return 1;//使已经按下的键失效}return CallNextHookEx(g_hKeyboard,code,wParam,lParam);
}void setHook(HWND hwnd,char *pre,char *fin)
{g_hWnd=hwnd;//保存魔兽句柄for (int i=0;i<11;i++){prek[i]=*(pre+i);}for (int j=0;j<11;j++){fink[j]=*(fin+j);}//将用户改键设置传入dll中的共享数组中g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("War3hook"),GetWindowThreadProcessId(g_hWnd,NULL));//设置键盘钩子
}

3.主程序编辑框的处理

 

在相应编辑框数据改变的响应函数中处理:

void CWar3KeyDlg::OnChangeEdit7()
{CString tempstr;tempstr=m_EDIT7;UpdateData(TRUE);m_EDIT7=inputkey(m_EDIT7,tempstr);//inputkey为自定义函数,将编辑框中现在的内容减去原来的内容if (checkrepeat(m_EDIT7)==FALSE)// checkrepeat为自定义函数,防止按键定义重复{m_EDIT7="";AfxMessageBox("按键重复定义!");}if (m_EDIT7==" "){m_EDIT7="空";UpdateData(FALSE);//为了显示‘空’m_EDIT7=" ";}else{UpdateData(FALSE);}
}

检测魔兽聊天状态和游戏开始的实现:

方法:通过Cheat Engine搜寻魔兽进程的内存内容,其中有两个内存块是聊天状态和游戏是否进行的状态标示。不同的游戏版本应该不一样,然后通过ReadProcessMemory()函数读取该内存的值,通过定时器监视,作出相应的相应。但是,主程序要想读魔兽内存必须要有权限,可以下面方法提升权限。

开启改键按钮中的部分代码:

HWND m_hwnd=::FindWindow("Warcraft III","Warcraft III");//需找魔兽句柄if (m_hwnd==NULL){AfxMessageBox("Warcraft III 未运行!");return;}DWORD PID;::GetWindowThreadProcessId(m_hwnd,&PID);//获取魔兽进程idif (PID==NULL){AfxMessageBox("进程ID获取失败");return;}m_War3ProcessID=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,PID);//获取魔兽进程句柄if (m_War3ProcessID==NULL){AfxMessageBox("进程句柄获取失败");return;}GetDlgItem(IDC_STATIC_yn)->SetWindowText("已开启改键");//静态框状态显示GetDlgItem(IDC_BTNRun)->EnableWindow(FALSE);setHook(m_hwnd,pkey,fkey);//调用dll中函数设置键盘钩子SetTimer(1,100,0);//启动定时器,开始监视EnableDebugPrivilege(TRUE);//提升权限,该函数为自定义函数

开关函数权限的定义:

BOOL CWar3KeyDlg::EnableDebugPrivilege(BOOL bEnableDebugPrivilege)
{HANDLE hToken;TOKEN_PRIVILEGES tp;LUID luid;if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)){::MessageBox(this->GetSafeHwnd(),"GET_TOKEN_ERROR","MSG_BOX_TITLE", MB_OK);return FALSE;}if(!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)){::MessageBox(this->GetSafeHwnd(),"GET_PRIVILEGE_VALUE_ERROR","MSG_BOX_TITLE", MB_OK);::CloseHandle(hToken);return FALSE;}tp.PrivilegeCount = 1;tp.Privileges[0].Luid = luid;if(bEnableDebugPrivilege){tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;}else{tp.Privileges[0].Attributes = 0;}if(!::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)){::MessageBox(this->GetSafeHwnd(),"ADJUST_PRIVILEGE_ERROR","MSG_BOX_TITLE", MB_OK);::CloseHandle(hToken);return FALSE;}::CloseHandle(hToken);if(::GetLastError() == ERROR_NOT_ALL_ASSIGNED){::MessageBox(this->GetSafeHwnd(),"ENABLE_DEBUG_ERROR","MSG_BOX_TITLE", MB_OK);return FALSE;}return TRUE;
}

定时器中的代码:

int buf=0;//临时保存聊天状态,0为操作状态,1为聊天状态,
int buf2=0; //临时保存游戏是否开启状态,1为游戏进行状态,0为未开始if (::ReadProcessMemory(m_War3ProcessID,(LPCVOID)0x6fad15f0,&buf,4,NULL)){//0x6fad15f0为相对内存地址chat(buf);//调用dll中函数,将聊天状态传入,共享数据块中,在钩子回调函数需要判断是否改建}if (::ReadProcessMemory(m_War3ProcessID,(LPCVOID)0x6fadb3d8,&buf2,4,NULL)){if (buf2==1&&m_GameRun==FALSE)// m_GameRun保存游戏是否进行的状态{m_GameRun=TRUE;if (::IsIconic(temphwnd)==TRUE){AfxMessageBox("游戏开始啦!!!");//如果魔兽此时是最小化且魔兽从未开始到进行则说明魔兽运行了,弹出消息提示::SetWindowPos(this->GetSafeHwnd(),HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);::SetForegroundWindow(this->GetSafeHwnd());}}else if (buf2==0){m_GameRun=FALSE;}}

至于

按键设置的保存:主要将两个改建前和改建后的字符串保存在ini文件中,没有加密,关闭时保存,启动时读取即可。

软件防重复:在窗口未创建前在app里的InitInstance()函数中通过EnumWindows函数搜寻是否有同名的函数,有则直接返回。

程序托盘:有固定形式,可百度google

hfut   tdk

源码 http://download.csdn.net/detail/tandyky/3683250

简单魔兽改键的基本原理及基于MFC实现相关推荐

  1. 基于键盘钩子的dota改键(单线程+DLL)MFC实现(源码+总结)

    呼..终于可以摒弃网上带广告的改键工具了.. 历经三天,写出自己的dota改键软件最简单版了. 还学习了两个新知识,钩子和动态链接库.下面以一个新手的角度,总结下这三天遇到的大小问题. 一般钩子在什么 ...

  2. c# 改键-之魔兽改键(Hook)

    玩过dota的人都知道这游戏要用到一个辅助软件,即改键的软件,由于dota这款游戏的快捷键众多且杂乱无章,所以就需要一款改键的软件把那些快捷键改成我们顺手的,比如我们可以把P改成Q,把B改成W,把C改 ...

  3. 扯一下关于魔兽改键的蛋

    五一放了几天,难得不用呆在实验室,于是就去了趟将来工作的城市,四处走了走,感觉还不错,但这只会让我心中更加纠结,唉! 算了,不说废话了,有半个月没写博客了,其实也不是没东西可写,反而是要写的太多了,不 ...

  4. 魔兽改键助手1.2(附VC源代码)

    魔兽改键助手 1.2 更新内容: (1)使用全局WH_KEYBOARD_LL  无需使用dll文件. (2)智能判断聊天模式,如果正在聊天,则取消改键. (3)支持托盘. (4)支持1.24版 更新计 ...

  5. 关于魔兽改键。。。类似11的

    事情是这样的--闲的无聊玩了一盘卡尔的DOTA,结果发现卡尔的按键真的是十分XX啊--于是就在各个网站找那种类似于11的魔兽改键工具,不是改快捷键,而是直接按照技能的位置来改键的.可是没有找到,而11 ...

  6. 强大的魔兽改键--可以像11对战平台一样,自动进入BN!支持命令改键;

    限定改键在A-Z,0-9,TAb,空格,小键盘的7,8,4,5,1,2:F1-F4; 增加Caps Lock和~两个键的版本,取消F1帮助响应; 强大的改键器: 1.高效改键,游戏聊天不冲突:检测游戏 ...

  7. 写魔兽改键时遇到的问题

    由于在DLL中定义了变量,所以要在读取ini文件时赋值,但遇到诡异的一个问题,每次赋值之后按一下键盘,进入HOOK,发现变量值又变为初始值,经仔细思考再查阅网络才知道,每次进入钩子,会出现dll冲入现 ...

  8. 客制化机械键盘改键软件VIA介绍

    VIA可以汉化,也可以直接使用原版本.如果汉化,就会失去via里很有意思的一个功能--any键.接下来以原版本对via功能进行大概介绍. 要使用via,请确保你的键盘支持via改键,且有对应键盘的.j ...

  9. 魔兽重置版改键+喊话

    魔兽重置版改键+喊话 原创软件,绝无广告 附代码 **长总求:自己写的改键+喊话软件 ** 最近在玩魔兽争霸3重置版 别的不评价了,没有改键功能非常麻烦,自己做了一个. 好坏就不评论了,就当给当年补票 ...

最新文章

  1. sql server日志占用空间过大的问题
  2. Winform中通过代码设置DevExpress的TextEdit的类型为Numbernic
  3. Struts2 常量配置
  4. error LNK2001: unresolved external symbol public: virtual void *__thiscall
  5. 以太坊扩容项目 Arbitrum 放弃专利,即将上线主网
  6. SCPPO(五):解决MVC中Json传输数据量问题
  7. Automysqlbackup: WARNING: Turning off multicore support, since pigz isn’t there.
  8. 第13周 本周个人总结
  9. 2021第十届小美赛-“认证杯”数学中国数学建模国际赛
  10. PN532读写卡器(支持NFC、RFID)
  11. visual studio 2012 密钥记录
  12. 未知环境探索(二)基于边界点的自主环境探索
  13. Spark入门到精通
  14. 进阶 | 手把手教你模拟键盘和鼠标操作-ActionChains
  15. Gif表情包在线制作小程序
  16. 微信怎么不支持华为鸿蒙,微信迟迟不加入鸿蒙,华为为何不着急呢?
  17. 野人岛java游戏,生存战争之独闯野人岛
  18. nlpir语义分析 java_集成nlpir语义分析
  19. 清理yarn、npm缓存包
  20. Ubuntu文件管理快捷键

热门文章

  1. eclipse列名无效_java – SQLException:列名无效……?
  2. vue项目导入谷歌字体包
  3. Docker部署微服务时Springcloud网关报错 java.net.UnknownHostException: xxx: Name or service not known
  4. Python3.6 车牌识别代码源码
  5. day6 AI面试刷题
  6. Java 从死到生的修炼 (第一章:生命的起源之接触.)
  7. 利用人工智能的模式辨识能力 由AI掌控的超音速飞机
  8. 现实题材网络文学正打开广阔天地
  9. 施一公直播首秀来了!解答读博困惑都说了啥?
  10. 计算机组成原理算术逻辑单元设计,计算机组成原理:带进位算术逻辑运算单元ALU设计实验.doc...