![](/img/trans.png)
[英]How to get list of all window handles in Java (Using JNA) on MacOS?
[英]How to get foreground window/process in Java (Using JNA) on MacOS?
目前,我正在努力在 MS Windows 中获取前景(顶部)窗口/进程。我需要使用 JNA 在 macOS 中做类似的事情。
macOS 中的等效代码是什么?
byte[] windowText = new byte[512];
PointerType hwnd = User32.INSTANCE.GetForegroundWindow();
User32.INSTANCE.GetWindowTextA(hwnd, windowText, 512);
System.out.println(Native.toString(windowText));
这里其实有两个问题,前台window和前台进程。 我会尽力回答这两个问题。
对于前台进程,使用 JNA 的一种简单方法是 map 应用程序服务API。请注意,这些功能是在 10.9 中引入的,现在已弃用,但从 10.15 开始仍然有效。 较新的版本在AppKit
库中,见下文。
创建这个 class,映射您需要的两个函数:
public interface ApplicationServices extends Library {
ApplicationServices INSTANCE = Native.load("ApplicationServices", ApplicationServices.class);
int GetFrontProcess(LongByReference processSerialNumber);
int GetProcessPID(LongByReference processSerialNumber, IntByReference pid);
}
“前台”进程可以通过GetFrontProcess()
获得。 这会返回一个称为ProcessSerialNumber
的东西,这是一个在整个应用程序服务 API 中使用的唯一 64 位值。要将其转换为您的用户空间使用,您可能需要进程 ID,而GetProcessPID()
会为您进行转换。
LongByReference psn = new LongByReference();
IntByReference pid = new IntByReference();
ApplicationServices.INSTANCE.GetFrontProcess(psn);
ApplicationServices.INSTANCE.GetProcessPID(psn, pid);
System.out.println("Front process pid: " + pid.getValue());
虽然上面的方法有效,但它已被弃用。 一个新的应用程序应该使用AppKit
库:
public interface AppKit extends Library {
AppKit INSTANCE = Native.load("AppKit", AppKit.class);
}
关于使用此库的最顶层应用程序,还有多个其他 StackOverflow 问题,例如这个。 映射所有需要的导入和对象比我在这里的答案中有时间做的工作要多得多,但您可能会发现它很有用。 弄清楚如何使用Rococoa 框架(它在后台使用 JNA 但已经通过 JNAerator 映射了所有 AppKit)来访问这个 API 可能更容易。 这里有一些 javadoc 。
还有使用AppleScript
的解决方案,您可以使用Runtime.exec()
通过命令行从 Java 执行并捕获 output。
关于屏幕上的前景window ,它有点复杂。 在我对您之前关于在 macOS 上迭代所有 windows 的问题的回答中,我回答了如何通过 JNA 使用CoreGraphics
获取所有 windows 的列表,包括包含更多信息的CFDictionary
。
其中一个字典键是kCGWindowLayer
,它将返回一个代表CFNumber
层号的 CFNumber。 文档 state 这是 32 位的,因此intValue()
是合适的。 该数字是“绘图顺序”,因此较高的数字将覆盖较低的数字。 因此,您可以遍历所有检索到的 windows 并找到最大数量。 这将是“前景”层。
有一些注意事项:
CGRect
的kCGWindowBounds
键(具有 4 个双精度、X、Y、宽度的结构,高度)。 您需要过滤到屏幕上的 windows。如果您已经获取列表,您可以使用kCGWindowIsOnscreen
键来确定 window 是否可见。 它返回一个CFBoolean
。 由于该密钥是可选的,因此您需要测试null
。 但是,如果您是从零开始,最好在最初调用CGWindowListCopyWindowInfo()
时使用kCGWindowListOptionOnScreenOnly
Window 选项常量。
除了迭代所有windows 之外, CGWindowListCopyWindowInfo()
function 还采用CGWindowID
参数relativeToWindow
并且您可以将(按位或) kCGWindowListOptionOnScreenAboveWindow
添加到选项中。
最后,您可能会发现限制为与当前 session 关联的 windows 可能很有用,您应该使用与CGWindowListCreate()
CopyInfo()
。 它返回一个包含 window 个数字的数组,您可以将字典搜索限制为该数组,或者将该数组作为参数传递给CGWindowListCreateDescriptionFromArray()
。
正如我在之前的回答中提到的,您“拥有”使用Create
或Copy
函数创建的每个 object,并负责在使用完成后释放它们,以避免 memory 泄漏。
AppleScriptEngine appleEngine = new apple.applescript.AppleScriptEngine();
ArrayList<String> processNames = null;
try {
String processName = null;
processNames = (ArrayList<String>) appleEngine
.eval("tell application \"System Events\" to get name of application processes whose frontmost is true and visible is true");
if (processNames.size() > 0) {
processName = processNames.get(0);// the front most process name
}
return processName;
} catch (ScriptException e) {
log.debug("no app running");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.