作者: 陸島工作室
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;