VB postmessage发送后台Tab

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

1.局部级模拟
从上面的流程能够看出,键盘事件是最终被送到活动窗口,而后才引发目标程序响应的。那么最直接的模拟方法就是:直接伪造一个键盘消息发给目标程序。哈哈,这实在是很简单,windows提供了几个这样的API函数能够实现直接向目标程序发送消息的功能,经常使用的有SendMessage和PostMessage,它们的区别是PostMessage函数直接把消息仍给目标程序就无论了,而SendMessage把消息发出去后,还要等待目标程序返回些什么东西才好。这里要注意的是,模拟键盘消息必定要用PostMessage函数才好,用SendMessage是不正确的(由于模拟键盘消息是不须要返回值的,否则目标程序会没反应),切记切记!PostMessage函数的VB声明以下:
Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
参数hwnd 是你要发送消息的目标程序上某个控件的句柄,参数wMsg 是消息的类型,表示你要发送什么样的消息,最后wParam 和lParam 这两个参数是随消息附加的数据,具体内容要由消息决定。
再来看看wMsg 这个参数,要模拟按键就靠这个了。键盘消息经常使用的有以下几个:
WM_KEYDOWN 表示一个普通键被按下
WM_KEYUP 表示一个普通键被释放
WM_SYSKEYDOWN 表示一个系统键被按下,好比Alt键
WM_SYSKEYUP 表示一个系统键被释放,好比Alt键
若是你肯定要发送以上几个键盘消息,那么再来看看如何肯定键盘消息中的wParam 和lParam 这两个参数。在一个键盘消息中,wParam 参数的含义较简单,它表示你要发送的键盘事件的按键虚拟码,好比你要对目标程序模拟按下A键,那么wParam 参数的值就设为VK_A ,至于lParam 这个参数就比较复杂了,由于它包含了多个信息,通常能够把它设为0,可是若是你想要你的模拟更真实一些,那么建议你仍是设置一下这个参数。那么咱们就详细了解一下lParam 吧。lParam 是一个long类型的参数,它在内存中占4个字节,写成二进制就是00000000 00000000 00000000 00000000 一共是32位,咱们从右向左数,假设最右边那位为第0位(注意是从0而不是从1开始计数),最左边的就是第31位,那么该参数的的0-15位表示键的发送次数等扩展信息,16-23位为按键的扫描码,24-31位表示是按下键仍是释放键。你们通常习惯写成16进制的,那么就应该是&H00 00 00 00 ,第0-15位通常为&H0001,若是是按下键,那么24-31位为&H00,释放键则为&HC0,那么16-23位的扫描码怎么会得呢?这须要用到一个API函数MapVirtualKey,这个函数能够将虚拟码转换为扫描码,或将扫描码转换为虚拟码,还能够把虚拟码转换为对应字符的ASCII码。它的VB声明以下:
Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
参数wCode 表示待转换的码,参数wMapType 表示从什么转换为何,若是是虚拟码转扫描码,则wMapType 设置为0,若是是虚拟扫描码转虚拟码,则wMapType 设置为1,若是是虚拟码转ASCII码,则wMapType 设置为2.相信有了这些,咱们就能够构造键盘事件的lParam参数了。下面给出一个构造lParam参数的函数:
Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Function MakeKeyLparam(ByVal VirtualKey As Long, ByVal flag As Long) As Long
'参数VirtualKey表示按键虚拟码,flag表示是按下键仍是释放键,用WM_KEYDOWN和WM_KEYUP这两个常数表示
Dim s As String
Dim Firstbyte As String 'lparam参数的24-31位
If flag = WM_KEYDOWN Then '若是是按下键
Firstbyte = "00"
Else
Firstbyte = "C0" '若是是释放键
End If
Dim Scancode As Long
'得到键的扫描码
Scancode = MapVirtualKey(VirtualKey, 0)
Dim Secondbyte As String 'lparam参数的16-23位,即虚拟键扫描码
Secondbyte = Right("00" & Hex(Scancode), 2)
s = Firstbyte & Secondbyte & "0001" '0001为lparam参数的0-15位,即发送次数和其它扩展信息
MakeKeyLparam = Val("&H" & s)
End Function
这个函数像这样调用,好比按下A键,那么lParam=MakeKeyLparam(VK_A,WM_KEYDOWN) ,很简单吧。值得注意的是,即便你发送消息时设置了lParam参数的值,可是系统在传递消息时仍然可能会根据当时的状况从新设置该参数,那么目标程序收到的消息中lParam的值可能会和你发送时的有所不一样。因此,若是你很懒的话,仍是直接把它设为0吧,对大多数程序不会有影响的,呵呵。
好了,作完以上的事情,如今咱们能够向目标程序发送键盘消息了。首先取得目标程序接受这个消息的控件的句柄,好比目标句柄是12345,那么咱们来对目标模拟按下并释放A键,像这样:(为了简单起见,lParam这个参数就不构造了,直接传0)
PostMessage 12345,WM_KEYDOWN,VK_A,0& '按下A键
PostMessage 12345,WM_UP,VK_A,0& '释放A键
好了,一次按键就完成了。如今你能够火烧眉毛的打开记事本作实验,先用FindWindowEx这类API函数找到记事本程序的句柄,再向它发送键盘消息,指望记事本里能诡异的自动出现字符。但是你立刻就是失望了,咦,怎么一点反应也没有?你欺骗感情啊~~~~~~~~~~55555555555555 不是的哦,接着往下看啊。
通常目标程序都会含有多个控件,并非每一个控件都会对键盘消息做出反应,只有把键盘消息发送给接受它的控件才会获得指望的反应。那记事原本说,它的编辑框实际上是个edit类,只有这个控件才对键盘事件有反应,若是只是把消息发给记事本的窗体,那是没有用的。如今你找出记事本那个编辑框的句柄,好比是54321,那么写以下代码:
PostMessage 54321,WM_KEYDOWN,VK_F1,0& '按下F1键
PostMessage 54321,WM_UP,VK_F1,0& '释放F1键
怎么样,是否是打开了记事本的“帮助”信息?这说明目标程序已经收到了你发的消息,还不错吧~~~~~~~~
能够立刻新问题就来了,你想模拟向记事本按下A这个键,好在记事本里自动输入字符,但是,没有任何反应!这是怎么一回事呢?
原来,若是要向目标程序发送字符,光靠WM_KEYDOWN和WM_UP这两个事件还不行,还须要一个事件:WM_CHAR,这个消息表示一个字符,程序需靠它看来接受输入的字符。通常只有A,B,C等这样的按键才有WM_CHAR消息,别的键(好比方向键和功能键)是没有这个消息的,WM_CHAR消息通常发生在WM_KEYDOWN消息以后。WM_CHAR消息的lParam参数的含义与其它键盘消息同样,而它的wParam则表示相应字符的ASCII编码(能够输入中文的哦^_^),如今你能够写出一个完整的向记事本里自动写入字符的程序了,下面是一个例子,并附有这些消息常数的具体值:
Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Public Const WM_KEYDOWN = &H100
Public Const WM_KEYUP = &H101
Public Const WM_CHAR = &H102
Public Const VK_A = &H41
Function MakeKeyLparam(ByVal VirtualKey As Long, ByVal flag As Long) As Long
Dim s As String
Dim Firstbyte As String 'lparam参数的24-31位
If flag = WM_KEYDOWN Then '若是是按下键
Firstbyte = "00"
Else
Firstbyte = "C0" '若是是释放键
End If
Dim Scancode As Long
'得到键的扫描码
Scancode = MapVirtualKey(VirtualKey, 0)
Dim Secondbyte As String 'lparam参数的16-23位,即虚拟键扫描码
Secondbyte = Right("00" & Hex(Scancode), 2)
s = Firstbyte & Secondbyte & "0001" '0001为lparam参数的0-15位,即发送次数和其它扩展信息
MakeKeyLparam = Val("&H" & s)
End Function
Private Sub Form_Load()
dim hwnd as long
hwnd = XXXXXX 'XXXXX表示记事本编辑框的句柄
PostMessage hwnd,WM_KEYDOWN,VK_A,MakeKeyLparam(VK_A,WM_KEYDOWN) '按下A键
PostMessage hwnd,WM_CHAR,ASC("A"),MakeKeyLparam(VK_A,WM_KEYDOWN) '输入字符A
PostMessage hwnd,WM_UP,VK_A,MakeKeyLparam(VK_A,WM_UP) '释放A键
End Sub
这就是经过局部键盘消息来模拟按键。这个方法有一个极大的好处,就是:它能够实现后台按键,也就是说他对你的前台操做不会有什么影响。好比,你能够用这个方法作个程序在游戏中模拟按键来不断地执行某些重复的操做,而你则一边喝茶一边与QQ上的MM们聊得火热,它丝绝不会影响你的前台操做。不管目标程序是否得到焦点都没有影响,这就是后台模拟按键的原理啦~~~~




'根据你的反馈,可知有的游戏已经屏蔽了KEYDOWN消息,因此不妨使用WM_LBUTTONDOWN,也许会成功。修改以下:

'用PostMessage,必须先知道目标的句柄hwd
Option Explicit
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202

Private Sub Command1_Click()
PostMessage Hwd, WM_LBUTTONDOWN, 0, 0 '模拟按下指定键
PostMessage Hwd, WM_LBUTTONUP, 0, 0
End Sub





用上面的方法模拟按键并非对全部程序都有效的,有的程序啊,你向它发了一大堆消息,但是它却一点反应也没有。这是怎么回事呢? 这就要看具体的状况了,有些程序(特别是一些游戏)出于某些缘由,会禁止用户对它使用模拟按键程序,这个怎么实现呢?好比能够在程序中检查一下,若是发现 本身不是活动窗口,就不接受键盘消息。或者仔细检查一下收到的键盘消息,你会发现真实的按键和模拟的按键消息老是有一些小差异,从这些小差异上,目标程序 就能判断出:这是假的!是伪造的!!所以,若是用PostMessage发送局部消息模拟按键不成功的话,你能够试一试全局级的键盘消息,看看能不能骗过 目标程序。 模拟全局键盘消息常见的能够有如下一些方法: (1) 用API函数keybd_event,这个函数能够用来模拟一个键盘事件,它的VB声明为: Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long) 参数bVk表示要模拟的按键的虚拟码,bScan表示该按键的扫描码(通常能够传0),dwFlags表示是按下键仍是释放键(按下键为0,释放键为2),dwExtraInfo是扩展标志,通常没有用。好比要模拟按下TAB键,能够这样: Const KEYEVENTF_KEYUP = &H2Const VK_TAB = &H9 keybd_event VK_TAB, 0, 0, 0 '按下TAB键 keybd_event VK_TAB, 0, KEYEVENTF_KEYUP, 0 '释放TAB键 注意有时候按键的速度不要太快,不然会出问题,能够用API函数Sleep来进行延时,声明以下: Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 参数dwMilliseconds表示延时的时间,以毫秒为单位。 那么若是要模拟按下功能键怎么作呢?好比要按下Ctrl+C实现拷贝这个功能,能够这样: keybd_event VK_Ctrl, 0, 0, 0 '按下Ctrl键 keybd_event VK_C, 0, 0, 0 '按下C键 Sleep 500 '延时500毫秒 keybd_event VK_C, 0, KEYEVENTF_KEYUP, 0 '释放C键 keybd_event VK_Ctrl, 0, KEYEVENTF_KEYUP, 0 '释放Ctrl键 好 了,如今你能够试试是否是能够骗过目标程序了,这个函数对大部分的窗口程序都有效,但是仍然有一部分游戏对它产生的键盘事件熟视无睹,这时候,你就要用上 bScan这个参数了。通常的,bScan都传0,可是若是目标程序是一些DirectX游戏,那么你就须要正确使用这个参数传入扫描码,用了它能够产生 正确的硬件事件消息,以被游戏识别。这样的话,就能够写成这样: Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long '先声明API函数mapvirtualkey,能够将字符转换为键盘扫描码 keybd_event VK_TAB, MapVirtualKey(VK_TAB, 0), 0, 0 '按下TAB键 keybd_event VK_TAB, MapVirtualKey(VK_TAB, 0), KEYEVENTF_KEYUP, 0 '释放TAB键 以上就是用keybd_event函数来模拟键盘事件。除了这个函数,SendInput函数也能够模拟全局键盘事件。另外用全局钩子也能够模拟键盘消息,不过我的以为比较啰嗦,呵呵
相关文章
相关标签/搜索