分享给朋友:通用代码: 复 制天龙八部按键精灵3.0自动打怪脚本使用方法下载至电脑扫码用手机看用或微信扫码在手机上继续观看二维码2小时内有效天龙八部按键精灵3.0自动打怪脚本使用方法扫码用手机继续看用或微信扫码在手机上继续观看二维码2小时内有效,扫码后可分享给好友没有优酷APP?立即下载请根据您的设备选择下载版本
药品服务许可证(京)-经营- 请使用者仔细阅读优酷、、、Copyright(C)2017 优酷
版权所有不良信息举报***: 上传我的文档
下载
收藏
该文档贡献者很忙,什么也没留下。
下载此文档
天龙八部2 按键 精灵自动打怪脚本
下载积分:500
内容提示:天龙八部2 按键 精灵自动打怪脚本
文档格式:PDF|
浏览次数:1006|
上传日期: 00:20:20|
文档星级:
全文阅读已结束,如果下载本文需要使用
500 积分
下载此文档
该用户还上传了这些文档
天龙八部2 按键 精灵自动打怪脚本
关注微信公众号自己写个网游工具天龙八部键盘连点之1:如何模拟键盘输入
从天龙八部1开始接触网游,到现在不知不觉的过了几年,现在都到天龙八部3了。从一开始不知道何为外挂,何为游戏机器人到现在看到满地图的游戏外挂才意识到原来那么多人在开发和使用游戏的自动操作工具。打怪升级刷副本捡东西得用鼠标点来点去的,确实是累啊。想到自己大学混的几年好歹也是学计算机的,何不自己也开发一个自动操作的工具,充分发挥下DIY精神呢?有想法就有了开始,于是开始google,开始编码,开始debug,
在过去几十天磕磕碰碰断断续续的开发中,终于将键盘连点,自动采矿,自动采药,自动捡包等做出来,能用了,借此记录一下之前开发的点滴,权当留个纪念。下面界面中的有些Tab如跑商,种植还是To
Designed呢...有时间再弄弄了。现在先说说键盘连点,想到什么写什么,没有刻意去想提纲,想编排之类的哦。打字也是一个累活,不过写写文档的好处往往能够促进对知识的记忆,帮助清理思路,有助于发现一些编码的细微问题。编程,文档和注释还是挺重要的,特别是当你的代码量越来越多的时候。
开发环境: Visual Studio 2008 用C++写。操作系统为Vista Ultimate
工具界面如下,经典的Windows窗口样式,没有花俏的装饰...
顾名思义,这个工具的核心就是模拟用户按键,所以只要把键盘按键消息发送到游戏窗口,功能就基本实现了。模拟按键可使用的Windows
API有两个:一个是PostMessage/SendMessage, 另一个是SendInput.
玩编程一定得喜欢看文档,懂得找资料.
不得不说MSDN是个好东东啊,一定要经常去看。对API那里有详尽的说明,还有有例子,是个宝库啊。。Windows编程可用的函数那么多,函数名字长,参数名字长,函数参数多,我也记不住那么多。幸亏现在编程工具都能智能感应,提示个函数名,参数名之类,要不编程真是被累死。
BOOL WINAPI PostMessage(
& __in_opt& HWND hWnd,
& __in&&&&& UINT Msg,
& __in&&&&& WPARAM wParam,
& __in&&&&& LPARAM lParam
上面就是PostMessage的定义,在MSDN有各个参数说明,我这里不多说. SendMessage也差不多,不过调用这个要等对方处理的消息才返回,万一对方应用程序挂掉了,SendMessage等不到返回于是自己的程序也不响应了。所以我不用SendMessage. 我的代码如下。我写了一个函数来调用PostMessage,只需要传进窗口句柄hWnd(也就是你要把键盘消息发送到哪个窗口)和要模拟的按键vKey.
void PostKey(HWND hWnd, UINT vKey)
&DWORD ScanC
if (hWnd == NULL)
&ScanCode=MapVirtualKey(vKey, MAPVK_VK_TO_VSC); //lParam需要ScanCode
&//1+ScanCode&&16结果是(1+ScanCode)相加后再移位 ScanCode&&16+1结果是移了17位(16+1)
//发送按键按下消息
PostMessage(hWnd, WM_KEYDOWN, vKey,(LPARAM)((ScanCode&&16)+1));
&Sleep(100); //如果不休眠一段时间,天龙八部不能识别按键,当然Sleep(50)也可以,太短就不行
//发送按键释放消息
&PostMessage(hWnd, WM_KEYUP, vKey, (LPARAM)((0xC0000000 | (ScanCode&&16))+1));
获取窗口句柄可以用FindWindow. 比如我用下面代码得到天龙八部游戏窗口句柄:
HWND hWndTLBB = ::FindWindow(_T("TianLongBaBu WndClass"), NULL);
这个函数可以使用用窗口类的名字或标题的名字查找窗口, 天龙八部游戏窗口类的名字为TianLongBaBu WndClass,上面例子就是用类名查找。不过注意的是它查找的时候是做完全匹配的,也就是假设有另外一个窗口的类名包含这个字符串,但多出一些字符,那算是不匹配的了,所以要找的窗口类名或标题不固定就有麻烦了。特别是窗口标题经常是变化的。比如天龙八部窗口标题就包含了游戏版本号和游戏服务器名的,每次更新之后,显示的标题就变了,玩家登陆进入不同的游戏服务器,标题也变了。要想用包含某个字符来找窗口,只能用EnumWindows这个API来遍历窗口,对每个窗口用GetWindowText读出窗口标题或用GetClassName读出窗口的类名之后自己再用字符串的比较查找函数来匹配了。
我们按一下键盘会触发2个消息WM_KEYDOWN和WM_KEYUP。当然不同的按键还可触发的是WM_SYSKEYDOWN和WM_SYSKEYUP,还可能伴有WM_CHAR等消息。比如说按F10就会产生WM_SYSKEYDOWN和WM_SYSKEYUP,而不是WM_KEYDOWN和WM_KEYUP,因为F10是一个系统键。当对我做的这个键盘连点来说,只需要模拟发送WM_KEYDOWN和WM_KEYUP消息就够了。PostMessage函数中wParam就是发送的键,通常代码中使用虚拟键,比如模拟按下F2,就写VK_F2. WinUser.h里面定义很多这些虚拟键,例如VK_F2:
#define VK_F2&&&&&&&&&&&& 0x71
特别注意需要正确的构造lParam参数,lParam用一些位来指示不同的信息,具体看MSDN,描述起来很长...
而且要注意的是PostMessage发送组合键不行。至少我没有试成功。天龙八部缺省的选怪快捷键是CTRL+TAB.
我曾实验先发Ctrl按下,TAB按下2个消息,接着发TAB释放,CTRL释放这个2个消息,但最终效果仿佛只按了TAB键,在游戏里弹出地图窗口了。我想可能是游戏里面判断组合键的时候使用了GetKeyState这个函数来检查键盘按键状态了,事实上在我的键盘连点中我也是用了这个函数。
比如::GetKeyState(VK_CO***OL) & 0x8000如果为1则表示Ctrl按下,0为未按下。双冒号::表示调用API,是个全局函数而不是某个类的成员函数。 注意要对返回值做位运算,因为不用位表示不同键入Shift, Alt等是否按下的状态。0x8000是判读Ctrl的掩码。
GetKeyState读键盘硬件的状态,而PostMessage发键盘消息并没有改变键盘硬件上任何按键状态相关的标志,所以游戏即使收到了键盘消息,一旦读键盘硬件状态就发现Ctrl,Shift等键并没有真实的按下,于是消息就不被处理了。这也是模拟按键的不可避免的缺点。但对这个游戏来说,这无所谓,因为快捷键是可以设置的,可以不用Ctrl+TAB组合键选怪,改用F1~F10这些单键作为选怪快捷键就可以了。
PostMessage因为有参数指定了窗口句柄,所以方便之处就是向指定窗口发消息,即使窗口不在前台,而被挡住或窗口部分被移出屏幕之外都可以让其接收键盘消息,但最小化就不行,因为这跟游戏的实现也有关系。基本可以肯定的是游戏被最小化了就不再更新游戏画面,实际上也没必要那样继续更新了,所以键盘消息根本就不处理了,你发过去也没用。
可是目前有些网游能够发现消息是由PostMessage或SendMessage发过来,就被过滤掉了,所以就没办法用这些函数模拟键盘了。目前天龙八部3还没过滤这个。但现在的版本它做了一些判断,我猜想是检查自己窗口是不是有输入焦点的(可以调用API GetFocus来判断)或是不是前台窗口(可以调用GetForegroundWindow来判断),所以一旦天龙八部3窗口不是前台了,它依然可以继续接受键盘消息(用Spy++发现它依然接收键盘消息),但是不做处理了。
怎么才能后台?之后再说。接下来说另一个模拟键盘的API SendInput.
UINT WINAPI SendInput( __in&&UINT nInputs, __in&&LPINPUT pInputs, __in&&int cbSize );
MSDN现在推荐使用这个函数。它不仅仅能够模拟键盘按键也能模拟鼠标按键和鼠标移动,但问题是它没有了窗口句柄做参数,所以不能用它向指定窗口发消息,它发出的消息是被当前有输入焦点的窗口接收了。如果它用于天龙八部的话需要游戏窗口是当前窗口才行,否则就没用了。使用它要注意设置好相应结构的值,看看我的代码:
//vKey Virtual Key to be sent Flag=0 KeyDown Flag=1 KeyUP
UINT KeybdInput(UINT vKey,int Flag)
::memset(&input, 0, sizeof(INPUT));
&input.type=INPUT_KEYBOARD; //只是这是一个键盘消息
&input.ki.wVk=vK
&input.ki.wScan=MapVirtualKey(vKey,MAPVK_VK_TO_VSC); //Do not distinguish between left- right-hand keys
&if (Flag) input.ki.dwFlags=KEYEVENTF_KEYUP;
return ::SendInput(1,&input,sizeof(INPUT));
void SendCombinedKeys(UINT vKey1, UINT vKey2)
&KeybdInput(vKey1,KEYDOWN);
&KeybdInput(vKey2,KEYDOWN);
&Sleep(100);
&KeybdInput(vKey1,KEYUP);
&KeybdInput(vKey2,KEYUP);
void SendKey(UINT vKey)
&KeybdInput(vKey, KEYDOWN);
&Sleep(100);
&KeybdInput(vKey, KEYUP);
因为要使用API SendInput赋值INPUT结构,这个结构是一个union,因为同一个结构要供模拟键盘和模拟鼠标使用而这两种需要不同参数,所以定义了联合体.因此也使得使用起来的写好几行代码,所以我首先写了一个函数KeybdInput来调用API SendInput。这样之后那个SendKey函数和SendCombinedKeys函数就显得简洁了。
和PostMessage一样,先发按键被按下的消息,睡眠100毫秒,接着发按键被释放消息。但这次组合键能够起作用,比如这样SendCombinedKeys(VK_CO***OL, VK_MENU)能够发送Ctrl+TAB(注意TAB的虚拟键不是VK_TAB而是VK_MENU,因为缺省TAB是激活Windows菜单项的键)给游戏并且游戏能够正确处理。所以不太清楚是否SendInput在模拟键盘消息的同时也置了键盘硬件的某些标志位使得游戏能够判断好像Ctrl等键真的被按下了。
如果是模拟鼠标消息的话,代码如下。对于鼠标移动,特别要注意如果使用MOUSEEVENTF_ABSOLUTE 标志的话,INPUT结构里面的dx, dy范围大小是0-65535,而不是屏幕分辨率,所以要先将屏幕坐标转换。下面的MouseMove函数就做了这样的转换。而鼠标的单击是先将鼠标移动至目标位置让后发送鼠标单击相关的消息,这时候INPUT结构的dx,dy没有特别设值而都是初始化为0.下面的函数都是用屏幕坐标即以像素为单位的。
UINT MouseInput(LONG dx, LONG dy, DWORD dwFlag)
&::memset(&input, 0, sizeof(INPUT));
&input.type=INPUT_MOUSE; //这是一个鼠标消息
&input.mi.dx=
&input.mi.dy=
&input.mi.dwFlags|=dwF
&return ::SendInput(1,&input,sizeof(INPUT));
void MouseLClick(LONG dx, LONG dy)
&SetCursorPos(dx, dy);//先把鼠标移动至指定位置
&INPUT&&&&&&&&&&&&&&&&
&ZeroMemory(&input,sizeof(INPUT));
&input.type&&&&&&& = INPUT_MOUSE;&&&&&&&&
&input.mi.dwFlags& = MOUSEEVENTF_LEFTDOWN;&&&&&&&
&SendInput( 1, &input, sizeof(INPUT) );&&&&&&&
&Sleep(100);
&ZeroMemory(&input,sizeof(INPUT));&&&&&&&&&
&input.type&&&&&&& = INPUT_MOUSE;&&&&&&&&&
&input.mi.dwFlags& = MOUSEEVENTF_LEFTUP;&&&&&&&&
&SendInput( 1, &input, sizeof(INPUT) );
void MouseRClick(LONG dx, LONG dy)
&SetCursorPos(dx, dy);
&INPUT&&&&
&ZeroMemory(&input,sizeof(INPUT));
&input.type&&&&&&& = INPUT_MOUSE;&&&&&&&&
&input.mi.dwFlags& = MOUSEEVENTF_RIGHTDOWN;&&&&&&&
&SendInput( 1, &input, sizeof(INPUT) );&&&&&&&
&Sleep(100);
&ZeroMemory(&input,sizeof(INPUT));&&&&&&&&&
&input.type&&&&&&& = INPUT_MOUSE;&&&&&&&&&
&input.mi.dwFlags& = MOUSEEVENTF_RIGHTUP;&&&&&&&&
&SendInput( 1, &input, sizeof(INPUT) );
void MouseMove(LONG dx, LONG dy)
&//If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535.
&//The event procedure maps these coordinates onto the display surface.
&//Coordinate (0,0) maps onto the upper-left corner of the display surface, and () maps onto the lower-right corner.
&int ScrnWidth = GetSystemMetrics(SM_CXSCREEN); //水平分辨率
&int ScrnHeight = GetSystemMetrics(SM_CYSCREEN); //垂直分辨率
&long dx1 = (long) dx * 65535.0 / ScrnW
&long dy1 = (long) dy * 65535.0 / ScrnH
&MouseInput(dx1, dy1, MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE);
以上就是几个核心的函数的使用,自己可以写几行测试代码来试试。其余剩下的编码就好办了,比如可以用Timer来做到固定间隔不断发按键消息。
另外,有时得用一用Spy++这个工具,它是Visual Studio Tools里面的一员。它能够截获某个窗口接收的消息。如果你不知道某个按键该发送什么消息或者发送的时候wParam, lParam应该设置为怎样的值,用Spy++截获消息看看就行了。
因为Spy++用hook实现消息截获,我在使用中它拦截天龙八部消息的时候发现有时因为截获的消息过多而设置消息过滤,只截获某些种类消息的时候它会出错,提示当前挂钩失败了。这时候必须重启SPY++才行,有时可能要重新登录游戏才行。我想会不会是游戏本身探测到有软件挂钩到自身而做出了一些保护造成SPy++ Hook失败了呢? 这是可能的,现在网游反外挂反调试的能力越来越厉害了。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。