繁体   English   中英

使用 JNA 获取所有可见的 windows

[英]Get all visible windows with JNA

我正在 Java 中编写覆盖图,显示多个 windows 的信息。

我需要它跟随它正在跟踪的 window,为此我会定期获取有关当前 windows 的信息,以更新我的叠加层的 position。 但我还需要知道 windows 是否可见以隐藏叠加层(如果不可见)。 理想情况下,我应该能够实时完成所有这些工作,但我担心这对性能的要求太高了。

我用 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 的 User32 API 之后尝试了“IsWindowVisible”,但它没有做我想要的。

您使用User32IsWindowVisible的直觉很好。 JNA 实际上已经在其WindowUtils class 中实现了这一点。

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

boolean 参数是onlyVisibleWindows

请注意,这里的“可见”是指 window 本身的 state,而不是它是否被最小化(可能具有屏幕外或“零”坐标)或其他 windows 的“后面”与“顶部”,因此对用户。 来自IsWindowVisible文档(注意第二段):

如果指定的 window、其父级 window、其父级的父级 window 等具有WS_VISIBLE样式,则返回值为非零。 否则,返回值为零。

因为返回值指定 window 是否具有WS_VISIBLE样式,所以即使 window 被其他 windows 完全遮盖,它也可能是非零的。

为了确定 window 是部分还是完全被遮挡,您必须使用 Z 顺序评估其相对于其“前面”的所有 windows 的locAndSize矩形。 您可以逐个像素地执行此操作,也可以仅评估角点,具体取决于您希望如何处理部分模糊的 windows。

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

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

在内部,您可以在内部 class W32WindowUtils中看到实现,它使用发送到User32EnumWindows function 的回调 function:

@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 上使用上述实现并添加来自其他函数的信息以获得 window 排序。 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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM