1

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

谢谢

4

3 回答 3

2

我不能直接给你一个解决方案,但我弄乱了一些代码,也许可以为你指明正确的方向。

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

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

话虽如此,您需要能够从 Java 调用这些函数。在正常情况下,调用这些本地方法是不可能的。但是,有一个库可以帮助您:JNA 库。JNA 代表 Java Native Access,它允许您使用我之前提到的闪亮的新功能。

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

在使用 找到相关的父窗口后EnumWindows(),调用EnumChildWindows()将为我们提供属于父窗口的所有子窗口和其他“控件”(包括潜在的编辑框)。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()通过和直接向控件的 HWND 发送消息SendMessage(),例如向 MalwareBytesButton类,将触发程序本身的按钮按下,非常类似于 SetForegroundWindow() 应该如何将编辑框样式控件置于前面,从而使您能够输入。有趣的东西玩:)

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

很抱歉,如果这篇文章离开了 java 提供的舒适区,但在如此广泛的范围内确实没有其他方法可以实现您的目标。

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

于 2012-08-02T08:08:48.660 回答
0

我的朋友,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。

于 2012-12-28T08:57:24.363 回答
-2

对于这类问题,AutoIt比 Java 更简单、更通用。

于 2012-08-02T06:10:56.227 回答