我正在尝试创建一个程序,该程序可以自动在屏幕上搜索文本字段,然后在该文本字段中重复输入一个单词。有没有可以找到文本字段的类?还是可以找到文本字段的任何方式?因为我知道Robot类可以键入文本,所以我只需要将光标移到文本字段上并使用mousePress()和mouseRelease()方法即可。
谢谢
我无法直接为您提供解决方案,但是我弄乱了一些代码,也许可以为您指明正确的方向。
您可能知道,Java在JVM中运行。这使其可以在任何操作环境中执行。每种操作环境(Windows,Mac等)都有其自己的系统,用于处理编辑框并将焦点设置在右侧窗口等。以下示例代码仅设计用于Windows,不符合Java语言的精神。正如Adriaan指出的那样,这类事情还有其他语言,但仅在Java上(有可能)就可以做到。
在Windows中,您必须了解如何管理所有活动窗口,以及所看到的所有内容(包括编辑框)都在考虑Windows OS的“窗口”。我并不真正了解事物的幕后运作方式,因此我无法提供更多信息。在诸如C ++之类的本地语言中,Windows OS API提供了一些功能,这些功能可用于实现您的目标。即,EnumWindows(),EnumChildWindows(),GetClassName(),和SetForegroundWindow()。您可以通过搜索MSDN文档库找到有关如何在本机语言中使用这些功能的文档。
EnumWindows()
EnumChildWindows()
GetClassName()
SetForegroundWindow()
因此,您需要能够从Java调用这些函数。通常情况下,无法调用这些本机方法。但是,有一个库可以帮助您:JNA库。JNA代表Java Native Access,它使您可以使用前面提到的闪亮的新功能。
因此,为了以母语实现您的目标,通常会从调用EnumWindows()返回操作系统知道的所有父窗口列表开始。此列表将包含父窗口的窗口句柄-名为“ MSN”,“ Eclipse”,“ Microsoft Office”等的窗口。作为父级,这些窗口中的每个都有子级。在此子级列表中,您会找到所需的“控件”:Edit控制。现在,许多应用程序对文本框使用不同的库和非标准的东西- 即Pidgin,我用其测试了一些相关代码的消息传递应用程序,具有每个名为“ gdkWindowChild”的控件,它不能确切告诉我们哪个控件实际上是EditBox或否则是一个允许我们输入文本的地方。那是你想法的主要问题;您无法始终准确地说出您希望将焦点放在哪个控件上,以便您可以输入文本。无论如何,我们将继续:
Edit
在找到相关的“父”窗口之后EnumWindows(),调用EnumChildWindows()将给我们所有属于父级的子窗口和其他“控件”(包括潜在的编辑框)。EnumChildWindows()为找到的每个子窗口调用一个回调函数,因此很容易在子窗口列表中“搜索”-使用GetClassName()查找控件的名称- 潜在地找到所需控件的HWND(窗口句柄) 。
找到正确的编辑框HWND后(当然,这是问题的总体范围,这是最困难的部分),只需简单调用SetForegroundWindow(targetHWND)即可将控件置于最前面,并将光标置于准备就绪状态。类型的编辑框。
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()和直接将消息发送到HWND控件SendMessage(),例如,发送到MalwareBytes Button类,将触发程序本身的按钮按下,这与SetForegroundWindow()将编辑框样式控件置于最前面的方式非常相似,从而使您能够输入。有趣的东西玩:)
PostMessage()
SendMessage()
Button
如果您想形象地表达我在说“父母”,“孩子”和“控制”时的意思,则该程序会有所帮助:Control Viewer。它可以显示每个控件,并在应用程序窗口以及其他功能中突出显示它-非常有用的工具。
抱歉,如果该帖子离开了Java提供的舒适区域,但在这样的一般范围内,实际上没有其他方法可以实现您的目标。
我希望至少已向您展示了实现目标所需的条件,并为您指明了正确的方向。对于本机Windows API来说,我不是上帝,所以在某些地方我可能是错的,但是代码确实可以工作。祝好运 :)