Delphi 使用WinAPI向另一个应用程序发送击键
我必须通过向另一个应用程序发送按键来控制它,如CTRL、CTRLSHIFTC或CTRLF 我试过很多东西,但都没法用。所以我试图在一个更简单的案例中正确处理这个问题 这将成功地将Delphi 使用WinAPI向另一个应用程序发送击键,delphi,winapi,delphi-7,sendmessage,postmessage,Delphi,Winapi,Delphi 7,Sendmessage,Postmessage,我必须通过向另一个应用程序发送按键来控制它,如CTRL、CTRLSHIFTC或CTRLF 我试过很多东西,但都没法用。所以我试图在一个更简单的案例中正确处理这个问题 这将成功地将Hey发送到记事本: procedure TForm1.Button1Click(Sender: TObject); var notepad, edit: HWND; begin notepad := FindWindow('notepad', nil); edit := FindWindowEx(notep
Hey
发送到记事本:
procedure TForm1.Button1Click(Sender: TObject);
var notepad, edit: HWND;
begin
notepad := FindWindow('notepad', nil);
edit := FindWindowEx(notepad, FindWindow('Edit', nil), nil, nil);
SendMessage(edit, WM_CHAR, dword('H'), 0);
SendMessage(edit, WM_CHAR, dword('e'), 0);
SendMessage(edit, WM_CHAR, dword('y'), 0);
end;
这将成功地将F5键发送到记事本,并且F3弹出“查找”对话框
notepad := FindWindow('notepad', nil);
PostMessage(notepad, WM_KEYDOWN, VK_F5, 0);
PostMessage(notepad, WM_KEYUP, VK_F5, 0);
但是我不知道为什么在上面的例子中使用SendMessage
不起作用
我能想到的最好的东西就是这样的东西,它什么也没用
notepad := FindWindow('notepad', nil);
PostMessage(notepad, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(notepad, WM_KEYDOWN, VkKeyScan('F'), 0);
PostMessage(notepad, WM_KEYUP, VkKeyScan('F'), 0);
PostMessage(notepad, WM_KEYUP, VK_CONTROL, 0);
我在这里的某个地方发现了一个类似VBScript发送键函数的库,但只要查看代码,它似乎只是向当前应用程序或所有应用程序广播键,因为没有句柄参数。警告:此方法取决于实现细节,如果需要保证程序的正确性,则不应使用。(另一方面,您已经走上了这条道路。例如,IIRC,在Windows 95中甚至没有“转到”对话框。)
我在我最喜欢的资源编辑器中打开了notepad.exe
,并查看了菜单栏。我注意到Save
菜单项的ID是3
。因此,以下代码在记事本中执行Save
菜单命令:
var
notepad: HWND;
begin
notepad := FindWindow('notepad', nil);
SendMessage(notepad, WM_COMMAND, 3, 0);
类似地,Find
在我的notepad.exe版本中是21
<代码>转到
is24
更新,根据注释:如果需要发送Ctrl+键,可以使用SendInput
:
var
notepad: HWND;
inputArray: array[0..3] of TInput;
begin
notepad := FindWindow('notepad', nil);
// TODO: Either exit if notepad isn't focused, or set focus to notepad
FillChar(inputArray, length(inputArray) * sizeof(TInput), 0);
inputArray[0].Itype := INPUT_KEYBOARD;
inputArray[0].ki.wVk := VK_LCONTROL;
inputArray[1].Itype := INPUT_KEYBOARD;
inputArray[1].ki.wVk := VkKeyScan('S');
inputArray[2].Itype := INPUT_KEYBOARD;
inputArray[2].ki.wVk := VkKeyScan('S');
inputArray[2].ki.dwFlags := KEYEVENTF_KEYUP;
inputArray[3].Itype := INPUT_KEYBOARD;
inputArray[3].ki.wVk := VK_LCONTROL;
inputArray[3].ki.dwFlags := KEYEVENTF_KEYUP;
SendInput(length(inputArray), inputArray[0], sizeof(TInput));
我已经使用keybd_事件很多年了。即使其他一切都失败了,它也会一直工作,因为它直接将输入输入到键盘驱动程序和Windows之间的接口中。手动键入和使用下面的函数生成键之间没有什么区别。唯一的缺点是目标窗口必须始终保持在前景中
procedure SendKey(Wnd,VK : Cardinal; Ctrl,Alt,Shift : Boolean);
var
MC,MA,MS : Boolean;
begin
// Try to bring target window to foreground
ShowWindow(Wnd,SW_SHOW);
SetForegroundWindow(Wnd);
// Get current state of modifier keys
MC:=Hi(GetAsyncKeyState(VK_CONTROL))>127;
MA:=Hi(GetAsyncKeyState(VK_MENU))>127;
MS:=Hi(GetAsyncKeyState(VK_SHIFT))>127;
// Press modifier keys if necessary (unless already pressed by real user)
if Ctrl<>MC then keybd_event(VK_CONTROL,0,Byte(MC)*KEYEVENTF_KEYUP,0);
if Alt<>MA then keybd_event(VK_MENU,0,Byte(MA)*KEYEVENTF_KEYUP,0);
if Shift<>MS then keybd_event(VK_SHIFT,0,Byte(MS)*KEYEVENTF_KEYUP,0);
// Press key
keybd_event(VK,0,0,0);
keybd_event(VK,0,KEYEVENTF_KEYUP,0);
// Release modifier keys if necessary
if Ctrl<>MC then keybd_event(VK_CONTROL,0,Byte(Ctrl)*KEYEVENTF_KEYUP,0);
if Alt<>MA then keybd_event(VK_MENU,0,Byte(Alt)*KEYEVENTF_KEYUP,0);
if Shift<>MS then keybd_event(VK_SHIFT,0,Byte(Shift)*KEYEVENTF_KEYUP,0);
end;
procedure SendKey(Wnd,VK:Cardinal;Ctrl,Alt,Shift:Boolean);
变量
MC,MA,MS:布尔型;
开始
//尝试将目标窗口置于前景
展示窗口(西北、西南展示);
SetforeGroundindow(西尼罗河);
//获取修改器关键点的当前状态
MC:=Hi(GetAsyncKeyState(VK_控制))>127;
MA:=Hi(GetAsyncKeyState(VK_菜单))>127;
MS:=Hi(GetAsyncKeyState(VK_SHIFT))>127;
//如有必要,按修改键(除非真实用户已按下)
如果为CtrlMC,则为keybd_事件(VK_控件,0,字节(MC)*KEYEVENTF_KEYUP,0);
如果为AltMA,则为keybd_事件(VK_菜单,0,字节(MA)*KEYEVENTF_键向上,0);
如果是ShiftMS,则为keybd_事件(VK_移位,0,字节(毫秒)*KEYEVENTF_KEYUP,0);
//按键
keybd_事件(VK,0,0,0);
keybd_事件(VK,0,KEYEVENTF_KEYUP,0);
//如有必要,释放修改器键
如果为CtrlMC,则为keybd_事件(VK_控件,0,字节(Ctrl)*KEYEVENTF_KEYUP,0);
如果为AltMA,则为keybd_事件(VK_菜单,0,字节(Alt)*KEYEVENTF_键向上,0);
如果为ShiftMS,则为keybd_事件(VK_移位,0,字节(移位)*KEYEVENTF_键向上,0);
结束;
这非常有用,但对我不起作用,因为我需要在一个没有标准windows组件的游戏中自动执行任务,所以我可能找不到任何命令ID,我只需将消息发送到顶部的窗口句柄,唯一可靠的方法是击键总是一样的。有“旧”吗不支持绝对的Delphi版本?我认为这是从伯兰·帕斯卡那里继承来的。@AndriyM:我的理解是,它是在德尔福2009年引入的,但显然是大卫在这一点上。我想我错了。我可以看出你已经删除了关于绝对值的部分,所以这只是为了确认。Delphi 6和Delphi 2006是我最近积极使用的两个版本,它们都支持它,我确信这与我在Borland/Turbo Pascal中经常使用的absolute
相同。所以,是的,你可以相信所有的Delphi版本都有absolute
。@Ken:是的,这就是我想要的。它可能会失败。当另一个进程插入交错的键盘事件时,它将失败。这就是SendInput存在的原因。我不知道你为什么认为keybd_事件比SendInput好。游戏可能并不总是响应SendMessage(),所以需要一个较低级别的函数。我假设SendInput是基于SendMessage()的高级函数。我被纠正了。