我正在用Java编写一个覆盖图,显示多个窗口的信息.

我需要它跟随它正在跟踪的窗口,为了做到这一点,我定期获取当前窗口的信息来更新我的覆盖图的位置.但我也需要知道窗口是否可见,如果不是,则隐藏覆盖.理想情况下,我应该能够实时完成所有这些工作,但我担心这对性能要求太高.

我和JNA一起做了所有这些

public interface User32 extends StdCallLibrary {
    User32 INSTANCE = (User32) Native.load("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);
    HWND FindWindow(String lpClassName, String lpWindowName);
    int GetWindowRect(HWND handle, int[] rect);
    boolean IsWindowVisible(HWND handle); // always true if window exist
}

public static int[] getWindowInformation(String windowName) {

    int[] rectangle = {0,0,0,0};

    HWND hwnd = User32.INSTANCE.FindWindow(null, windowName);

    User32.INSTANCE.GetWindowRect(hwnd, rectangle);
    boolean res = User32.INSTANCE.IsWindowVisible(hwnd);
    System.out.println(windowName + " is visible ? " + res);

    return rectangle;
}

以下是我的代码,您可以看到,在完全阅读了JNA的User32API之后,我try 了"IsWindowVisible",但它没有做我想要的事情.

推荐答案

你从User32开始使用IsWindowVisible的直觉很好.JNA实际上已经在其WindowUtils类中实现了这一点.

List<DesktopWindow> windows = WindowUtils.getAllWindows(true);

布尔参数为onlyVisibleWindows.

请注意,这里的"可见"指的是窗口本身的状态,而不是它是否被最小化(可能具有屏幕外或"零"坐标)或是否在其他窗口的"后面"而不是"顶部",从而对用户可见.摘自IsWindowVisible份文件(注意第二段):

如果指定的窗口、其父窗口、其父窗口等的样式为WS_VISIBLE,则返回值为非零.否则,返回值为零.

由于返回值指定窗口是否具有WS_VISIBLE样式,因此即使该窗口完全被其他窗口遮挡,返回值也可能是非零值.

为了确定窗口是部分遮挡还是完全遮挡,您必须使用Z顺序计算相对于其前面的所有窗口的locAndSize个矩形.您可以逐个像素地执行此操作,或者仅计算角点,具体取决于您希望如何处理部分遮挡的窗口.

JNA getAllWindows()方法返回封装以下字段的JNA DesktopWindow列表(按可见性过滤):

private HWND hwnd;
private String title;
private String filePath;
private Rectangle locAndSize;

在内部,您可以在内部类W32WindowUtils中看到the implementation,它使用一个发送到User32EnumWindows函数的回调函数:

@Override
public List<DesktopWindow> getAllWindows(final boolean onlyVisibleWindows) {
    final List<DesktopWindow> result = new LinkedList<DesktopWindow>();

    final WNDENUMPROC lpEnumFunc = new WNDENUMPROC() {
        @Override
        public boolean callback(final HWND hwnd, final Pointer arg1) {
            try {
                final boolean visible = !onlyVisibleWindows
                    || User32.INSTANCE.IsWindowVisible(hwnd);
                if (visible) {
                    final String title = getWindowTitle(hwnd);
                    final String filePath = getProcessFilePath(hwnd);
                    final Rectangle locAndSize = getWindowLocationAndSize(hwnd);
                    result.add(new DesktopWindow(hwnd, title, filePath,
                                                 locAndSize));
                }
            } catch (final Exception e) {
                // FIXME properly handle whatever error is raised
                e.printStackTrace();
            }

            return true;
        }
    };

    if (!User32.INSTANCE.EnumWindows(lpEnumFunc, null))
        throw new Win32Exception(Kernel32.INSTANCE.GetLastError());

    return result;
}

我维护了基于JNA的OSHI项目,并通过new SystemInfo().getOperatingSystem().getDesktopWindows()实现了这个跨平台,它在Windows上使用上面的实现,并添加来自其他函数的信息来获得窗口排序.Oshi的返回列表包括这些字段,并且在order中已对返回列表进行了排序,以帮助您确定用户可见性:

private final long windowId;
private final String title;
private final String command;
private final Rectangle locAndSize;
private final long owningProcessId;
private final int order;
private final boolean visible;

Java相关问答推荐

为什么我们仍然需要实现noArgsConstructor如果Java默认提供一个非参数化的构造函数?''

取消按钮,但没有任何操作方法引发和异常

流迭代列表<;对象>;上的NoSuchElementException

Java记录的不同序列化/反序列化

存根基类的受保护方法

名称冲突具有相同的擦除

如何创建一个2d自上而下的移动系统,其中移动,同时持有两个关键是可能的处理?

在AVL树的Remove方法中使用NoSuchElementException时遇到问题

Bean定义不是从Spring ApplationConext.xml文件加载的

Java-动态绑定-问题-了解

SonarLint:只能有条件地调用方法(S)

如何在列表(链表)中插入一个新 node (作为prelast)

何时调用密封层次 struct 的switch 中的默认情况

如何设计包含已知和未知键值对映射的Java类?

使用@ExceptionHandler的GlobalExceptionHandler还是来自服务器的REST应答的ResponseEntity?

Java System.getProperty在哪里检索user.home?

在数组中查找素数时出现逻辑错误

在JSON上获取反斜杠

如何在java中从以百分比表示的经过时间和结束日期中找到开始日期

将在 Docker 中运行的 Spring Boot 连接到在 Docker 中运行的 PostgreSQL,无需 compose 文件?