按键精灵硬件模拟鼠键超级模拟和硬件模拟无效

//模拟方式(0普通|1硬件|2超级)

MessageBox "这个例子會演示 普通/硬件/超级 这三种模拟方式的效果点击确定后3秒钟开始模拟,会用普通模拟按3下a硬件模拟按3下b,超级模拟按3下c"

这种复制来的東西有意思吗文不对题的
你自己问的不清楚。按键只有SetSimMode 是设置按键设置

你对这个回答的评价是?

模拟鼠标键盘操作含硬件模拟技术。
键盘是我们使用计算机的一个很重要的输入设备了即使在鼠标大行其道的今天,很多程序依然离不开键盘来操作但是有时候,┅些重复性的很繁琐的键盘操作总会让人疲惫,于是就有了用程序来代替人们按键的方法这样可以把很多重复性的键盘操作交给程序來模拟,省了很多精力按键精灵硬件模拟鼠键就是这样的一个软件。那么我们怎样才能用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函数声明:

参考资料

 

随机推荐