【按键精灵PC实战——游戏刷属性(下)】 优化电脑使用效率,让电脑自动帮我们玩游戏的同时还能玩电脑
编写背景
上期内容中讲解了如何从零开始编写一个刷词缀的自动化程序,实现工具用到的是按键精灵。【按键精灵PC实战——游戏刷属性(上)】 从游戏流程到逻辑流程再到编程流程,零基础的脚本上手功法,从此解放双手不是梦
本期将基于上期的代码,进行修改提升。
提升点如下:
- 修改点击为后台点击,提高电脑使用效率(仅使用按键自带后台插件)
- 解放游戏窗口随意移动,不受窗口固定点限制
需要用到的基础理论
本期内容涉及后台内容,剖析按键后台插件可以发现其内部是使用了Windows系统API——SendMessage(parm),因此这里需要梳理Windows的消息机制;此外我们需要理解顶层窗口和子窗口的区别,以及辨别接受输入窗口到底是子窗口还是顶层窗口;另外需要将游戏窗口不固定运行,需要将窗口坐标转换为屏幕坐标,这里也需要明白屏幕坐标轴和窗口坐标轴的转换(纯数学知识)
消息机制
消息机制并不是一个新内容了,Windows的消息机制是为了让进程窗口可以响应用户的输入,最直观的就是鼠标,键盘操作。那么让我们用一张图来看看Windows的消息机制作用流程:
可以看到当用户通过外设输入信息是,首先会被系统捕获到并存储至系统消息队列队尾。然后由消息分发部分(内核和窗口管理器组成)将特定的消息分发给对应的应用进程。应用程序通过消息循环把目标窗口(窗口句柄区分)的消息插入对应窗口的消息队列队尾。窗口类将从自己的窗口消息队列中一条条的取出消息并进行处理。
消息机制是一种窗口响应用户输入的方式,但不是唯一的方式。在很多及时性要求高的游戏场景已经舍弃了消息机制而改用直接输入(direct input),就是我们常说的dx输入输出。这也是为什么我们通过SendMessage给一些游戏窗口发送按键鼠标信息不被响应的原因,因为dx输入已经舍弃了对窗口消息队列的处理步骤,而SendMessage函数作用点正是窗口消息队列:
本篇内容仅对消息机制实现的后台进行简单实现,若是对于dx后台不起到引导作用。
顶层窗口和子窗口
简单理解一下顶层窗口就是指独立的不依赖于其他窗口的窗口,比较绕。还是来举个例子看一下吧:
可以看到红色框框选的窗口是独立的,他仅仅依赖QQ.exe的进程而不依赖于其他任何窗口。但是其他颜色框选的窗口都依赖于红色框框选的窗口。
这里并没有从术语的角度解释顶层窗口,因为微软对于顶层窗口已经解释得很清楚了:窗口功能
另外,在了解顶层窗口和子窗口外,还需要分辨响应用户输入的窗口。换句话说就是当我们点击按钮的时候响应这个鼠标点击事件的是按钮还是主窗口!很显然用过电脑的同学们都知道是按钮,所以我们使用SendMessage发送鼠标点击事件的就应该是按钮句柄而不是窗口句柄。
窗口坐标到屏幕坐标的转换
这就是一个纯数学问题了,基于不同坐标轴的同一个点肯定是有不同坐标点表示的。看了下面的图还不懂的可以戳我
需要用到的函数
代码逻辑流
因为本篇内容是基于上一篇的,因此会在上一期代码上进行修改。具体的修改流程如下:
- 获取窗口信息,窗口起始坐标!
- 删除原始代码中移动鼠标的语句及其延时
- 修改原始代码中找图和找色的屏幕范围
- 修改前台点击为后台点击
代码实现
Dimenv targetWind
DimEnv setPath
Dimenv mainWlx, mainWly, mainWrx, mainWry
Dimenv delayTIme
DimEnv thread1,threadfd,threadlm
Function BackHeadPage
For i = 0 To 3
Call Plugin.Bkgnd.LeftClick(targetWind, 281,825)
Delay 200
Next
End Function
Sub MainThread()
BackHeadPage
delayTIme = 1200
targetWind = Plugin.Window.Find("Chrome_WidgetWin_0", "寻道大千")
If targetWind = 0 Then
MessageBox "未找到目标窗口!"
ExitScript
End If
setPath = "E:\code\anjian\"
Call Plugin.TURING.Link(targetWind)//关联句柄
窗口大小 = Split(Plugin.TURING.Window_GetSize(), ",")//获取指定句柄的窗口大小
If 窗口大小(3) = 0 Then
MessageBox "未找获取到目标窗口信息!"
ExitScript
End If
Call Plugin.TURING.UnLink()//取消句柄的关联
mainWlx = 窗口大小(0)
mainWly = 窗口大小(1)
mainWrx = 窗口大小(2)
mainWry = 窗口大小(3)
threadlm = BeginThread(Reflash)
While 1//阻塞主线程
Delay 1000 * 10
Wend
End Sub
Sub Reflash()
BackHeadPage
Call Plugin.Bkgnd.LeftClick(targetWind, 327, 597)
Delay 1200
While 1
Call Plugin.Bkgnd.LeftClick(targetWind, 221, 706)
Delay delayTime + 1000
FindColorEx mainWlx+262,mainWly+505,mainWlx+324,mainWly+528, "347921", 1, 0.8, intX, intY
If intX > 0 And intY > 0 Then
TracePrint "zhaodao yl"
FindPic mainWlx+218,mainWly+334,mainWlx+420,mainWly+434,setPath + "朱雀灵脉.bmp",0.7,intX,intY
If intX > 0 And intY > 0 Then
TracePrint "zhaodao zq"
FindPic mainWlx+240,mainWly+503,mainWlx+420,mainWly+602,setPath + "朱雀灵脉.bmp",0.7,intX,intY
If intX > 0 And intY > 0 Then
TracePrint "zhaodao zq"
Call Plugin.Bkgnd.LeftClick(targetWind, 336,701)
Delay delayTime + 1000
Else
Call Plugin.Bkgnd.LeftClick(targetWind, 113,702)
Delay delayTime
Call Plugin.Bkgnd.LeftClick(targetWind, 323,491)
Delay delayTime + 1000
End If
Else
Call Plugin.Bkgnd.LeftClick(targetWind, 336,701)
Delay delayTime + 1000
End If
Else
Call Plugin.Bkgnd.LeftClick(targetWind, 113,702)
Delay delayTime
End If
//Delay 1000
Wend
End Sub
Event Form1.Button1.Click
If Form1.Button1.Caption = "启动" Then
//启动
Form1.Button1.Caption = "停止"
thread1 = BeginThread(MainThread)
Else
//停止
Form1.Button1.Caption = "启动"
If thread1 Then
StopThread thread1
ExitScript
End If
End If
End Event
视频观看连接:【戳我】