admin管理员组

文章数量:1571935

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

原文地址:http://wwwblogs/Jnshushi99/archive/2011/09/03.html



以前就想过如何模拟键盘按键向其他程序发送控制命令,但总是无功而返,这次也不例外。
模拟按键的方法很多,如PostMessage(不能用SendMessage),SendInput,keybd_event。
但最要命的是以上方法基本上都要窗口获取焦点时才有效。也就是想后台模拟键盘按键难度
是很高的。

当然有些特殊情况。
一、模拟单个按键,如按下键A
用::PostMessage(hWnd,WM_KEYDOWN,'A',0); 在一般情况下可以,即使目标程序在后台运行也可以。
但正如你等下在下面看到的文章所说,在某些程序里第四个参数需要特别注意,否则发送按键将无效。

二、模拟ALT+'A'
向后台程序发送组合键ALT+按键 是可行的。记住,只可以是ALT,不能是Ctrl或Shift
操作如下:发送ALT+'A'
::PostMessage(hWnd,WM_SYSKEYDOWN,'A',1<<29);

三、我现在的做法只能是激活目标窗口使其成为前台窗口后再模拟发送组合按键,如下:
但这个方法有时也不行,因为SetForegroundWindow有时会无法激活窗口
SetForegroundWindow(g_OperaWnd);
keybd_event(VK_CONTROL,0,0,0);
keybd_event(65,0,0,0);
keybd_event(65,0,KEYEVENTF_KEYUP,0);
keybd_event(VK_CONTROL,0,KEYEVENTF_KEYUP,0);

四、模拟鼠标的行为最好用SendMessage(不要用PostMessage),这样可以把消息直接发送
到目的窗口的窗口处理过程。成功率会高很多。
::SendMessage(GetWnd(),WM_LBUTTONDOWN,NULL,MAKELPARAM(47,11));
::SendMessage(GetWnd(),WM_LBUTTONUP,NULL,MAKELPARAM(40,65));
::SendMessage(GetWnd(),WM_MOUSEMOVE,NULL,MAKELPARAM(40,65));


五、按以下文章所说的,我们不能用PostMessage模拟键盘组合键
http://blogs.msdn/b/oldnewthing/archive/2005/05/30/423202.aspx


━━━━━━━━━━━━━━━━━━━━━━━━
六、以下是一些网上的资料,供大家参考:

WM_KEYDOWN:

0-15位:指定当前消息的重复次数。其值就是用户按下该键后自动重复的次数,但是重复次数不累积
16-23位:指定其扫描码,其值依赖于OEM厂商
24位:指定该按键是否为扩展按键,所谓扩展按键就是Ctrl,Alt之类的,如果是扩展按键,其值为1,否则为0
25-28位:保留字段,暂时不可用
29位:指定按键时的上下文,其值为1时表示在按键时Alt键被按下,其值为0表示WM_SYSKEYDOWN消息因没有任何窗口有键盘焦点而被发送到当前活动窗口。
30位:指定该按键之前的状态,其值为1时表示该消息发送前,该按键是被按下的,其值为0表示该消息发送前该按键是抬起的。
31位:指定其转换状态,对WM_SYSKEYDOWN消息而言,其值总为0。


Param资讯
  在四个按键讯息(WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN和WM_SYSKEYUP)中,wParam讯息参数含有上面
所讨论的虚拟键码,而lParam讯息参数则含有对了解按键非常有用的其他资讯。lParam的32位分为6个栏位,
如图所示。在Win 3.x中,WPARAM是16位的,而LPARAM是32位的,两者有明显的区别。因为地址通常是32位的,
所以LPARAM被用来传递地址,这个习惯在Win32 API中仍然能够看到。在Win32 API中,WPARAM和LPARAM都是32位,
所以没有什么本质的区别。Windows的消息必须参考帮助文件才能知道具体的含义。如果是你定义的消息,
愿意怎么使这两个参数都行。但是习惯上,我们愿意使用LPARAM传递地址,而WPARAM传递其他参数。


━━━━━━━━━━━━━━━━━━━━━━━━

PostMessage模拟后台按键第四参数的初次探究
  最近做游戏挂机的时候,遇到一个问题。PostMessage可以很方便地后台按键,可是第四个参数却随着第三个参数(按键代码,或称虚拟键码)的改变而改变。在普通的程序中,第四个参数赋予零就可以实现按键,但是在游戏中是不行的(可能是游戏会检测吧,个人猜测)
  于是我到 MSDN 上查找相关资料。

  lParam
  The repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown following.
Bits Meaning
0-15 The repeat count for the current message. The value is the number of times the keystroke is autorepeated as a result of the user holding down the key. If the keystroke is held long enough, multiple messages are sent. However, the repeat count is not cumulative.
16-23 The scan code. The value depends on the OEM.
24 Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25-28 Reserved; do not use.
29 The context code. The value is always 0 for a WM_KEYDOWN message.
30 The previous key state. The value is 1 if the key is down before the message is sent, or it is zero if the key is up.
31 The transition state. The value is always 0 for a WM_KEYDOWN message.
  来源:http://msdn.microsoft/en-us/library/ms646280%28VS.85%29.aspx

  原来 lParam 有特殊的含义,其第0~15位是表示键重复的次数,第16~23位是键的 Scan Code,组合键需要设置第24位。看来问题是在第16~23位的 Scan Code 上了。怎么获取这个 Scan Code 呢?其实很容易,微软给我们提供了一个 API:MapVirtualKey。
  在易语言中的声明格式:
  
复制代码

.DLL命令 MapVirtualKey, 整数型, "user32.dll", "MapVirtualKeyA"
.参数 uCode, 整数型
.参数 uMapType, 整数型

  知道了道理就好办了,第一个参数无疑是键代码,第二个参数是什么?查下 MSDN。

  uMapType [in] UINT
  The translation to be performed. The value of this parameter depends on the value of the uCode parameter.
Value Meaning
MAPVK_VK_TO_CHAR
2 uCode is a virtual-key code and is translated into an unshifted character value in the low-order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
MAPVK_VK_TO_VSC
0 uCode is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
MAPVK_VSC_TO_VK
1 uCode is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
MAPVK_VSC_TO_VK_EX
3 uCode is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
  来源:http://msdn.microsoft/en-us/library/ms646306%28VS.85%29.aspx
  我们需要的是 MAP_VK_VK_TO_VSC (即0)。下面的事情就好办了。我们先通过这个 API 获取到 Scan Code,然后 左移16位,再加上1,得到 lParam,PostMessage WM_KEYDOWN、WM_KEYUP 即可。
  源码就不带了,懂者自懂,不懂的源码上了也没用。



━━━━━━━━━━━━━━━━━━━━━━━━
VB PostMessage 向Windows窗口发送Alt组合键2008-04-30 01:40关于向Windows窗口发送Alt组合键的问题,这个真是经典问题啊,在网上找了一下,问的人N多,方法差不多,
但就是没有很好解决问题。
之前找到一个能正确发送的code:(Alt+A)

PostMessage(hWnd,WM_SYSKEYDOWN,VK_MENU,0);
PostMessage(hWnd,WM_SYSKEYDOWN,0x41,0);
Sleep(50);
PostMessage(hWnd,WM_SYSKEYUP,0x41,0);
PostMessage(hWnd,WM_SYSKEYUP,VK_MENU,0);

有人解释说,按下组合键的时候系统是发两条消息的
但是看到Win32 SDK,感觉上就发一次就可以了……
偶然间又看到最后一个参数的说明,有所发现!先看WM_SYSKEYDOWN的help
The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when the user holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lKeyData parameter.

WM_SYSKEYDOWN
nVirtKey = (int) wParam; // virtual-key code
lKeyData = lParam; // key data
Parameters
nVirtKey
Value of wParam. Specifies the virtual-key code of the key being pressed.
lKeyData
Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:
Value Description
0-15 Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16-23 Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24 Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25-28 Reserved; do not use.
29 Specifies the context code. The value is 1 if the ALT key is down while the key is pressed; it is 0 if the WM_SYSKEYDOWN message is posted to the active window because no window has the keyboard focus.
30 Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31 Specifies the transition state. The value is always 0 for a WM_SYSKEYDOWN message.

之前曾经修改过keyData的16-23位为VK_MENU,第30位参数为1,但没效果
请看位29的说明!!
The value is 1 if the ALT key is down while the key is pressed;
当值为1时表示ALT键被按下!这不正是我需要的吗?于是把29位设置为1,函数调用变成
PostMessage(hWnd,WM_SYSKEYDOWN,0x41,1<<29);
经过测试,发现这个就是Alt+A的效果!!原来这么简单,但为什么很多人弄得那么复杂,我当时查找的时候也是迷惘啊,浪费了N多小时。
类似有个WM_SYSKEYUP,WM_SYSCHAR(这个不知道干什么用)


━━━━━━━━━━━━━━━━━━━━━━━━

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

1.局部级模拟

从上面的流程可以看出,键盘事件是最终被送到活动窗口,然后才引起目标程序响应的。那么最直接的模拟方法就是:直接伪造一个键盘消息发给目标程序。哈哈,这实在是很简单,windows提供了几个这样的API函数可以实现直接向目标程序发送消息的功能,常用的有SendMessage和 PostMessage࿰

本文标签: 按键键盘