如何在MacOS上获取Java中所有窗口句柄的列表(使用JNA)? [英] How to get list of all window handles in Java (Using JNA) on MacOS?

查看:396
本文介绍了如何在MacOS上获取Java中所有窗口句柄的列表(使用JNA)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用JNA库来获取Windows中所有可见的窗口句柄.我需要使用JNA在macOS中做类似的事情.

以下是获取Windows中所有窗口句柄的代码:

 public static List<HWND> findAll() {
    final List<HWND> windows = new LinkedList<>();
    User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() {
        @Override
        public boolean callback(HWND hWnd, Pointer arg) {
            if (User32.INSTANCE.IsWindowVisible(hWnd)) {
                windows.add(hWnd);
            }
            return true;
        } 
    }, null);
    return windows;
}

macOS中的等效代码是什么?

解决方案

您需要映射核心图形框架.您可以使用 CGWindowListCopyWindowInfo()函数列出窗口. /p>

要加载该框架,您需要映射一个扩展JNA Library类的CoreGraphics接口,并映射您需要的功能:

public interface CoreGraphics extends Library {
    CoreGraphics INSTANCE = Native.load("CoreGraphics", CoreGraphics.class);

    CFArrayRef CGWindowListCopyWindowInfo(int option, int relativeToWindow);
}

CFArrayRef类型已经在JNA中的窗口列表选项(可能是kCGWindowListOptionAll = 0).如果您已经有一个窗口编号,则可以使用相对误差,否则将对第二个参数使用kCGNullWindowID(0).从您的代码中调用它应该很简单:

CFArrayRef windowInfo = CoreGraphics.INSTANCE.CGWindowListCopyWindowInfo(0, 0);

这将为您提供代表窗口的CFDictionaryRef对象数组.您可以迭代数组,然后在此处中记录了必需键的列表,而可选键是此处.常量字符串与变量名匹配.

对于每个窗口编号(等效的句柄"),这应该为您提供CFNumberRef:

// Set up keys for dictionary lookup
CFStringRef kCGWindowNumber = CFStringRef.createCFString("kCGWindowNumber");
CFStringRef kCGWindowOwnerPID = CFStringRef.createCFString("kCGWindowOwnerPID");
// Note: the Quartz name is rarely used
CFStringRef kCGWindowName = CFStringRef.createCFString("kCGWindowName");
CFStringRef kCGWindowOwnerName = CFStringRef.createCFString("kCGWindowOwnerName");

// Iterate the array
int numWindows = windowInfo.getCount();
for (int i = 0; i < numWindows; i++) {
    // For each array element, get the dictionary
    Pointer result = windowInfo.getValueAtIndex(i);
    CFDictionaryRef windowRef = new CFDictionaryRef(result);

    // Now get information from the dictionary.

    // Get a pointer to the result, in this case a CFNumber
    result = windowRef.getValue(kCGWindowNumber);
    // "Cast" the pointer to the appropriate type
    CFNumberRef windowNumber = new CFNumberRef(result);
    // CoreFoundation.INSTANCE.CFNumberGetType(windowNumber)
    // --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()
    
    // Get a pointer to the result, in this case a CFNumber
    result = windowRef.getValue(kCGWindowOwnerPID);
    // "Cast" the pointer to the appropriate type
    CFNumberRef windowOwnerPID = new CFNumberRef(result);
    // CoreFoundation.INSTANCE.CFNumberGetType(windowOwnerPID)
    // --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()

    // Get a pointer to the result, in this case a CFString
    result = windowRef.getValue(kCGWindowName);
    // "Cast" the pointer to the appropriate type
    // Optional key, check for null
    String windowName = result == null ? "" : new CFStringRef(result).stringValue();

    // Get a pointer to the result, in this case a CFString
    result = windowRef.getValue(kCGWindowOwnerName);
    // "Cast" the pointer to the appropriate type
    // Optional key, check for null
    String windowOwnerName = result == null ? "" : new CFStringRef(result).stringValue();

    // ... look up other keys if needed ...
    // use ProcessHandle with the PID to get start time

    // Output or add to List, etc.
    System.out.println(windowNumber.longValue() 
        + " (" + windowOwnerName + ", pid=" 
        + windowOwnerPID.longValue()
        + "): " + windowName);
}

// CF references from "Copy" or "Create" must be released
// release the created key references
kCGWindowNumber.release();
kCGWindowOwnerPID.release();
kCGWindowName.release();
kCGWindowOwnerName.release();
// release the array
windowInfo.release();

I have been using the JNA library to get all visible window handles in Windows. I need to do something similar in macOS using JNA.

Here is code to get all window handles in Windows:

 public static List<HWND> findAll() {
    final List<HWND> windows = new LinkedList<>();
    User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() {
        @Override
        public boolean callback(HWND hWnd, Pointer arg) {
            if (User32.INSTANCE.IsWindowVisible(hWnd)) {
                windows.add(hWnd);
            }
            return true;
        } 
    }, null);
    return windows;
}

What is the equivalent code in macOS?

解决方案

You'll need to map portions of the Core Graphics Framework. You can list windows using the CGWindowListCopyWindowInfo() function.

To load the framework you'll need to map a CoreGraphics interface extending JNA's Library class, and map the function you need:

public interface CoreGraphics extends Library {
    CoreGraphics INSTANCE = Native.load("CoreGraphics", CoreGraphics.class);

    CFArrayRef CGWindowListCopyWindowInfo(int option, int relativeToWindow);
}

The CFArrayRef type is already mapped in JNA in the CoreFoundation class. Pick the appropriate Window List Option (probably kCGWindowListOptionAll = 0). If you already had a window number you could use relative reerences, otherwise you'll use kCGNullWindowID (0) for the second parameter. Calling it from your code should be simple:

CFArrayRef windowInfo = CoreGraphics.INSTANCE.CGWindowListCopyWindowInfo(0, 0);

That will give you an array of CFDictionaryRef objects representing the windows. You can iterate the array and then use further methods in the CFDictionaryRef class to explore these dictionary objects: you'll create a CFString for the keys. A list of required keys is documented here and optional keys are here. The constant strings match the variable name.

This should get you a CFNumberRef for each window number (the "handle" equivalent):

// Set up keys for dictionary lookup
CFStringRef kCGWindowNumber = CFStringRef.createCFString("kCGWindowNumber");
CFStringRef kCGWindowOwnerPID = CFStringRef.createCFString("kCGWindowOwnerPID");
// Note: the Quartz name is rarely used
CFStringRef kCGWindowName = CFStringRef.createCFString("kCGWindowName");
CFStringRef kCGWindowOwnerName = CFStringRef.createCFString("kCGWindowOwnerName");

// Iterate the array
int numWindows = windowInfo.getCount();
for (int i = 0; i < numWindows; i++) {
    // For each array element, get the dictionary
    Pointer result = windowInfo.getValueAtIndex(i);
    CFDictionaryRef windowRef = new CFDictionaryRef(result);

    // Now get information from the dictionary.

    // Get a pointer to the result, in this case a CFNumber
    result = windowRef.getValue(kCGWindowNumber);
    // "Cast" the pointer to the appropriate type
    CFNumberRef windowNumber = new CFNumberRef(result);
    // CoreFoundation.INSTANCE.CFNumberGetType(windowNumber)
    // --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()
    
    // Get a pointer to the result, in this case a CFNumber
    result = windowRef.getValue(kCGWindowOwnerPID);
    // "Cast" the pointer to the appropriate type
    CFNumberRef windowOwnerPID = new CFNumberRef(result);
    // CoreFoundation.INSTANCE.CFNumberGetType(windowOwnerPID)
    // --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()

    // Get a pointer to the result, in this case a CFString
    result = windowRef.getValue(kCGWindowName);
    // "Cast" the pointer to the appropriate type
    // Optional key, check for null
    String windowName = result == null ? "" : new CFStringRef(result).stringValue();

    // Get a pointer to the result, in this case a CFString
    result = windowRef.getValue(kCGWindowOwnerName);
    // "Cast" the pointer to the appropriate type
    // Optional key, check for null
    String windowOwnerName = result == null ? "" : new CFStringRef(result).stringValue();

    // ... look up other keys if needed ...
    // use ProcessHandle with the PID to get start time

    // Output or add to List, etc.
    System.out.println(windowNumber.longValue() 
        + " (" + windowOwnerName + ", pid=" 
        + windowOwnerPID.longValue()
        + "): " + windowName);
}

// CF references from "Copy" or "Create" must be released
// release the created key references
kCGWindowNumber.release();
kCGWindowOwnerPID.release();
kCGWindowName.release();
kCGWindowOwnerName.release();
// release the array
windowInfo.release();

这篇关于如何在MacOS上获取Java中所有窗口句柄的列表(使用JNA)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆