、应用程序级模拟,也就是说会产生一个WM

2020-01-05 19:23 来源:未知

演示工程下载

本文目录如下

演示工程下载

Windows提供了一个模拟键盘API函数Keybd_event(),使用该函数可以相应的屏蔽键盘的动作。Keybd_event()函数能触发一个按键事件,也就是说会产生一个WM_KEYDOWN或WM_KEYUP消息。

unit My_KeyBD_Event;

一、基于windows 消息机制的鼠标键盘模拟

unit Mouse_Event_Demo;

 

interface

**、应用程序级模拟**

interface

该函数原型如下:

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

**、系统级模拟**

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Menus;

  VOID keybd_event(

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

**1、 用API函数keybd_event 模拟键盘事件**

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    PopupMenu1: TPopupMenu;
    N1: TMenuItem;
    ioriliao1: TMenuItem;
    QQ825306621: TMenuItem;
    N2010811: TMenuItem;
    Button4: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  BYTE bVk, // virtual-key code

var
  Form1: TForm1;
const
     VK_0 = 48;
     VK_1 = 49;
     VK_2 = 50;
     VK_3 = 51;
     VK_4 = 52;
     VK_5 = 53;
     VK_6 = 54;
     VK_7 = 55;
     VK_8 = 56;
     VK_9 = 57;
     VK_A = 65;
     VK_B = 66;
     VK_C = 67;
     VK_D = 68;
     VK_E = 69;
     VK_F = 70;
     VK_G = 71;
     VK_H = 72;
     VK_I = 73;
     VK_J = 74;
     VK_K = 75;
     VK_L = 76;
     VK_M = 77;
     VK_N = 78;
     VK_O = 79;
     VK_P = 80;
     VK_Q = 81;
     VK_R = 82;
     VK_S = 83;
     VK_T = 84;
     VK_U = 85;
     VK_V = 86;
     VK_W = 87;
     VK_X = 88;
     VK_Y = 89;
     VK_Z = 90;
implementation

**2、 SendInput函数模拟全局键盘鼠标事件**

var
  Form1: TForm1;

  BYTE bScan, // hardware scan code

{$R *.dfm}

**3、用全局钩子模拟键盘消息**

implementation

  DWORD dwFlags, // flags specifying various function options

procedure TForm1.Button1Click(Sender: TObject);
begin
     ShowMessage('模拟成功!')
end;

**二、驱动级模拟**

{$R *.dfm}
{模拟鼠标动作API函数mouse_event,它可以实现模拟鼠标按下和放开等动作。}
{procedure mouse_event(dwFlags, dx, dy, dwData, dwExtraInfo: DWORD); stdcall;}
{参数说明:}
{dwFlags, 鼠标动作标识。}
{dx, 鼠标水平方向位置。 }
{dy, 鼠标垂直方向位置。 }
{dwData, 鼠标轮子转动的数量。}
{dwExtraInfo,一个关联鼠标动作辅加信息。}
{其中,dwFlags表示了各种各样的鼠标动作和点击活动,它的常用取值如下:}
{MOUSEEVENTF_MOVE 表示模拟鼠标移动事件。}
{MOUSEEVENTF_LEFTDOWN 表示模拟按下鼠标左键。}
{MOUSEEVENTF_LEFTUP 表示模拟放开鼠标左键。}
{MOUSEEVENTF_RIGHTDOWN 表示模拟按下鼠标右键。}
{MOUSEEVENTF_RIGHTUP 表示模拟放开鼠标右键。}
{MOUSEEVENTF_MIDDLEDOWN 表示模拟按下鼠标中键。}
{MOUSEEVENTF_MIDDLEUP 表示模拟放开鼠标中键。}

  DWORD dwExtraInfo // additional data associated with keystroke

procedure TForm1.Button2Click(Sender: TObject);
begin
    {模拟键盘动作API函数keydb_event,它可以模拟对键盘上的某个或某些键进行按下或放开的动作。}
    {procedure keybd_event(bVk: Byte; bScan: Byte; dwFlags, dwExtraInfo: DWORD); stdcall;}
    {参数说明:}
    {bVk, 虚拟键值。}
    {bScan, 硬件扫描码。}
    {dwFlags, 动作标识。}
    {dwExtraInfo, 与键盘动作关联的辅加信息。}
    {dwFlags表示各种各样的键盘动作,它有两种取值:KEYEVENTF_EXTENDEDKEY和KEYEVENTF_KEYUP。}

*******************************************************************************************

{获取当前鼠标位置函数GetCursorPos()}
{function GetCursorPos(var lpPoint: TPoint): BOOL; stdcall;}
{参数说明:}
{lpPoint, 返回鼠标的当前位置。}
{TPoint结构说明:}
{TPoint = packed record
    X: Longint; 鼠标的水平方向位置。
    Y: Longint; 鼠标的垂直方向位置。
end;}
{返回值:如果成功,返回True;如果失败,返回值为False。}

  );

    {MapVirtualKey函数将一虚拟键码翻译(映射)成一扫描码或一字符值,或者将一扫描码翻译成一虚拟键码。}
    {function MapVirtualKey(uCode, uMapType: UINT): UINT; stdcall;}
    {参数说明:}
    {uCode:定义一个键的扫描码或虚拟键码。该值如何解释依赖于uMapType参数的值。}
    {uMapType:定义将要执行的翻译。该参数的值依赖于uCode参数的值。取值如下:}
    {0:代表uCodee是一虚拟键码且被翻译为一扫描码。若一虚拟键码不区分左右,
     则返回左键的扫描码。若未进行翻译,则函数返回O。}
    {1:代表uCode是一扫描码且被翻译为一虚拟键码,且此虚拟键码不区分左右。若未进行翻译,则函数返回0。}
    {2:代表uCode为一虚拟键码且被翻译为一未被移位的字符值存放于返回值的低序字中。
        死键(发音符号)则通过设置返回值的最高位来表示。若未进行翻译,则函数返回0。}
    {3:代表uCode为一扫描码且被翻译为区分左右键的一虚拟键码。若未进行翻译,则函数返回0。}
    {返回值:返回值可以是一扫描码,或一虚拟键码,或一字符值,
     这完全依赖于不同的uCode和uMapType的值。若未进行翻译,则函数返回O。}

一、基于windows 消息机制的鼠标键盘模拟

{设置当前鼠标位置函数SetCursorPos()。}
{function SetCursorPos(X, Y: Integer): BOOL; stdcall;}
{参数说明:}
{X, 鼠标的水平方向位置。}
{Y, 鼠标的垂直方向位置。}
{返回值:如果成功,返回True;如果失败,返回值为False。}

  从原型可以看出,Keybd_event()共有四个参数:

    {模拟ALT键按下}
    KeyBD_Event(VK_MENU,MapVirtualKey(VK_MENU,0),0,0);
    {模拟C键按下}
    KeyBD_Event(VK_C,MapVirtualKey(VK_C,0),0,0);
    {模拟C键弹起}
    KeyBD_Event(VK_C,MapVirtualKey(VK_C,0),KEYEVENTF_KEYUP,0);
    {模拟ALT键起}
    KeyBD_Event(VK_MENU,MapVirtualKey(VK_MENU,0),KEYEVENTF_KEYUP,0);
end;

我们怎样才能用Delphi来写一个程序,用来代替人们按键的方法呢?那就让我们来先了解一下windows中响应键盘事件的机制。

procedure TForm1.FormCreate(Sender: TObject);
begin

      第一个为按键的虚拟键值,如回车键为vk_return, tab键为vk_tab(其他具体的参见附录:常用模拟键的键值对照表);

end.

当用户按下键盘上的一个键时,键盘内的芯片会检测到这个动作,并把这个信号传送到计算机。如何区别是哪一个键被按下了呢?键盘上的所有按键都有一个编码,称作键盘扫描码。当你按下一个键时,这个键的扫描码就被传给系统。扫描码是跟具体的硬件相关的,同一个键,在不同键盘上的扫描码有可能不同。键盘控制器就是将这个扫描码传给计算机,然后交给键盘驱动程序。键盘驱动程序会完成相关的工作,并把这个扫描码转换为键盘虚拟码。什么是虚拟码呢?因为扫描码与硬件相关,不具有通用性,为了统一键盘上所有键的编码,于是就提出了虚拟码概念。无论什么键盘,同一个按键的虚拟码总是相同的,这样程序就可以识别了。简单点说,虚拟码就是我们经常可以看到的像VK_A,VK_B这样的常数,比如键A的虚拟码是65,写成16进制就是&H41,注意,人们经常用16进制来表示虚拟码。当键盘驱动程序把扫描码转换为虚拟码后,会把这个键盘操作的扫描码和虚拟码还有其它信息一起传递给操作系统。然后操作系统则会把这些信息封装在一个消息中,并把这个键盘消息插入到消息列队。最后,要是不出意外的话,这个键盘消息最终会被送到当前的活动窗口那里,活动窗口所在的应用程序接收到这个消息后,就知道键盘上哪个键被按下,也就可以决定该作出什么响应给用户了。

end;
{模拟鼠标相对当前位置水平移动50个像素}
procedure TForm1.Button1Click(Sender: TObject);begin
     Mouse_Event(MOUSEEVENTF_MOVE,50,0,0,0);
end;

      第二个参数为扫描码,一般不用设置,用0代替就行;

永利平台娱乐 1

这个过程可以简单的如下表示:

{模拟鼠标左键单击}
procedure TForm1.Button2Click(Sender: TObject);begin
     {先把鼠标移动到目标按钮}
     Mouse_Event(MOUSEEVENTF_MOVE,30,0,0,0);
     {模拟鼠标左键按下动作}
     Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
     {模拟鼠标左键弹起动作}
     Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
end;

      第三个参数为选项标志,如果为keydown则置0即可,如果为keyup则设成"KEYEVENTF_KEYUP";

用户按下键盘上的一个键 >>>>> 键盘控制器就把这个键的扫描码传给计算机,然后交给键盘驱动程序 >>>>> 键盘驱动程序会把这个扫描码转换为键盘虚拟码(VK_A,VK_B这样的常数,比如键A的虚拟码是65,写成16进制就是&H41)传给操作系统 >>>>> 操操作系统则会把这些信息封装在一个消息中,并把这个键盘消息插入到消息列队 >>>>> 键盘消息被发送到当前活动窗口

procedure TForm1.Button3Click(Sender: TObject);begin
      ShowMessage('鼠标左键已经单击中了我');
end;

      第四个参数一般也是置0即可。

明白了这个过程,我们就可以编程实现在其中的某个环节来模拟键盘操作了。在Delphi中,有多种方法可以实现键盘模拟,我们就介绍几种比较典型的。

procedure TForm1.Button4Click(Sender: TObject);
begin
     {先把鼠标移动到目标窗体}
     Mouse_Event(MOUSEEVENTF_MOVE,0,50,0,0);
     {模拟鼠标右键按下动作}
     Mouse_Event(MOUSEEVENTF_RIGHTDOWN,0,0,0,0);
     {模拟鼠标右键弹起动作}
     Mouse_Event(MOUSEEVENTF_RIGHTUP,0,0,0,0);
end;

 

、应用程序级模拟(只针对某个程序,我称之为局部模拟)

end.

例子1:模拟按下'A'键
   keybd_event(65,0,0,0);
   keybd_event(65,0,KEYEVENTF_KEYUP,0);

windows提供了几个这样的API函数可以实现直接向目标程序发送消息的功能,常用的有SendMessage和PostMessage,它们的区别是PostMessage函数直接把消息仍给目标程序就不管了,而SendMessage把消息发出去后,还要等待目标程序返回些什么东西才好。这里要注意的是,模拟键盘消息一定要用PostMessage函数才好,用SendMessage是不正确的(因为模拟键盘消息是不需要返回值的,不然目标程序会没反应),切记切记!

永利平台娱乐 2

 

PostMessage函数的delphi声明如下:

例子2:模拟按下'ALT+F4'键
   keybd_event(18,0,0,0);
   keybd_event(115,0,0,0);
   keybd_event(115,0,KEYEVENTF_KEYUP,0);
   keybd_event(18,0,KEYEVENTF_KEYUP,0);

PostMessage(

 

hWnd: HWND; {目标程序上某个控件的句柄}

附:常用模拟键的键值对照表(也可参考)

Msg: UINT; {消息的类型}

 

wParam: WPARAM; {32位指定附加的消息特定的信息}

                                                         键盘键与虚拟键码对照表

lParam: LPARAM {32位指定附加的消息特定的信息}

 

): BOOL;

      字母和数字键 数字小键盘的键          功能键          其它键 
      键   键码    键   键码    键   键码     键    键码 
      A   65     0   96     F1   112   Backspace    8 
      B   66     1   97     F2   113   Tab       9 
      C   67     2   98      F3   114    Clear      12 
      D   68   3   99     F4   115  Enter      13 
      E   69     4   100    F5   116  Shift      16 
      F   70     5   101    F6   117  Control     17 
      G   71     6   102    F7   118   Alt       18 
      H   72    7   103    F8   119  Caps Lock    20 
      I   73    8   104    F9   120  Esc       27 
      J   74    9   105    F10  121  Spacebar    32 
      K   75    *   106     F11  122  Page Up     33 
      L   76    +   107     F12  123  Page Down    34 
      M   77    Enter 108    --   --   End       35 
      N   78    -

参数hwnd 是你要发送消息的目标程序上某个控件的句柄,参数Msg 是消息的类型,表示你要发送什么样的消息,最后wParam 和lParam这两个参数是随消息附加的数据,具体内容要由消息决定。

再来看看Msg 这个参数,要模拟按键就靠这个了。

键盘消息常用的有如下几个:

WM_KEYDOWN 表示一个普通键被按下

WM_KEYUP 表示一个普通键被释放

WM_SYSKEYDOWN 表示一个系统键被按下,比如Alt键

WM_SYSKEYUP 表示一个系统键被释放,比如Alt键

如果你确定要发送以上几个键盘消息,那么再来看看如何确定键盘消息中的wParam 和lParam 这两个参数。在一个键盘消息中,wParam 参数的含义较简单,它表示你要发送的键盘事件的按键虚拟码,比如你要对目标程序模拟按下A键,那么wParam 参数的值就设为VK_A ,至于lParam 这个参数就比较复杂了,因为它包含了多个信息,一般可以把它设为0。即

PostMessage (MyHwnd, WM_KEYDOWN, key, 0);

但是如果你想要你的模拟更真实一些,那么建议你还是设置一下这个参数。那么我们就详细了解一下lParam 吧。

lParam 是一个32 bit的参数,它在内存中占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码。它的delphi 声明如下:

MapVirtualKey(

uCode: UINT; {key code, scan code or virtual key}

uMapType: UINT {flags for translation mode}

): UINT; {returns translated key code}

永利平台娱乐,参数uCode 表示待转换的码,参数uMapType 表示从什么转换为什么,如果是虚拟码转扫描码,则uMapType 设置为0,如果是虚拟扫描码转虚拟码,则wMapType 设置为1,如果是虚拟码转ASCII码,则uMapType 设置为2.相信有了这些,我们就可以构造键盘事件的lParam参数了。

下面给出一个构造lParam参数的函数:

function VKB_param(VirtualKey:Integer;flag:Integer):Integer; //函数名

var

s,Firstbyte,Secondbyte:String;

S_code:Integer;

Begin

if flag=1 then //按下键

begin

Firstbyte :='00'

end

else //弹起键

begin

Firstbyte :='C0'

end;

S_code:= MapVirtualKey(VirtualKey, 0);

Secondbyte:='00'+inttostr;

Secondbyte:=copy(Secondbyte,Length(Secondbyte)-1,2);

s:='$'+Firstbyte + Secondbyte + '0001';

Result:=strtoint;

End;

使用按键的方法:

说明:key为键值,如1键[不是数字键的1]的值是$31,flag传递的是按键状态,1是按下,0是弹起。

lparam := VKB_param; {按下键}

PostMessage (MyHwnd, WM_KEYDOWN, key, lParam);

lParam := VKB_param; {松开键}

PostMessage (MyHwnd, WM_KEYUP, key, lParam);

var

hwnd, lparam:Cardinal;

begin

hwnd:=FindWindowEx(FindWindow(nil,'无标题 - 记事本'),0,'edit',nil);

lparam := VKB_param; {按下键}

PostMessage (hwnd,WM_KEYDOWN,vk_F3,lparam) ; //按下F3键

//PostMessage (hwnd,WM_CHAR,97,lparam); //输入字符A (edit控件接收字符)

lParam := VKB_param; {松开键}

PostMessage (hwnd,WM_KEYUP,vk_F3,lparam); //释放F3键

end;

模拟鼠标点击

Var

P1:Tpoint;

Lparam:integer;

begin

GetCursorPos; // 获取屏幕坐标

P1.X:= P1.X+100;

P1.Y:=P1.Y+100;

lparam:=p1.X+ p1.Y shl 16;

sendmessage(h,messages.WM_LBUTTONDOWN ,0,lparam);// 按下鼠标左键

sendmessage(h,messages.WM_LBUTTONUP ,0, lparam); //抬起鼠标左键

End;

、系统级模拟(针对所有程序的窗口,我称之为全局模拟)

模拟全局键盘消息常见的可以有以下一些方法:

1、 用API函数keybd_event,这个函数可以用来模拟一个键盘事件

keybd_event(

bVk: Byte; {virtual-key code}

bScan: Byte; {scan-code}

dwFlags: DWORD; {option flags}

dwExtraInfo: DWORD {additional information about the key}

); {this procedure does not return a value}

keybd_event(VK_A, 0, 0, 0) '按下A键

keybd_event (VK_A, 0, KEYEVENTF_KEYUP, 0) '释放A键

注意有时候按键的速度不要太快,否则会出问题,可以用API函数Sleep来进行延时,delphi声明如下:

Sleep(

dwMilliseconds: DWORD {specifies the number of milliseconds to pause}

);

参数dwMilliseconds表示延时的时间,以毫秒为单位。

TAG标签:
版权声明:本文由永利平台娱乐发布于新闻动态,转载请注明出处:、应用程序级模拟,也就是说会产生一个WM