|
本帖最后由 bacy001 于 2016-6-24 15:30 编辑
关键字:网游辅助(外挂) VS2010 MFC 鼠标键盘消息 游戏控制
前面我们分别介绍了 WinPcap 编程接口以及封包数据分析的基本方法,对于我们的网游辅助(外挂)程序来说,实现以上内容,相当于给我们的程序安装上了眼睛和耳朵,使得它有能力对游戏中产生的数据做出反应,而这些反应具体来说就是实现对游戏人物的控制。这部分的内容其实按键精灵已经做得很不错了,而我们将要采用的方法也基本相同,无非就是通过发送鼠标和键盘消息来实现对游戏人物的控制!唯一不同的地方在于,我们能够实现针对具体游戏窗口发送,而按键精灵需要收费插件才能提供此功能!否则就只能将消息发送给获得焦点的窗口(本质上是将消息发送给了 Windows 桌面)。
1、搜索游戏窗口
Windows 系统是消息驱动的系统,任何一个操作都会触发一系列的消息,每一个窗口程序都有一个消息处理函数用于处理这些消息!使用一个程序去控制另外一个程序,最简单也是最安全的方法,就是发送消息给被控程序。要实现这个功能,第一步是要知道被控程序的主窗口句柄!Windows API 提供了一个函数可以用来完成这个工作,代码如下:- HWND *hwndChildAfter;
- CPtrList plCore;
- hwndChildAfter = new HWND;
- *hwndChildAfter = NULL;
- do{
- *hwndChildAfter = ::FindWindowEx(NULL,*hwndChildAfter,NULL,"GameName");
- plCore.AddTail((void*)hwndChildAfter);
- hwndChildAfter = new HWND;
- *hwndChildAfter = *(HWND*)plCore.GetTail();
- } while ( *hwndChildAfter != 0 );
- plCore.RemoveTail();
复制代码 函数 FindWindowEx 用于通过窗口名称来获取窗口的句柄,以上代码将搜索系统中正在运行的名称为 “GameName” 的窗口,并将获得的窗口句柄保存在链表类 plCore 中,如果同时打开了多个窗口,那么每个窗口的句柄信息将依次保存在 plCore 指向的链表结构中。FindWindowEx 是标准 Windows API,CPtrList 是标准 MFC 类,详细信息,请访问 MSDN。- UINT iGameNum = plCore.GetCount();
- HWND iGameHwnd[iGameNum]
- if(iGameNum)
- {
- for(UINT i = 0; i < iGameNum; i++){
- POSITION pos = plCore.FindIndex(i);
- iGameHwnd[iGameNum] = *(HWND*)plCore.GetAt(pos);
- }
- }
复制代码 以上代码将链表中保存的句柄信息保存在数组中以便备用。
2、鼠标操作
一般游戏中的鼠标操作无非是:鼠标左键单击、右键单击、移动等等,某些游戏还支持双击操作。以鼠标左键单击为例,一次完整的鼠标左键单击操作可以分解成如下三个独立的消息,按照时间顺序依次是:WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP,发送消息则使用 :ostMessage 函数,具体代码如下:- #define POS(x,y) x + y * 0x10000
- #define SLEEPTIME 100
- void ClickLeftMouseButton(HWND hwnd, UINT x, UINT y)
- {
- int pos = POS(x,y);
- ::PostMessage(hwnd, WM_MOUSEMOVE, 0, pos);
- Sleep(SLEEPTIME);
- ::PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, pos); //Click Left Mouse Button
- ::PostMessage(hwnd, WM_LBUTTONUP, 0, pos);
- }
复制代码 这段代码定义了一个 POS 宏,用于将坐标值组合到一个 32 位整数中作为 PostMessage 函数的最后一个参数,而 Sleep 函数则起到延迟操作的作用,设定合适的 SLEEPTIME 可以使得函数模拟的鼠标操作更加接近人的手工操作。与此对应的是鼠标右键单击,封装到自定义函数后,代码如下:- void ClickRightMouseButton(HWND hwnd, UINT x, UINT y)
- {
- int pos = POS(x,y);
- ::PostMessage(hwnd, WM_MOUSEMOVE, 0, pos);
- Sleep(SLEEPTIME);
- ::PostMessage(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, pos); //Click Right Mouse Button
- ::PostMessage(hwnd, WM_RBUTTONUP, 0, pos);
- }
复制代码 3、窗口坐标系统
鼠标操作中有一个非常重要的参数,就是坐标,如果给的坐标不对,就无法准确打开游戏菜单,拾取道具等等。那么如何确定有效的坐标参数呢?有一个简便的方法就是使用QQ的窗口截图 + Windows 自带的画笔程序。以 Windows 自带的扫雷程序为例,步骤如下:
1)运行扫雷程序,使用QQ的截图功能将整个窗口截图;
2)将截图粘帖到画图程序中,将鼠标移动到扫雷游戏界面的左上角(见下图中粉红色的点),注意这里说的是游戏界面,而不是窗口!
3)上图中粉红色的点就是游戏窗口中的坐标原点,也就是(0, 0),而上图右下角的坐标(3, 29)是包含了窗口边框的宽度的。因此我们要确认游戏界面上某个点的坐标时,只需要将鼠标移动到指定的位置上,然后将画图软件右下角显示的坐标减去(3, 29)即可获得该位置在游戏界面上的真实坐标,也就是我们鼠标消息中准确的坐标值。
例如:要确定扫雷游戏界面上黄色笑脸按钮的坐标,则首先在画笔程序中找到按钮中间的某个点的坐标(256, 79),然后减去(3, 29),得到(256 - 3 = 253, 79 - 29 = 50),然后调用函数:ClickLeftMouseButton(hwnd, 253, 50); 就能实现模拟鼠标点击扫雷窗口上黄色笑脸图标了,其中 hwnd 是扫雷程序的窗口句柄。
4、键盘操作
单单只有鼠标的操作肯定是不够的,键盘的操作一般主要用于游戏客户端的快捷键的使用,比如施放技能,吃药等等。下面的代码实现键盘输入英文字符串的功能:- void TypeString(HWND hwnd, char *str)
- {
- while(*str)
- {
- ::PostMessage(hwnd, WM_CHAR, *str, 0);
- str++;
- }
- ::PostMessage(hwnd,WM_KEYDOWN,VK_RETURN,0x00420001);
- ::PostMessage(hwnd,WM_KEYUP,VK_RETURN,0xC0420001);
- }
复制代码 可以看到,输入英文字符可以使用 WM_CHAR 消息,而输入回车这样的控制符,则需要使用 WM_KEYDOWN 与 WM_KEYUP ,这有点类似鼠标的单击操作。如果要发送功能键比如F1~F12,只需要修改上述代码中 VK_RETURN 的部分,更详细的信息请参考 MSDN。
如果希望输入中文,使用系统剪贴板是比较方便的,在这里就不做介绍了!
|
|