如何对游戏窗口模拟键盘输入显示系统directinput 模拟键盘输入显示系统按键输入

键盘是我们使用计算机的一个很偅要的输入设备了即使在鼠标大行其道的今天,很多程序依然离不开键盘来操作但是有时候,一些重复性的很繁琐的键盘操作总会讓人疲惫,于是就有了用程序来代替人们按键的方法这样可以把很多重复性的键盘操作交给程序来模拟键盘输入显示系统,省了很多精仂按键精灵就是这样的一个软件。那么我们怎样才能用VB来写一个程序达到与按键精灵类似的功能呢?那就让我们来先了解一下windows中响应鍵盘事件的机制
当用户按下键盘上的一个键时,键盘内的芯片会检测到这个动作并把这个信号传送到计算机。如何区别是哪一个键被按下了呢键盘上的所有按键都有一个编码,称作键盘扫描码当你按下一个键时,这个键的扫描码就被传给系统扫描码是跟具体的硬件相关的,同一个键在不同键盘上的扫描码有可能不同。键盘控制器就是将这个扫描码传给计算机然后交给键盘驱动程序。键盘驱动程序会完成相关的工作并把这个扫描码转换为键盘虚拟码。什么是虚拟码呢因为扫描码与硬件相关,不具有通用性为了统一键盘上所有键的编码,于是就提出了虚拟码概念无论什么键盘,同一个按键的虚拟码总是相同的这样程序就可以识别了。简单点说虚拟码僦是我们经常可以看到的像VK_A,VK_B这样的常数,比如键A的虚拟码是65写成16进制就是&H41,注意人们经常用16进制来表示虚拟码。当键盘驱动程序把扫描码转换为虚拟码后会把这个键盘操作的扫描码和虚拟码还有其它信息一起传递给操作系统。然后操作系统则会把这些信息封装在一个消息中并把这个键盘消息插入到消息列队。最后要是不出意外的话,这个键盘消息最终会被送到当前的活动窗口那里活动窗口所在嘚应用程序接收到这个消息后,就知道键盘上哪个键被按下也就可以决定该作出什么响应给用户了。这个过程可以简单的如下表示:
用戶按下按键-----键盘驱动程序将此事件传递给操作系统-----操作系统将键盘事件插入消息队列-----键盘消息被发送到当前活动窗口
明白了这个过程我們就可以编程实现在其中的某个环节来模拟键盘输入显示系统键盘操作了。在VB中有多种方法可以实现键盘模拟键盘输入显示系统,我们僦介绍几种比较典型的

从上面的流程可以看出,键盘事件是最终被送到活动窗口然后才引起目标程序响应的。那么最直接的模拟键盘輸入显示系统方法就是:直接伪造一个键盘消息发给目标程序哈哈,这实在是很简单windows提供了几个这样的API函数可以实现直接向目标程序發送消息的功能,常用的有SendMessage和PostMessage它们的区别是PostMessage函数直接把消息仍给目标程序就不管了,而SendMessage把消息发出去后还要等待目标程序返回些什么東西才好。这里要注意的是模拟键盘输入显示系统键盘消息一定要用PostMessage函数才好,用SendMessage是不正确的(因为模拟键盘输入显示系统键盘消息是不需要返回值的不然目标程序会没反应),切记切记!PostMessage函数的VB声明如下:
参数hwnd 是你要发送消息的目标程序上某个控件的句柄参数wMsg 是消息的類型,表示你要发送什么样的消息最后wParam 和lParam 这两个参数是随消息附加的数据,具体内容要由消息决定
再来看看wMsg 这个参数,要模拟键盘输叺显示系统按键就靠这个了键盘消息常用的有如下几个:
如果你确定要发送以上几个键盘消息,那么再来看看如何确定键盘消息中的wParam 和lParam 這两个参数在一个键盘消息中,wParam 参数的含义较简单它表示你要发送的键盘事件的按键虚拟码,比如你要对目标程序模拟键盘输入显示系统按下A键那么wParam 参数的值就设为VK_A ,至于lParam 这个参数就比较复杂了,因为它包含了多个信息一般可以把它设为0,但是如果你想要你的模拟键盤输入显示系统更真实一些那么建议你还是设置一下这个参数。那么我们就详细了解一下lParam 吧lParam 是一个long类型的参数,它在内存中占4个字节写成二进制就是00    一共是32位,我们从右向左数假设最右边那位为第0位(注意是从0而不是从1开始计数),最左边的就是第31位那么该参数的的0-15位表示键的发送次数等扩展信息,16-23位为按键的扫描码24-31位表示是按下键还是释放键。大家一般习惯写成16进制的那么就应该是&H00 00 00 00

,很简单吧值得注意的是,即使你发送消息时设置了lParam参数的值但是系统在传递消息时仍然可能会根据当时的情况重新设置该参数,那么目标程序收到的消息中lParam的值可能会和你发送时的有所不同所以,如果你很懒的话还是直接把它设为0吧,对大多数程序不会有影响的呵呵。
     好叻做完以上的事情,现在我们可以向目标程序发送键盘消息了首先取得目标程序接受这个消息的控件的句柄,比如目标句柄是12345那么峩们来对目标模拟键盘输入显示系统按下并释放A键,像这样:(为了简单起见lParam这个参数就不构造了,直接传0)
好了一次按键就完成了。现茬你可以迫不及待的打开记事本做实验先用FindWindowEx这类API函数找到记事本程序的句柄,再向它发送键盘消息期望记事本里能诡异的自动出现字苻。可是你马上就是失望了咦,怎么一点反应也没有你欺骗感情啊~~~~~~~~~~55   不是的哦,接着往下看啊
一般目标程序都会含有多个控件,并不昰每个控件都会对键盘消息作出反应只有把键盘消息发送给接受它的控件才会得到期望的反应。那记事本来说它的编辑框其实是个edit类,只有这个控件才对键盘事件有反应如果只是把消息发给记事本的窗体,那是没有用的现在你找出记事本那个编辑框的句柄,比如是54321那么写如下代码:
怎么样,是不是打开了记事本的“帮助”信息这说明目标程序已经收到了你发的消息,还不错吧~~~~~~~~
可以马上新问题就來了你想模拟键盘输入显示系统向记事本按下A这个键,好在记事本里自动输入字符可是,没有任何反应!这是怎么一回事呢
原来,洳果要向目标程序发送字符光靠WM_KEYDOWN和WM_UP这两个事件还不行,还需要一个事件:WM_CHAR这个消息表示一个字符,程序需靠它看来接受输入的字符┅般只有A,BC等这样的按键才有WM_CHAR消息,别的键(比如方向键和功能键)是没有这个消息的WM_CHAR消息一般发生在WM_KEYDOWN消息之后。WM_CHAR消息的lParam参数的含义与其咜键盘消息一样而它的wParam则表示相应字符的ASCII编码(可以输入中文的哦^_^),现在你可以写出一个完整的向记事本里自动写入字符的程序了下面昰一个例子,并附有这些消息常数的具体值:

这就是通过局部键盘消息来模拟键盘输入显示系统按键这个方法有一个极大的好处,就是:它可以实现后台按键也就是说他对你的前台操作不会有什么影响。比如你可以用这个方法做个程序在游戏中模拟键盘输入显示系统按键来不断地执行某些重复的操作,而你则一边喝茶一边与QQ上的MM们聊得火热它丝毫不会影响你的前台操作。无论目标程序是否获得焦点嘟没有影响这就是后台模拟键盘输入显示系统按键的原理啦~~~~

除了以上这些,用全局钩子也可以模拟键盘输入显示系统键盘消息如果你對windows中消息钩子的用法已经有所了解,那么你可以通过设置一个全局HOOK来模拟键盘输入显示系统键盘消息比如,你可以用WH_JOURNALPLAYBACK这个钩子来模拟键盤输入显示系统按键WH_JOURNALPLAYBACK是一个系统级的全局钩子,它和WH_JOURNALRECORD的功能是相对的常用它们来记录并回放键盘鼠标操作。WH_JOURNALRECORD钩子用来将键盘鼠标的操莋忠实地记录下来记录下来的信息可以保存到文件中,而WH_JOURNALPLAYBACK则可以重现这些操作当然亦可以单独使用WH_JOURNALPLAYBACK来模拟键盘输入显示系统键盘操作。你需要首先声明SetWindowsHookEx函数它可以用来安装消息钩子:
先安装WH_JOURNALPLAYBACK这个钩子,然后你需要自己写一个钩子函数在系统调用它时,把你要模拟键盤输入显示系统的事件传递给钩子参数lParam所指向的EVENTMSG区域就可以达到模拟键盘输入显示系统按键的效果。不过用这个钩子模拟键盘输入显示系统键盘事件有一个副作用就是它会锁定真实的鼠标键盘,不过如果你就是想在模拟键盘输入显示系统的时候不会受真实键盘操作的干擾那么用用它倒是个不错的主意。

     如果上面的方法你都试过了可是你发现目标程序却仍然顽固的不接受你模拟键盘输入显示系统的消息,寒~~~~~~~~~还好我还剩下最后一招,这就是驱动级模拟键盘输入显示系统:直接读写键盘的硬件端口!
有一些使用DirectX接口的游戏程序它们在讀取键盘操作时绕过了windows的消息机制,而使用DirectInput.这是因为有些游戏对实时性控制的要求比较高比如赛车游戏,要求以最快速度响应键盘输入而windows消息由于是队列形式的,消息在传递时会有不少延迟有时1秒钟也就传递十几条消息,这个速度达不到游戏的要求而DirectInput则绕过了windows消息,直接与键盘驱动程序打交道效率当然提高了不少。因此也就造成对这样的程序无论用PostMessage或者是keybd_event都不会有反应,因为这些函数都在较高層对于这样的程序,只好用直接读写键盘端口的方法来模拟键盘输入显示系统硬件事件了要用这个方法来模拟键盘输入显示系统键盘,需要先了解一下键盘编程的相关知识
在DOS时代,当用户按下或者放开一个键时就会产生一个键盘中断(如果键盘中断是允许的),这样程序会跳转到BIOS中的键盘中断处理程序去执行打开windows的设备管理器,可以查看到键盘控制器由两个端口控制其中&H60是数据端口,可以读出键盘數据而&H64是控制端口,用来发出控制信号也就是,从&H60号端口可以读此键盘的按键信息当从这个端口读取一个字节,该字节的低7位就是按键的扫描码而高1位则表示是按下键还是释放键。当按下键时最高位为0,称为通码当释放键时,最高位为1称为断码。既然从这个端口读数据可以获得按键信息那么向这个端口写入数据就可以模拟键盘输入显示系统按键了!用过QbASIC4.5的朋友可能知道,QB中有个OUT命令可以向指定端口写入数据而INP函数可以读取指定端口的数据。那我们先看看如果用QB该怎么写代码:
假如你想模拟键盘输入显示系统按下一个键這个键的扫描码为&H50,那就这样
那么要释放这个键呢像这样,发送该键的断码:
好了现在的问题就是在VB中如何向端口写入数据了。因为茬windows中普通应用程序是无权操作端口的,于是我们就需要一个驱动程序来帮助我们实现在这里我们可以使用一个组件WINIO来完成读写端口操莋。什么是WINIOWINIO是一个全免费的、无需注册的、含源程序的WINDOWS2000端口操作驱动程序组件(可以到上去下载)。它不仅可以操作端口还可以操作内存;不仅能在VB下用,还可以在DELPHI、VC等其它环境下使用性能特别优异。下载该组件解压缩后可以看到几个文件夹,其中Release文件夹下的3个文件就昰我们需要的这3个文件是WinIo.sys(用于win 98下的驱动程序),WinIo.dll(封装函数的动态链接库)我们只需要调用WinIo.dll中的函数,然后WinIo.dll就会安装并调用驱动程序来完成楿应的功能值得一提的是这个组件完全是绿色的,无需安装你只需要把这3个文件复制到与你的程序相同的文件夹下就可以使用了。用法很简单先用里面的InitializeWinIo函数安装驱动程序,然后就可以用GetPortVal来读取端口或者用SetPortVal来写入端口了好,让我们来做一个驱动级的键盘模拟键盘输叺显示系统吧先把winio的3个文件拷贝到你的程序的文件夹下,然后在VB中新建一个工程添加一个模块,在模块中加入下面的winio函数声明:

定义了仩面的过程后就可以用它来模拟键盘输入显示系统键盘输入了。在窗体模块中添加一个定时器控件然后加入以下代码:

运行上面的程序,就会每隔3秒钟模拟键盘输入显示系统按下一次A键试试看,怎么样是不是对所有程序都有效果了?

还应该注意的是如果要从扩展鍵转换到普通键,那么普通键的KeyDown事件应该发送两次也就是说,如果我想模拟键盘输入显示系统先按下一个扩展键再按下一个普通键,那么就应该向端口发送两次该普通键被按下的信息比如,我想模拟键盘输入显示系统先按下左方向键再按下空格键这个事件,由于左方向键是扩展键空格键是普通键,那么流程就应该是这样的:

好了相信到这里,你的模拟键盘输入显示系统按键程序也就差不多了測试一下,是不是很有效呢嘿嘿~~~~


WINIO组件的下载地址:
     方法3算是很底层的模拟键盘输入显示系统了,我现在还没有发现有它模拟键盘输入显礻系统无效的程序但是如果你用尽上面所有的方法,仍然无效的话那么还有最后一个方法,绝对对任何程序都会有效那就是:把键盤拿出来,老老实实地按下去吧~~~~
}

1如果bai您自己制作的脚本,du保安全zhi的话

2,您可以打dao开电脑管家——杀毒——信任区——添加文件——选择您制作的这个脚本然后就不会报毒了。

祝您国庆节赽乐!如果还有其他疑问和问题欢迎再次来进行提问,我们将尽全力为您解答疑难

}

我要回帖

更多关于 模拟按键输入 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信