我必须通过发送按键来控制另一个应用程序,如 CTRL S 或 CTRL SHIFT C 或 CTRL F 。
我尝试了很多东西,但我无法让它发挥作用。所以我试图在一个更简单的情况下做到这一点。
这成功将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发送键功能的库,但只是查看代码,它似乎只是向当前应用程序或所有应用程序广播键,因为没有Handle参数。
答案 0 :(得分:5)
警告:此方法取决于实施细节,如果您需要保证程序的正确性,则不应使用此方法。(另一方面,您是已经在那条路上。例如,IIRC,在Windows 95中甚至没有Go to
对话框。)
我在我最喜欢的资源编辑器中打开了notepad.exe
,并调查了菜单栏。我注意到Save
菜单项的ID是3
。因此,以下代码在记事本中执行Save
菜单命令:
var
notepad: HWND;
begin
notepad := FindWindow('notepad', nil);
SendMessage(notepad, WM_COMMAND, 3, 0);
同样,我的Find
版本中21
为notepad.exe
。 Go to
为24
。
更新,根据评论:如果您需要发送 Ctrl + Key ,您可以使用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));
答案 1 :(得分:3)
我多年来一直在使用keybd_event。即使其他一切都失败也会一直工作,因为它将输入直接输入到键盘驱动程序和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;