7

我必须通过向它发送击键来控制另一个应用程序,例如CTRLSorCTRLSHIFTCCTRLF

我已经尝试了很多东西,但我无法让它工作。所以我试图在一个更简单的情况下做到这一点。

这成功发送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);

但我不知道为什么 usingSendMessage在上面的例子中不起作用。

我能想到的最好的事情就是这样,它什么也没做。

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 参数。

4

2 回答 2

7

警告:此方法取决于实现细节,如果您需要保证程序的正确性,则不应使用此方法。(另一方面,您已经走上了这条路。例如,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);

同样,Find21我的notepad.exe. Go to24

更新,根据评论:如果你需要发送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));
于 2013-04-06T17:14:39.913 回答
4

我已经使用 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;
于 2013-04-06T23:58:04.550 回答