gpt4 book ai didi

java - 找出 Java 中的焦点应用程序(窗口)

转载 作者:IT老高 更新时间:2023-10-28 20:32:18 30 4
gpt4 key购买 nike

我想知道如何编写一个知道哪个 Windows 应用程序处于焦点位置的 Java 程序。我可以打开许多窗口,但我想知道正在使用的窗口(比如我现在正在输入的谷歌浏览器)。

我不需要更改窗口或应用程序中的任何内容,只需要知道它的名称即可。

最佳答案

正如其他人已经指出的那样,没有可移植的方法可以在所有平台上获得它。但更糟糕的是:在 MS Windows 上甚至没有一致的方法。我将提供一些代码来解决不同平台的问题并指出限制。使用风险自负,由于安全原因,代码可能会提供错误的结果或根本无法运行。如果它在您的机器上运行,并不意味着它会在其他机器上同样好地运行。

代码使用 JNA。在我的实验中,我遇到了不同版本的 JNA 和 JNA 平台库的问题。最好自己编译,这样你就有了一致的环境。

窗口

kichik 提供的答案在当时是正确的,但并非在所有情况下都适用于 Windows 8。问题是,它不能正确处理 Metro 应用程序。不幸的是,目前没有稳定的 API 来获取当前运行的 Metro 应用程序的名称。我在代码中插入了一些提示,但最好等到 Microsoft 为您提供 API。

在 Windows 上,特权应用程序和 UAC 对话框也会出现问题。所以你不会总是得到正确的答案。

public interface Psapi extends StdCallLibrary {
Psapi INSTANCE = (Psapi) Native.loadLibrary("Psapi", Psapi.class);

WinDef.DWORD GetModuleBaseNameW(Pointer hProcess, Pointer hModule, byte[] lpBaseName, int nSize);
}
if (Platform.isWindows()) {
final int PROCESS_VM_READ=0x0010;
final int PROCESS_QUERY_INFORMATION=0x0400;
final User32 user32 = User32.INSTANCE;
final Kernel32 kernel32=Kernel32.INSTANCE;
final Psapi psapi = Psapi.INSTANCE;
WinDef.HWND windowHandle=user32.GetForegroundWindow();
IntByReference pid= new IntByReference();
user32.GetWindowThreadProcessId(windowHandle, pid);
WinNT.HANDLE processHandle=kernel32.OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, true, pid.getValue());

byte[] filename = new byte[512];
Psapi.INSTANCE.GetModuleBaseNameW(processHandle.getPointer(), Pointer.NULL, filename, filename.length);
String name=new String(filename);
System.out.println(name);
if (name.endsWith("wwahost.exe")) { // Metro App
// There is no stable API to get the current Metro app
// But you can guestimate the name form the current directory of the process
// To query this, see:
// http://stackoverflow.com/questions/16110936/read-other-process-current-directory-in-c-sharp
}

Linux/Unix/X11

对于 X11,我们有三个问题:

  1. 由于网络透明性,来自完全不同机器的多个窗口可能会混合在同一个 X11 中。因此,在您查询的机器上,属于窗口的进程的名称和 PID 都可能没有意义。
  2. 大多数 Windows 管理器都有多个桌面。在每个桌面上,前台可以有不同的应用程序
  3. 平铺窗口管理器(如 XMonad )没有前景窗口的概念。它们以某种方式排列所有窗口,因此每个窗口同时位于前台。

在 X11 上,查询当前具有焦点的窗口更有意义。

public interface XLib extends StdCallLibrary {
XLib INSTANCE = (XLib) Native.loadLibrary("XLib", Psapi.class);

int XGetInputFocus(X11.Display display, X11.Window focus_return, Pointer revert_to_return);
}

if(Platform.isLinux()) { // Possibly most of the Unix systems will work here too, e.g. FreeBSD
final X11 x11 = X11.INSTANCE;
final XLib xlib= XLib.INSTANCE;
X11.Display display = x11.XOpenDisplay(null);
X11.Window window=new X11.Window();
xlib.XGetInputFocus(display, window,Pointer.NULL);
X11.XTextProperty name=new X11.XTextProperty();
x11.XGetWMName(display, window, name);
System.out.println(name.toString());
}

Mac OS X

Mac OS X 不关注窗口,而是关注应用程序。因此,询问当前 Activity 的应用程序是有意义的。旧版本的 Mac OS X 提供多个桌面。较新的版本可以同时打开多个全屏应用程序。所以你可能并不总是得到正确的答案。

    if(Platform.isMac()) {
final String script="tell application \"System Events\"\n" +
"\tname of application processes whose frontmost is tru\n" +
"end";
ScriptEngine appleScript=new ScriptEngineManager().getEngineByName("AppleScript");
String result=(String)appleScript.eval(script);
System.out.println(result);
}

结论

当我使用这段代码时,它在最基本的情况下都有效。但是,如果您希望此代码可靠运行,则必须进行大量润色。自己决定是否值得。

为了使代码完整,这里是我使用的导入部分:

    import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.platform.unix.X11;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

当然,您必须重新排列代码的各个部分。我在开头使用了一个带有接口(interface)的大类 a,然后在一个大的 main 方法中使用了其余的类。

关于java - 找出 Java 中的焦点应用程序(窗口),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5206633/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com