按键精灵是一类很普遍的游戏插件,wow raid过程中部分职业的某些操作就需要此类插件(文俊的牧师号在打某些BOSS时驱散用到过)。类似的插件无非是用程序来模拟重复性的键盘动作。

游戏中进行键盘操作的程序可以理解为:

按下某键——键盘驱动程序将此事件传递给操作系统——操作系统将此事件插入消息队列——此消息被发送到当前活动窗口。

按照这个过程来理解程序,剩下的只不过要将抽象化的语句翻译成代码。当然很多过程编程工具(.NET)会自动处理,而不需你去理会。(如如何插入消息队列,消息队列的管理,无用对象的释放)。

第一个问题,按下如何用程序来模拟在键盘上按下某键。

日常操作中,当用户在键盘上按下某个按键时,键盘内芯片会检测到这个动作,并将这个信号传递给计算机。对于每个按键,键盘分配给它不同的编码,称做键盘扫描码。当敲击键盘时,底层上实际传递给计算机消息队列的是该按键的键盘扫描码,所以知道了欲按键的扫描码,就可以将该信息传递给电脑,从而达到模拟按键的功能。

第二个问题,键盘驱动程序如何把此事件传递给操作系统。

解决第一个问题的关键是必须知道按键的键盘扫描码,但是仅仅知道键盘扫描码不够。因为操作系统需要得到的信息的并不是键盘扫描码。因为键盘扫描码是跟具体的硬件相关的,同一个键在不同键盘上的扫描码有可能不同。键盘控制器将这个扫描码传给计算机,然后交给键盘驱动程序。键盘驱动程序会完成相关的工作,并把这个扫描码转换为键盘虚拟码。键盘虚拟码是针对键盘扫描码的非通用性所提出。尽管出于硬件原因,同一个按键可能有不同的扫描码,但是无论什么键盘,同一个按键的虚拟码总是相同的,这样程序就可以识别了。简单点说,虚拟码就是我们经常可以看到的像VK_A,VK_B这样的常数,比如键a的虚拟码(字母大小写虽然是同一个键,但是虚拟码不同)是&H61(即十进制的97,一般用16进制来表示虚拟码)。当键盘驱动程序把扫描码转换为虚拟码后,会把这个键盘操作的扫描码和虚拟码还有其它信息一起传递给操作系统。

操作系统在得到这个信息后,会对消息进行封装,然后把这个键盘消息插入到消息列队(这个过程则不需要我们理会)。最后,这个键盘消息最终会被送到当前的活动窗口那里,活动窗口所在的应用程序接收到这个消息后,就知道键盘上哪个键被按下,也就可以根据按键决定该作出什么响应返回给用户了。

明白整个过程后,然后就可以进行编程实现模拟键盘按键操作了。最直接的模拟方法是:直接伪造一个键盘消息发给目标程序。因为键盘信息最终发送的目标程序而引起目标程序的响应。

WINDOWS提供了消息函数(API函数(非托管函数)),这里要用到的主要是:

PostMessage(将一条消息投递到指定窗口的消息队列),

SendMessage(调用一个窗口的窗口函数,将一条消息发给那个窗口),

PostMessage函数和SendMessage函数的声明一样,均能向目标程序发送消息,所不同的返回值不同。

Declare Function PostMessage& Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any)

Declare Function SendMessage& Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any)

若成功发送信息,PostMessage函数的返回值为TURE,SendMessage函数的返回值则根据发送的信息有不同的返回值(http://11wuqingchao.blog.163.com/blog/static/33425622200932452146648/edit/)。这里只需向目标程序发送按键信息,而不需要根据该信息的返回值进行下一步操作,所以用PostMessage函数。PostMessage函数的参数的含义跟SendMessage函数大致相同。这里主要用到的WMsg参数的常量见(http://11wuqingchao.blog.163.com/blog/static/3342562220093333317338/edit/)

可以用到的常量很多,这里要用到以下几个:

WM_KEYDOW   按下一个键

WM_KEYUP       释放一个键

WM_SYSKEYDOWN  当用户按住ALT键同时按下其它键时提交此消息给拥有焦点的窗口

WM_SYSKEYUP        当用户释放一个键同时ALT 键还按着时提交此消息给拥有焦点的窗口

PostMessage函数还有2个参数,WParam,IParam。在一个键盘消息中,前一个参数的意义较为简单,表示欲模拟的按键的虚拟码(如按键A的的虚拟码为VK_A,欲模拟这个按键时,WParam的值即为VK_A)。而后一个参数的则较为复杂,因为它包含了多个信息,一般的模拟过程中可以把它设置为0,但如果你想要模拟更真实,那么有必要对这个参数进行设置。lParam 是一个long类型的参数,内存中占4个字节,二进制格式为

00000000 00000000 00000000 00000000  该参数的的0-15(从右往左的16位)位表示键的发送次数等扩展信息,16-23位为按键的扫描码,24-31位表示是按下键还是释放键。此参数一般写成16进制格式,即为

&H00 00 00 00 ,第0-15位一般为&H0001,如果是按下键,那么24-31位为&H00,释放键那么24-31位则为&HC0,16-23位的扫描码的得到需要用到一个API函数MapVirtualKey,这个函数可以将虚拟码转换为扫描码,或将扫描码转换为虚拟码,还可以把虚拟码转换为对应字符的ASCII码。

MapVirtualKey的声明如下:

Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long, 其中,

wCode  类型为Long,欲转换的源字符或扫描码

wMapType  类型为Long,控制映射类型,取值为0,1,2,0表示wCode是个虚拟键码。函数返回相应的扫描码,1表示wCode是个扫描码。函数返回相应的虚拟键码,2表示wCode是个虚拟键码。函数返回相应的ASCII值(未加Shift组合键)。

函数返回值为Long型,其结果取决于wMapType参数

如下函数是利用MapVirtualKey函数得到一个虚拟按键的扫描码,进而构造IParam参数,从而向记事本模拟发送一个A

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _

ByVal lpClassName As String, _

ByVal lpWindowName As String) As Long

Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _

ByVal hWnd1 As Long, ByVal hWnd2 As Long, _

ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _

ByVal hWnd As Long, _

ByVal wMsg As Long, _

ByVal wParam As Long, lParam As Any) As Long

Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" ( _

ByVal wCode As Long, ByVal wMapType As Long) As Long

Private Const WM_KEYDOWN = &H100

Private Const WM_KEYUP = &H101

Private Const WM_CHAR = &H102

Private Const VK_A = &H41

Function MakeIParam(Byval VirtualKey as long,Byval Flag as long) As Long

'VirtualKey表示按键虚拟码,Flag表示按下键还是释放键。

Dim s As String

Dim FirstByte As string

If Flag=WM_KEYDOWN Then

FirstByte="00"    '用来表示IParam的第24位至31位,先用字符串储存,后转换为16进制

Else

FirstByte="C0"

EndIf

Dim ScanCode As long

ScanCode=MapVirtuealKey(VIrtualKey,0) '使用API函数前需先声明

Dim SecondByte as string

SecondByte=Right("00"&Hex(ScanCode),2)  '用来表示IParam的第16位至23位

s=FirstByte&SecondByte&"0001"

MakeIParam=Val("&H"&s)

End Function

Private Sub Form_Load()

Dim hWnd&

Dim hEdit&

hWnd = FindWindow("notepad", "无标题 - 记事本")

hEdit = FindWindowEx(hWnd, 0, "Edit", vbNullString)

If hWnd = 0 Or hEdit = 0 Then

MsgBox "donot find,sorry!"

Else

PostMessage hEdit, WM_CHAR, Asc("A"), MakeIparam(VK_A, WM_KEYDOWN) '输入字符A

End If

End Sub

FindWindow 和FindWindowEx函数用来查找记事本编辑框的句柄。(句柄可以解释为系统分配给每个资源的唯一标识)这种方法通过局部键盘消息来模拟按键,它可以实现后台按键,也就是说他对你的前台操作不会有什么影响。比如,你可以用这个方法做个程序在游戏中模拟按键来不断地执行某些重复的操作,无论目标程序是否获得焦点都没有影响,这就是后台模拟按键的原理。

当然模拟按键的方法不止一种!

按键精灵可以实现c语言吗,按键精灵的原理和编写方法(1)相关推荐

  1. python语言入门m-Python -m参数原理及使用方法解析

    python -m xxx.py 作用是:把xxx.py文件当做模块启动 但是我一直不明白当做模块启动到底有什么用.python xxx.py和python -m xxx.py有什么区别! 自问自答: ...

  2. c语言按键控制的步进电机程序,独立按键控制步进电机运转c语言程序

    独立按键控制步进电机运转c语言程序 /* * 名称:步进电机 * * 晶振:12MHZ * * 修改:无 * * 内容: 主程序中用 3 个按键,加速.减速.启动和停止.定时器做数码* * 管动态扫描 ...

  3. 按键连续点击的c语言程序,长按键C语言程序

    长按键C语言程序 zhchxgh | 2009-07-04 01:46:51    阅读:8246 发布文章 一共用了四个按钮. #define _KEYDOWN_TEST_TIME      (20 ...

  4. 单片机c语言的按键程序,51单片机按键扫描C程序

    原标题:51单片机按键扫描C程序 大二上学期做过80 的按键程序,当时项目要求实现按键控制 屏显示并且接收GPRS传来的数据.当时为了节省成本,就去大西电子市场买来8*8的LED块,然后自己一点一点的 ...

  5. c语言单片机按键程序,通过键盘往单片机中输入任意数字的C语言程序?

    满意答案 ty7044140 推荐于 2018.03.29 采纳率:55%    等级:13 已帮助:8716人 我这有个AVR的矩阵键盘的识别程序.其中PORTA就相当于51里的P0一样的端口的表示 ...

  6. C语言 按键抬起有效 代码,最好的按键扫描和消抖方法,适用于复合、长按、按下或抬起响应按键...

    刚参加工作的时候,看了一些同事采用的按键扫描和消抖方法,对比学校里和网上查到的按键处理,发现觉得不尽善尽美,有以下几点: 1. 消抖复杂,效率低.有人直接在电平判断后使用delay()函数,进行消抖, ...

  7. 独立式键盘的编程方法 按键的去抖动原理和基本方法

    独立式键盘的编程方法 按键的去抖动原理和基本方法 A P3.2  开始 按此键则灯开始流动(由左向右) B P3.3  停止 按此键则停止流动 所有灯为灭 C P3.4  向左 按此键则灯反向流动 由 ...

  8. vba循环通过键盘某个按键按下退出循环_51单片机按键检测--独立按键与矩阵键盘...

    按键可以说是51单片机项目开发的一个重要组件了,它是作为51单片机IO口输入的一种重要方式.我们可以通过按键控制单片机执行相应的程序,得到我们想要得效果.51单片机的按键输入主要有两种,一种是独立按键 ...

  9. android模拟器游戏按键映射,刺激战场模拟器按键映射对比 逍遥安卓模拟器智能按键最好...

    原标题:刺激战场模拟器按键映射对比 逍遥安卓模拟器智能按键最好 绝地求生手游刺激战场模拟器现在有好多款,基本上每款模拟器都说自己是最好用的,绝大部分用户并不知道哪个刺激战场模拟器好,也没有时间和兴趣一 ...

  10. android 虚拟按键自定义,如何适配Android底部虚拟按键

    前言 本文章只做一个记录,一个备忘,也为了更好的帮助他人,文章参考地址:Android适配底部虚拟按键的方法 问题说明 项目进行中需要透明渐变的状态栏,全屏显示,当然透明渐变好弄,方法有很多,但是如果 ...

最新文章

  1. python中3or5什么意思_示例详解Python3 or Python2 两者之间的差异
  2. redis集群(主从配置)
  3. SAP CRM WebClient UI,如何快速定位到抛出错误消息的那一行代码
  4. java二维数组的常见初始化
  5. 分分钟写出Vue原理
  6. linux lvm界面,Linux使用入门教程之LVM
  7. Factory Method 抽象工厂模式(创建型)
  8. iphone7字体风格怎么改_苹果7怎么更改字体样式 苹果手机换好看的字体
  9. 重磅长文!先进院李骁健等人:在体神经界面技术的发展-从小到大规模记录
  10. 美团 2021 届秋季校园招聘—小团的 AB 队(排序)
  11. 富集分析(GO、KEGG、GSEA)
  12. 离散数学 - 逻辑与推理
  13. 电商之下:服务类商品订单履约系统如何设计
  14. 爬取网易云音乐50000+首歌曲
  15. php7生命周期,PHP 的生命周期与模块的sapi 原理
  16. python解一元二次方程虚根_怎么用python解一元二次方程
  17. 小型便携式AIS接收机dAI01
  18. 智慧工厂用到的技术_智慧工厂如何实现智能化
  19. NASA庆祝地球日:50年地球最精美图片亮相(转载)
  20. 环境混合物总体效应:加权分位数和回归(WQS)

热门文章

  1. OOP的六大原则+一法则
  2. Android图片轮播控件——Banner
  3. dos下的for命令详解(zz)
  4. destoon php文件,Destoon 任意文件读取
  5. Barsetto百胜图全自动美式磨豆咖啡机测评
  6. 运用 children 获取节点子元素解决文本节点阻碍
  7. www读取本地图片做微缩图
  8. 云杰恒指:8.16恒指期货指导交易周小结
  9. 考研数据结构——买卖青蛙
  10. 经典运放电路详细分析(模拟电子技术)