Java搜索屏幕上的文本字段

我正在尝试创建一个程序,自动搜索屏幕上的文本字段,并在该文本字段中重复键入一个单词。 有没有可以找到文本字段的类? 或者有什么方法可以找到文本字段? 因为我知道Robot类可以键入文本,所以我只需要将光标放到文本字段并使用mousePress()和mouseRelease()方法。

谢谢

我不能直接给你一个解决方案,但我搞砸了一些代码,可能会指出你正确的方向。

您可能知道,Java在JVM中运行。 这允许它在任何操作环境中执行。 每个操作环境(windows,mac等)都有自己的系统,用于处理编辑框并将焦点设置到右侧窗口等等。 以下示例代码仅用于Windows,不符合Java语言的精神。 正如Adriaan所指出的那样,还有其他语言用于此类事情,但只有Java才有可能完成(在一定程度上)。

在Windows中,您必须了解所有活动窗口的管理方式,以及您看到的所有内容(包括编辑框)都在考虑Windows操作系统的“窗口”。 我真的不明白事情是如何运作的,所以我不能提供更多的信息。 在诸如C ++之类的本地语言中,Windows OS API提供了一些用于实现目标的function。 即, EnumWindows()EnumChildWindows()GetClassName()SetForegroundWindow() 。 您可以通过搜索MSDN文档库找到有关如何在本机语言中使用这些函数的文档。

所以说,你需要能够从Java调用这些函数。 在正常情况下,无法调用这些本机方法。 但是,有一个库可以帮助您:JNA库。 JNA代表Java Native Access,让您可以使用我之前提到的shiny的新function。

因此,要以本机语言实现目标,通常可以通过调用EnumWindows()来返回操作系统知道的所有父窗口的列表。 此列表将包含父窗口的窗口句柄 – 标题为“MSN”,“Eclipse”,“Microsoft Office”等的窗口。作为父窗口的每个窗口都有子窗口。 在这个孩子列表中,您将找到您正在寻找的“控件”: Edit控件。 现在,许多应用程序对文本框使用不同的库和非标准的东西 – 即Pidgin,我测试了一些相关代码的消息传递应用程序,每个控件都命名为“gdkWindowChild”,它并不完全告诉我们哪个控件实际上是EditBox或者否则是一个允许我们输入文字的地方。 这是你的想法的主要问题; 你不能总是确切地告诉你希望有什么样的控制,你可以输入文字。 无论如何,我们将继续:

在使用EnumWindows()找到相关的父窗口后,对EnumChildWindows()的调用将为我们提供属于Parent的所有子窗口和其他“控件”(包括潜在的编辑框)。 EnumChildWindows()为它找到的每个子窗口调用一个回调函数,因此很容易通过子窗口列表“搜索” – 使用GetClassName()来查找控件的名称 – 可能找到HWND(窗口句柄) )你想要的控制。

一旦找到编辑框的正确HWND(当然,考虑到你的问题的一般范围,这是一个困难的部分),对SetForegroundWindow(targetHWND)的简单调用应该将控件置于前面并将光标设置为一个随时可用的编辑框。

这是我编写的一些工作示例代码,可以帮助您入门。 此代码将使用EnumWindows()遍历所有活动窗口,然后在每个父窗口上调用EnumChildWindows() ,打印出它找到的所有控件。 请注意,此代码需要运行JNA库。

 import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.examples.win32.W32API.HWND; import com.sun.jna.examples.win32.W32API.LPARAM; import com.sun.jna.win32.StdCallLibrary; import com.sun.jna.win32.W32APIOptions; public class IterateChildWindows { public interface User32 extends StdCallLibrary { User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS); HWND FindWindow(String lpClassName, String lpWindowName); int GetWindowRect(HWND handle, int[] rect); int SendMessage(HWND hWnd, int msg, int wParam, byte[] lParam); HWND FindWindowEx(HWND parent, HWND child, String className, String window); boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg); boolean EnumChildWindows(HWND parent, WNDENUMPROC callback, LPARAM info); interface WNDENUMPROC extends StdCallCallback { boolean callback(HWND hWnd, Pointer arg); } int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount); long GetWindowLong(HWND hWnd, int index); boolean SetForegroundWindow(HWND in); int GetClassNameA(HWND in, byte[] lpString, int size); } public static void main(String[] args) { User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() { public boolean callback(HWND hWnd, Pointer userData) { // this will be called for each parent window found by EnumWindows(). the hWnd parameter is the HWND of the window that was found. byte[] textBuffer = new byte[512]; User32.INSTANCE.GetWindowTextA(hWnd, textBuffer, 512); String wText = Native.toString(textBuffer); System.out.println("Window found: " + wText); // now call EnumChildWindows() giving the previously found parent window as the first parameter User32.INSTANCE.EnumChildWindows(hWnd, new User32.WNDENUMPROC() { public boolean callback(HWND hWnd, Pointer userData) { // this is called for each child window that EnumChildWindows() finds - just like before with EnumWindows(). byte[] textBuffer = new byte[512]; User32.INSTANCE.GetClassNameA(hWnd, textBuffer, 512); System.out.println(" - Found sub window / control class: " + new String(textBuffer).trim()); return true; } }, null); return true; } }, null); } } 

以下是此代码提供的输出摘录:

 Window found: Pidgin - Found sub window / control class: gdkWindowChild - Found sub window / control class: gdkWindowChild - Found sub window / control class: gdkWindowChild - Found sub window / control class: gdkWindowChild Window found: Malwarebytes Anti-Malware - Found sub window / control class: Static - Found sub window / control class: Static - Found sub window / control class: Button - Found sub window / control class: Button - Found sub window / control class: Button 

通过PostMessage()SendMessage()将消息直接发送到控件的HWND,例如发送到MalwareBytes Button类,将触发程序本身的按钮按下,非常类似于SetForegroundWindow()应如何带来编辑框样式控件在前面给你打字的能力。 有趣的东西玩:)

如果您希望在我说“父母”,“孩子”和“控制”时想象我的意思,您可能会发现此程序很有用: 控制查看器 。 它可以显示每个控件并在应用程序窗口中突出显示它 – 更有用 – 非常有用的工具。

很抱歉,如果这篇文章离开了java提供的舒适区,但是在这样的一般范围内实际上没有其他方法可以实现你的目标。

我希望我至少向你展示了实现目标所需要的,并指出了正确的方向。 当涉及到原生的Windows API时,我不是上帝,所以我可能在某些地方出错,但代码确实有效。 祝好运 :)

我的朋友,Robot类可以模拟写文本。

 private static void typeOut(String s,Robot bot) { try { char [] chars = s.toCharArray(); for (char c : chars) { bot.keyPress((int)c); bot.keyRelease((int)c); } } catch (Exception e) { System.out.println(e.getMessage()); } } 

你可以使用这个方法

 Robot bot=new Robot(); typeOut("WWW.GOOGLE.COM", bot); 

如果您想以任何方式阅读文本或将文本写入浏览器的文本字段,我建议您使用selenium。

对于这类问题, AutoIt比Java更容易,更通用。