java - 如何在 MacOS 上获取 Java(使用 JNA)中所有窗口句柄的列表?
问题描述
我一直在使用 JNA 库来获取 Windows 中所有可见的窗口句柄。我需要在 macOS 中使用 JNA 做类似的事情。
这是获取 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()函数列出窗口。
要加载框架,您需要映射一个CoreGraphics
扩展 JNALibrary
类的接口,并映射您需要的函数:
public interface CoreGraphics extends Library {
CoreGraphics INSTANCE = Native.load("CoreGraphics", CoreGraphics.class);
CFArrayRef CGWindowListCopyWindowInfo(int option, int relativeToWindow);
}
该CFArrayRef
类型已映射到CoreFoundation
类中的 JNA 中。选择适当的窗口列表选项(可能kCGWindowListOptionAll
= 0)。如果您已经有一个窗口编号,您可以使用相对重新引用,否则您将使用kCGNullWindowID
(0) 作为第二个参数。从您的代码中调用它应该很简单:
CFArrayRef windowInfo = CoreGraphics.INSTANCE.CGWindowListCopyWindowInfo(0, 0);
CFDictionaryRef
这将为您提供代表窗口的对象数组。您可以迭代数组,然后使用CFDictionaryRef
类中的其他方法来探索这些字典对象:您将为CFString
键创建一个。此处记录了所需密钥的列表,此处提供了可选密钥。常量字符串与变量名匹配。
这应该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();
推荐阅读
- github-actions - 如何假设启动 GitHub Action 的用户?
- python - 如何在 scipy.io.wavfile.read 中明确定义采样率?
- docker - gitlab-runner 的 Docker 卷清理
- reactjs - 使用 craco 在运行时更改 antd 变量
- go - 如何使用切片构造嵌套结构
- android - Flutter 如何根据流事件自动弹出页面?
- flutter - Flutter - 发送电子邮件时面临邮件程序包的问题
- ruby-on-rails - 延迟作业无法将日志放入delayed_log.log
- asp.net-mvc - iisreset 后对象空引用异常消失
- swift - UICollectionViewDiffableDataSource 是否与 UICollectionViewDataSourcePrefetching 一起使用?