delphi通过代码实现模拟按键的函数

2018-10-31

Windows API 的 keybd_event 函数,它可以产生键盘消息。实现向其他窗口模拟真实的按键动作。
例如:
{按下A键}
Edit1.SetFocus;
keybd_event(VK_SHIFT, 0, 0, 0);
keybd_event(ord('A'), 0, 0, 0);
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);

{按下左Window键然后选择“运行”}
keybd_event(VK_LWIN, 0, 0, 0);
keybd_event(ord('R'), 0, 0, 0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);


KEYBD_EVENT 的函数说明:
函数功能:该函数合成一次击键事件。系统可使用这种合成的击键事件来产生WM_KEYUP或WM_KEYDOWN消息,键盘驱动程序的中断处理程序调用keybd_event函数。在Windows NT中该函数己被使用Sendlhput来替代它。

函数原型;VOID keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,DWORD dwExtralnfo);

参数:

bVk:定义一个虚据拟键码。键码值必须在1~254之间。

bScan:定义该键的硬件扫描码。

dwFlags:定义函数操作的名个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位。

KEYEVENTF_EXETENDEDKEY:若指定该值,则扫描码前一个值为OXEO(224)的前缀字节。DEYEVENTF_KEYUP:若指定该值,该键将被释放;若未指定该值,该键交被接下。dwExtralnfo:定义与击键相关的附加的32位值。



根据这个API函数,整理一个完整的函数,方便操作:

procedure PostKey(const mKey: Word; mShiftState: TShiftState; mCount: Integer = 1);
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;

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;

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;
另外一处函数也可以实现类似功能。

Procedure PostKeyEx32( key: Word; Const shift: TShiftState; specialkey: Boolean );
Type
TShiftKeyInfo = Record
shift: Byte;
vkey : Byte;
End;

byteset = Set of 0..7;
Const
shiftkeys: Array [1..3] of TShiftKeyInfo =
((shift: Ord(ssCtrl); vkey: VK_CONTROL ),
(shift: Ord(ssShift); vkey: VK_SHIFT ),
(shift: Ord(ssAlt); vkey: VK_MENU ));
Var
flag: DWORD;
bShift: ByteSet absolute shift;
i: Integer;
Begin
for i := 1 to 3 Do
begin
if shiftkeys[i].shift in bShift Then
keybd_event( shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), 0, 0);
end;

if specialkey then
flag := KEYEVENTF_EXTENDEDKEY
else
flag := 0;

keybd_event( key, MapvirtualKey( key, 0 ), flag, 0 );
flag := flag or KEYEVENTF_KEYUP;
keybd_event( key, MapvirtualKey( key, 0 ), flag, 0 );

for i := 3 downto 1 do
begin
If shiftkeys[i].shift In bShift Then
keybd_event( shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), KEYEVENTF_KEYUP, 0);
end; { For }
End;
阅读147