首页  编辑  

模拟和发送按键

Tags: /超级猛料/Hardware.硬件相关/键盘和鼠标/   Date Created:

下面的代码是模拟Ctrl+C和Ctrl+V:

//Ctrl+C:

keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0);

keybd_event(Ord('C'), MapVirtualKey(Ord('C'), 0), 0, 0);

keybd_event(Ord('C'), MapVirtualKey(Ord('C'), 0), KEYEVENTF_KEYUP, 0);

keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0)

//Ctrl+V:

keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0);

keybd_event(Ord('V'), MapVirtualKey(Ord('V'), 0), 0, 0);

keybd_event(Ord('V'), MapVirtualKey(Ord('V'), 0), KEYEVENTF_KEYUP, 0);

keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0)

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

按下一个键最好用SendMessage,用sndkey32.pas无疑会增加程序尺寸。

组合键(超过两个以上)用sndkey32.pas就显出优势来了。

另一种解决方法,下例模拟按下Alt+Down,可参见Delphi SDK的帮助:

 keybd_event( VK_MENU, MapVirtualKey( VK_MENU, 0 ), 0 , 0 );     // Alt down

 keybd_event( VK_DOWN, MapVirtualKey( VK_DOWN, 0 ), 0 , 0 );     // down arrow key down

 keybd_event( VK_DOWN, MapVirtualKey( VK_DOWN, 0 ), KEYEVENTF_KEYUP , 0 );  // down arrow key up

 keybd_event( VK_MENU, MapVirtualKey( VK_MENU, 0 ), KEYEVENTF_KEYUP , 0 );  // Alt key up

让 WIN95 模拟按了一个按键,例如按下 ENTER或者 TAB 键?

PostMessage(Object.Handle, WM_KEYDOWN, VK_TAB, 0);

////////////////////////////////

unit Unit1;

interface

uses

 SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

 Forms, Dialogs, StdCtrls;

type

 TForm1 = class(TForm)

   Button1: TButton;

   Button2: TButton;

   procedure Button1Click(Sender: TObject);

   procedure Button2Click(Sender: TObject);

   procedure FormKeyPress(Sender: TObject; var Key: Char);

 private

   AppInst: THandle;

   AppWind: THandle;

 public

   { Public declarations }

 end;

var

 Form1: TForm1;

implementation

{$R *.DFM}

uses ShellAPI;

procedure SendShift(H: HWnd; Down: Boolean);

var vKey, ScanCode, wParam: Word;

   lParam: longint;

begin

 vKey:= $10;

 ScanCode:= MapVirtualKey(vKey, 0);

 wParam:= vKey or ScanCode shl 8;

 lParam:= longint(ScanCode) shl 16 or 1;

 if not(Down) then lParam:= lParam or $C0000000;

 SendMessage(H, WM_KEYDOWN, vKey, lParam);

end;

procedure SendCtrl(H: HWnd; Down: Boolean);

var vKey, ScanCode, wParam: Word;

   lParam: longint;

begin

 vKey:= $11;

 ScanCode:= MapVirtualKey(vKey, 0);

 wParam:= vKey or ScanCode shl 8;

 lParam:= longint(ScanCode) shl 16 or 1;

 if not(Down) then lParam:= lParam or $C0000000;

 SendMessage(H, WM_KEYDOWN, vKey, lParam);

end;

procedure SendKey(H: Hwnd; Key: char);

var vKey, ScanCode, wParam: Word;

   lParam, ConvKey: longint;

   Shift, Ctrl: boolean;

begin

 ConvKey:= OemKeyScan(ord(Key));

 Shift:= (ConvKey and $00020000) <> 0;

 Ctrl:= (ConvKey and $00040000) <> 0;

 ScanCode:= ConvKey and $000000FF or $FF00;

 vKey:= ord(Key);

 wParam:= vKey;

 lParam:= longint(ScanCode) shl 16 or 1;

 if Shift then SendShift(H, true);

 if Ctrl then SendCtrl(H, true);

 SendMessage(H, WM_KEYDOWN, vKey, lParam);

 SendMessage(H, WM_CHAR, vKey, lParam);

 lParam:= lParam or $C0000000;

 SendMessage(H, WM_KEYUP, vKey, lParam);

 if Shift then SendShift(H, false);

 if Ctrl then SendCtrl(H, false);

end;

function EnumFunc(Handle: HWnd; TF: TForm1): Bool; Far;

begin

 TF.AppWind:= 0;

 if GetWindowWord(Handle, GWW_HINSTANCE) = TF.AppInst then

   TF.AppWind:= Handle;

 result:= (TF.AppWind = 0);

end;

procedure TForm1.Button1Click(Sender: TObject);

var Text: Array[0..255] of char;

begin

 AppInst:= ShellExecute(Handle, 'open', 'notepad.exe', nil, '', SW_NORMAL);

 EnumWindows(@EnumFunc, longint(self));

 AppWind:= GetWindow(AppWind, GW_CHILD);

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

 SendKey(AppWind, 'T');

 SendKey(AppWind, 'e');

 SendKey(AppWind, 's');

 SendKey(AppWind, 't');

end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);

begin

 if AppWind <> 0 then SendKey(AppWind, Key);

end;

end.

///////////////////////////////////////////////////////////////////////

Ah,这个嘛......正好在《DELPHI新闻组学习笔记》上看到一篇:

How to send [Alt]+[Down]?--------------发出一个Alt+Down 组合键

Re:

Use the keybd_event API function to fake keyboard events. Note that each

key down event needs a matching key up or you mess up the key state array.

 keybd_event( VK_MENU, MapVirtualKey( VK_MENU, 0 ), 0 , 0 );     // Alt down

 keybd_event( VK_DOWN, MapVirtualKey( VK_DOWN, 0 ), 0 , 0 );     // down arrow key down

 keybd_event( VK_DOWN, MapVirtualKey( VK_DOWN, 0 ), KEYEVENTF_KEYUP , 0 );  // down arrow key up

 keybd_event( VK_MENU, MapVirtualKey( VK_MENU, 0 ), KEYEVENTF_KEYUP , 0 );  // Alt key up

经本人试验,确实可行,另加补充:

Ctrl: VK_CONTROL

SHIFT:VK_SHIFT

TAB:  VK_TAB

'A':  byte('A')                (98-6-8 22:28)

/////////////////////////////////////////////////////////////

(*

Converts a string of characters and key names to keyboard events and

passes them to Windows.

Example syntax:

SendKeys('abc123{left}{left}{left}def{end}456{left 6}ghi{end}789', True);

*)

Function SendKeys(SendKeysString : PChar; Wait : Boolean) : Boolean;

type

 WBytes = array[0..pred(SizeOf(Word))] of Byte;

 TSendKey = record

   Name : ShortString;

   VKey : Byte;

 end;

const

 {Array of keys that SendKeys recognizes.

 If you add to this list, you must be sure to keep it sorted alphabetically

 by Name because a binary search routine is used to scan it.}

 MaxSendKeyRecs = 41;

 SendKeyRecs : array[1..MaxSendKeyRecs] of TSendKey =

 (

  (Name:'BKSP';            VKey:VK_BACK),

  (Name:'BS';              VKey:VK_BACK),

  (Name:'BACKSPACE';       VKey:VK_BACK),

  (Name:'BREAK';           VKey:VK_CANCEL),

  (Name:'CAPSLOCK';        VKey:VK_CAPITAL),

  (Name:'CLEAR';           VKey:VK_CLEAR),

  (Name:'DEL';             VKey:VK_DELETE),

  (Name:'DELETE';          VKey:VK_DELETE),

  (Name:'DOWN';            VKey:VK_DOWN),

  (Name:'END';             VKey:VK_END),

  (Name:'ENTER';           VKey:VK_RETURN),

  (Name:'ESC';             VKey:VK_ESCAPE),

  (Name:'ESCAPE';          VKey:VK_ESCAPE),

  (Name:'F1';              VKey:VK_F1),

  (Name:'F10';             VKey:VK_F10),

  (Name:'F11';             VKey:VK_F11),

  (Name:'F12';             VKey:VK_F12),

  (Name:'F13';             VKey:VK_F13),

  (Name:'F14';             VKey:VK_F14),

  (Name:'F15';             VKey:VK_F15),

  (Name:'F16';             VKey:VK_F16),

  (Name:'F2';              VKey:VK_F2),

  (Name:'F3';              VKey:VK_F3),

  (Name:'F4';              VKey:VK_F4),

  (Name:'F5';              VKey:VK_F5),

  (Name:'F6';              VKey:VK_F6),

  (Name:'F7';              VKey:VK_F7),

  (Name:'F8';              VKey:VK_F8),

  (Name:'F9';              VKey:VK_F9),

  (Name:'HELP';            VKey:VK_HELP),

  (Name:'HOME';            VKey:VK_HOME),

  (Name:'INS';             VKey:VK_INSERT),

  (Name:'LEFT';            VKey:VK_LEFT),

  (Name:'NUMLOCK';         VKey:VK_NUMLOCK),

  (Name:'PGDN';            VKey:VK_NEXT),

  (Name:'PGUP';            VKey:VK_PRIOR),

  (Name:'PRTSC';           VKey:VK_PRINT),

  (Name:'RIGHT';           VKey:VK_RIGHT),

  (Name:'SCROLLLOCK';      VKey:VK_SCROLL),

  (Name:'TAB';             VKey:VK_TAB),

  (Name:'UP';              VKey:VK_UP)

 );

 {Extra VK constants missing from Delphi's Windows API interface}

 VK_NULL=0;

 VK_SemiColon=186;

 VK_Equal=187;

 VK_Comma=188;

 VK_Minus=189;

 VK_Period=190;

 VK_Slash=191;

 VK_BackQuote=192;

 VK_LeftBracket=219;

 VK_BackSlash=220;

 VK_RightBracket=221;

 VK_Quote=222;

 VK_Last=VK_Quote;

 ExtendedVKeys : set of byte =

 [VK_Up,

  VK_Down,

  VK_Left,

  VK_Right,

  VK_Home,

  VK_End,

  VK_Prior,  {PgUp}

  VK_Next,   {PgDn}

  VK_Insert,

  VK_Delete];

const

 INVALIDKEY = $FFFF {Unsigned -1};

 VKKEYSCANSHIFTON = $01;

 VKKEYSCANCTRLON = $02;

 VKKEYSCANALTON = $04;

 UNITNAME = 'SendKeys';

var

 UsingParens, ShiftDown, ControlDown, AltDown, FoundClose : Boolean;

 PosSpace : Byte;

 I, L : Integer;

 NumTimes, MKey : Word;

 KeyString : String[20];

procedure DisplayMessage(Message : PChar);

begin

 MessageBox(0,Message,UNITNAME,0);

end;

function BitSet(BitTable, BitMask : Byte) : Boolean;

begin

 Result:=ByteBool(BitTable and BitMask);

end;

procedure SetBit(var BitTable : Byte; BitMask : Byte);

begin

 BitTable:=BitTable or Bitmask;

end;

Procedure KeyboardEvent(VKey, ScanCode : Byte; Flags : Longint);

var

 KeyboardMsg : TMsg;

begin

 keybd_event(VKey, ScanCode, Flags,0);

 If (Wait) then While (PeekMessage(KeyboardMsg,0,WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) do begin

   TranslateMessage(KeyboardMsg);

   DispatchMessage(KeyboardMsg);

 end;

end;

Procedure SendKeyDown(VKey: Byte; NumTimes : Word; GenUpMsg : Boolean);

var

 Cnt : Word;

 ScanCode : Byte;

 NumState : Boolean;

 KeyBoardState : TKeyboardState;

begin

 If (VKey=VK_NUMLOCK) then begin

   NumState:=ByteBool(GetKeyState(VK_NUMLOCK) and 1);

   GetKeyBoardState(KeyBoardState);

   If NumState then KeyBoardState[VK_NUMLOCK]:=(KeyBoardState[VK_NUMLOCK] and not 1)

   else KeyBoardState[VK_NUMLOCK]:=(KeyBoardState[VK_NUMLOCK] or 1);

   SetKeyBoardState(KeyBoardState);

   exit;

 end;

 ScanCode:=Lo(MapVirtualKey(VKey,0));

 For Cnt:=1 to NumTimes do

   If (VKey in ExtendedVKeys)then begin

     KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY);

     If (GenUpMsg) then

       KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)

   end else begin

     KeyboardEvent(VKey, ScanCode, 0);

     If (GenUpMsg) then KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);

   end;

end;

Procedure SendKeyUp(VKey: Byte);

var

 ScanCode : Byte;

begin

 ScanCode:=Lo(MapVirtualKey(VKey,0));

 If (VKey in ExtendedVKeys)then

   KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY and KEYEVENTF_KEYUP)

 else KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);

end;

Procedure SendKey(MKey: Word; NumTimes : Word; GenDownMsg : Boolean);

begin

 If (BitSet(Hi(MKey),VKKEYSCANSHIFTON)) then SendKeyDown(VK_SHIFT,1,False);

 If (BitSet(Hi(MKey),VKKEYSCANCTRLON)) then SendKeyDown(VK_CONTROL,1,False);

 If (BitSet(Hi(MKey),VKKEYSCANALTON)) then SendKeyDown(VK_MENU,1,False);

 SendKeyDown(Lo(MKey), NumTimes, GenDownMsg);

 If (BitSet(Hi(MKey),VKKEYSCANSHIFTON)) then SendKeyUp(VK_SHIFT);

 If (BitSet(Hi(MKey),VKKEYSCANCTRLON)) then SendKeyUp(VK_CONTROL);

 If (BitSet(Hi(MKey),VKKEYSCANALTON)) then SendKeyUp(VK_MENU);

end;

{Implements a simple binary search to locate special key name strings}

Function StringToVKey(KeyString : ShortString) : Word;

var

 Found, Collided : Boolean;

 Bottom, Top, Middle : Byte;

begin

 Result:=INVALIDKEY;

 Bottom:=1;

 Top:=MaxSendKeyRecs;

 Found:=false;

 Middle:=(Bottom+Top) div 2;

 Repeat

   Collided:=((Bottom=Middle) or (Top=Middle));

   If (KeyString=SendKeyRecs[Middle].Name) then begin

      Found:=True;

      Result:=SendKeyRecs[Middle].VKey;

   end else begin

      If (KeyString>SendKeyRecs[Middle].Name) then Bottom:=Middle

      else Top:=Middle;

      Middle:=(Succ(Bottom+Top)) div 2;

   end;

 Until (Found or Collided);

 If (Result=INVALIDKEY) then DisplayMessage('Invalid Key Name');

end;

procedure PopUpShiftKeys;

begin

 If (not UsingParens) then begin

   If ShiftDown then SendKeyUp(VK_SHIFT);

   If ControlDown then SendKeyUp(VK_CONTROL);

   If AltDown then SendKeyUp(VK_MENU);

   ShiftDown:=false;

   ControlDown:=false;

   AltDown:=false;

 end;

end;

begin

 AllocationSize:=MaxInt;

 Result:=false;

 UsingParens:=false;

 ShiftDown:=false;

 ControlDown:=false;

 AltDown:=false;

 I:=0;

 L:=StrLen(SendKeysString);

 If (L>AllocationSize) then L:=AllocationSize;

 If (L=0) then Exit;

 While (IINVALIDKEY) then begin

              SendKey(MKey,1,True);

              PopUpShiftKeys;

            end else DisplayMessage('Invalid KeyName');

            Inc(I);

         end;

   end;

 end;

 Result:=true;

 PopUpShiftKeys;

end;

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

{//虚拟按键

调用方法:

SendKey(VK_ESCAPE,[]);

}

procedure SendKey(const mKey: Word; mShiftState: TShiftState;

 mCount: Integer = 1); { 模拟系统按键;mCount指定按键次数 }

const

 cExtended: set of Byte = [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_HOME,

   VK_END, VK_PRIOR, VK_NEXT, VK_INSERT, VK_DELETE];

 procedure pKeyboardEvent(mKey, mScanCode: Byte; mFlags: Longint);

 var

   vKeyboardMsg: TMsg;

 begin

   keybd_event(mKey, mScanCode, mFlags, 0);

   while PeekMessage(vKeyboardMsg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) do

   begin

     TranslateMessage(vKeyboardMsg);

     DispatchMessage(vKeyboardMsg);

   end;

 end; { pKeyboardEvent }

 procedure pSendKeyDown(mKey: Word; mGenUpMsg: Boolean);

 var

   vScanCode: Byte;

   vNumState: Boolean;

   vKeyBoardState: TKeyboardState;

 begin

   if (mKey = VK_NUMLOCK) then begin

     vNumState := ByteBool(GetKeyState(VK_NUMLOCK) and 1);

     GetKeyBoardState(vKeyBoardState);

     if vNumState then

       vKeyBoardState[VK_NUMLOCK] := (vKeyBoardState[VK_NUMLOCK] and not 1)

     else vKeyBoardState[VK_NUMLOCK] := (vKeyBoardState[VK_NUMLOCK] or 1);

     SetKeyBoardState(vKeyBoardState);

     Exit;

   end;

   vScanCode := Lo(MapVirtualKey(mKey, 0));

   if (mKey in cExtended) then begin

     pKeyboardEvent(mKey, vScanCode, KEYEVENTF_EXTENDEDKEY);

     if mGenUpMsg then

       pKeyboardEvent(mKey, vScanCode,

         KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)

   end else begin

     pKeyboardEvent(mKey, vScanCode, 0);

     if mGenUpMsg then pKeyboardEvent(mKey, vScanCode, KEYEVENTF_KEYUP);

   end;

 end; { pSendKeyDown }

 procedure pSendKeyUp(mKey: Word);

 var

   vScanCode: Byte;

 begin

   vScanCode := Lo(MapVirtualKey(mKey, 0));

   if mKey in cExtended then

     pKeyboardEvent(mKey, vScanCode, KEYEVENTF_EXTENDEDKEY and KEYEVENTF_KEYUP)

   else pKeyboardEvent(mKey, vScanCode, KEYEVENTF_KEYUP);

 end; { pSendKeyUp }

var

 I: Integer;

begin

 for I := 1 to mCount do begin

   if ssShift in mShiftState then pSendKeyDown(VK_SHIFT, False);

   if ssCtrl in mShiftState then pSendKeyDown(VK_CONTROL, False);

   if ssAlt in mShiftState then pSendKeyDown(VK_MENU, False);

   pSendKeyDown(mKey, True);

   if ssShift in mShiftState then pSendKeyUp(VK_SHIFT);

   if ssCtrl in mShiftState then pSendKeyUp(VK_CONTROL);

   if ssAlt in mShiftState then pSendKeyUp(VK_MENU);

 end;

end; { SendKey }