我不能直接给你一个解决方案,但我弄乱了一些代码,也许可以为你指出正确的方向。
您可能知道,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() 和SendMessage() 直接向控件的 HWND 发送消息,例如向 MalwareBytes Button 类,将触发程序本身的按钮按下,非常类似于 SetForegroundWindow() 应该如何带来前面的编辑框样式控件使您能够键入。好玩的东西:)
如果您想形象化我所说的“父母”、“孩子”和“控制”的意思,您可能会发现这个程序很有帮助:Control Viewer。它可以向您显示每个控件并在应用程序窗口中突出显示它等等 - 非常有用的工具。
如果这篇文章离开了 java 提供的舒适区,很抱歉,但在如此广泛的范围内,真的没有其他方法可以实现您的目标。
我希望我至少向您展示了实现目标所需的条件,并为您指明了正确的方向。当谈到原生 Windows API 时,我不是上帝,所以我可能在某些地方错了,但是代码确实有效。祝你好运:)