如何使用delphi 2010将虚拟密钥发送到其他应用程序?

时间:2013-08-10 15:53:38

标签: delphi delphi-2010 virtual-keyboard

我需要从我的delphi应用程序(myapp.exe)向另一个应用程序(target.exe)发送几个虚拟键(VK_RETURN)。    Eg : Send VK_RETURN twice , from myapp.exe , into target.exe

我使用的操作系统是Windows 7 64位和Windows XP。

我看过:How to send an "ENTER" key press to another application?Send Ctrl+Key to a 3rd Party Application(对我不起作用)以及之前提出的其他问题。 但我仍然感到困惑。

如何将焦点设置为目标应用程序?

如何将虚拟密钥发送到目标应用程序?

简单示例:我想将VK_RETURN两次发送到notepad.exe或calc.exe(已加载)或来自我的delphi应用程序的任何其他程序。怎么做 ?

在Delphi 2010中执行此操作的最简单方法,请...

PS: 我从http://delphi.about.com/od/adptips2004/a/bltip1104_3.htm尝试了SndKey32.pass 并得到错误: [DCC错误] SndKey32.pas(420):E2010不兼容的类型:'Char'和'AnsiChar'

  If (Length(KeyString)=1) then MKey:=vkKeyScan(KeyString[1])

1 个答案:

答案 0 :(得分:4)

如果目标应用程序不是前台窗口,则需要使用PostMessage向其窗口句柄发送击键。您可以使用FindWindow获取该窗口句柄。下面的代码将 Enter 键发送到正在运行的记事本实例中的文本区域(注意它使用额外的FindWindowEx来首先找到备忘录区域)。它在Windows 7 64上使用Delphi 2007和Delphi XE4(32位目标)进行了测试。

procedure TForm1.Button1Click(Sender: TObject);
var
  NpWnd, NpEdit: HWnd;
begin
  NpWnd := FindWindow('Notepad', nil);
  if NpWnd <> 0 then
  begin
    NpEdit := FindWindowEx(NpWnd, 0, 'Edit', nil);
    if NpEdit <> 0 then
    begin
      PostMessage(NpEdit, WM_KEYDOWN, VK_RETURN, 0);
      PostMessage(NpEdit, WM_KEYUP, VK_RETURN, 0); 
    end;
  end;
end;

要按标题(标题)查找窗口,您只需使用第二个参数FindWindow即可。这会找到一个新的记事本实例,默认的“无标题”文件打开:

NpWnd := FindWindow(nil, 'Untitled - Notepad');

请注意,这需要在窗口标题上进行完全匹配。例如,-之前或之后的额外空格将导致匹配失败并且不会检索窗口句柄。

如果有多个实例正在运行,则可以同时使用窗口类和标题。要查找加载了Readme.txt的记事本副本,您可以使用

NpWnd := FindWindow('Notepad', 'Readme.txt - Notepad');

要查找其他应用程序,您需要使用WinSpy或WinSight之类的东西来查找窗口类名称。 (还有其他一些,例如Winspector或WinDowse(两者都是用Delphi编写的)。)

您的评论提及Calculator;根据Winspector的说法,Calculator主窗口位于Windows 7上名为CalcFrame的窗口类中,数字显示的区域是Static窗口(意味着它看起来不像直接接收击键)。这些按钮简称为Button,因此您必须使用EnumChildWindows遍历它们,查找各个按钮以识别它们以获取它们的句柄。

(如何枚举子窗口是一个单独的问题;你可以通过在这里或通过谷歌搜索找到一个例子。如果你不能,发布一个新的,单独的问题,我们可以尝试给你一个答案。)

这是一个通过窗口类找到它后向Calculator发送密钥的快速示例。它没有做任何有用的事情,因为它需要一些时间来识别不同的按钮和每个响应的键(以及消息的正确组合)。此代码只是将 1 1 Numpad + 2 2 发送到计算器窗口(a快速测试显示它们已被正确接收和显示,而且这是我想要花费在整个过程中的所有时间。)

procedure TForm1.Button1Click(Sender: TObject);
var
  NpWnd: HWnd;
begin
  NpWnd := FindWindow('CalcFrame',  nil);
  if NpWnd <> 0 then
  begin
    PostMessage(NpWnd, WM_KEYDOWN, VK_NUMPAD1, 0);
    PostMessage(NpWnd, WM_KEYDOWN, VK_ADD, 0);
    PostMessage(NpWnd, WM_KEYDOWN, VK_NUMPAD2, 0);
  end;
end;