Получите все видимые окна с помощью JNA

Я программирую наложение на 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;
}

Вот мой код, вы можете видеть, что я попробовал «IsWindowVisible» после того, как полностью прочитал User32 API JNA, но он не делает то, что я хочу.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваша интуиция в использовании IsWindowVisible от User32 хороша. JNA фактически реализовала это в своем классе WindowUtils.

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

Булев параметр — onlyVisibleWindows.

Обратите внимание, что «видимый» здесь относится к состоянию самого окна, а не к тому, свернуто ли оно (может иметь внеэкранную или «нулевую» координату) или «позади» или «поверх» других окон и, таким образом, видимо для пользователя. пользователь. Из документации IsWindowVisible (обратите внимание на второй абзац):

Если указанное окно, его родительское окно, его родительское родительское окно и т. д. имеют стиль WS_VISIBLE, возвращаемое значение не равно нулю. В противном случае возвращаемое значение равно нулю.

Поскольку возвращаемое значение указывает, имеет ли окно стиль WS_VISIBLE, оно может быть ненулевым, даже если окно полностью закрыто другими окнами.

Чтобы определить, частично или полностью закрыто окно, вам нужно будет оценить его прямоугольник locAndSize относительно всех окон «перед» ним, используя Z-порядок. Вы можете сделать это попиксельно или просто оценить угловые точки, в зависимости от того, как вы хотите обрабатывать частично закрытые окна.

Метод JNA getAllWindows() возвращает список (отфильтрованный по видимости) JNA DesktopWindow, инкапсулирующих эти поля:

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

Внутри вы можете увидеть реализацию во внутреннем классе W32WindowUtils, который использует функцию обратного вызова, отправленную в функцию 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;
}

Я поддерживаю проект OSHI на основе JNA и реализовал эту кросс-платформу через 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;

Спасибо за ответ. На самом деле это не работает так, как я хочу. В нем говорится, что на моем компьютере открываются все окна (и даже больше, например, окно с двумя параметрами?). Я хочу знать, какие окна действительно видны, чтобы скрыть наложение, когда в этом нет необходимости. Как если бы это было частью оригинального окна

Noah Fraiture 16.01.2023 19:59

@NoahFraiture «Видимость» окна также зависит от Z-порядка и местоположения. Для любого заданного пикселя на экране вы найдете самое переднее окно (порядок Z), которое содержит пиксель в своем locAndSize. Вы можете перебирать окна по порядку спереди назад, проверяя пиксели.

Daniel Widdis 16.01.2023 20:28

Другие вопросы по теме