简体   繁体   English

如何在 MacOS 上的 Java(使用 JNA)中获取所有 window 句柄的列表?

[英]How to get list of all window handles in Java (Using JNA) on MacOS?

I have been using the JNA library to get all visible window handles in Windows.我一直在使用 JNA 库来获取 Windows 中所有可见的 window 句柄。 I need to do something similar in macOS using JNA.我需要在 macOS 中使用 JNA 做类似的事情。

Here is code to get all window handles in Windows:这是获取 Windows 中所有 window 句柄的代码:

 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? macOS 中的等效代码是什么?

You'll need to map portions of the Core Graphics Framework .您需要 map 部分Core Graphics Framework You can list windows using the CGWindowListCopyWindowInfo() function.您可以使用CGWindowListCopyWindowInfo() function 列出 windows。

To load the framework you'll need to map a CoreGraphics interface extending JNA's Library class, and map the function you need:要加载框架,您需要 map 扩展 JNA Library class 的CoreGraphics接口,以及 map 您需要的 ZC1C4145264E6798

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. CFArrayRef类型已映射到 JNA 中的CoreFoundation class。 Pick the appropriate Window List Option (probably kCGWindowListOptionAll = 0).选择合适的Window 列表选项(可能kCGWindowListOptionAll = 0)。 If you already had a window number you could use relative reerences, otherwise you'll use kCGNullWindowID (0) for the second parameter.如果您已经有一个 window 编号,您可以使用相对引用,否则您将使用kCGNullWindowID (0) 作为第二个参数。 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.这将为您提供代表 windows 的CFDictionaryRef对象数组。 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.您可以迭代数组,然后使用CFDictionaryRef class 中的其他方法来探索这些字典对象:您将为键创建一个CFString 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):这应该为每个CFNumberRef编号(“句柄”等效项)提供一个 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();

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

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