如果某个应用程序处于焦点状态,请检查 Java

Check in Java if a certain application is in focus

我想知道某个应用程序是否在 Linux 中。说是GoogleChrome。为此,我写了一个 bash 在线班轮,它正确地做到了。

xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)

当此命令在终端中为运行时,它将打印终端本身的ID。为避免这种情况,运行 以下命令和 select Chrome 在三秒的时间跨度内。

sleep 3; xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)

问题是当我运行上面提到的来自Java的单行时,它似乎总是什么都不打印。这是我的代码:

String cmd = "xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)";
Process p = Runtime.getRuntime().exec(cmd);
String result = getCommandResult(p.getInputStream());

private static String getCommandResult(InputStream stream) throws IOException {

    StringBuilder sb = new StringBuilder();
    try (InputStreamReader isr = new InputStreamReader(stream);
         BufferedReader in = new BufferedReader(isr)) {

        String line;
        while ((line = in.readLine()) != null) {
            sb.append(line);
        }
    }
    return sb.toString().trim();
}

我愿意接受不同的解决方案来解决这个问题。

如果您正在使用管道重定向,那么您必须调用 shell,或者您自己将输出从一个程序重定向到另一个程序。

但是,恕我直言,您根本不需要 grep,只需:

  1. 枚举 windows 某些 class。
  2. 获取活动 window id 并检查活动 window 列表是否包含它。

示例(省略了 q&d,resource/error 处理):

private static List<String> exec(String... args) throws IOException {
    List<String> result = new ArrayList<>();
    String line;

    BufferedReader reader = new BufferedReader(
            new InputStreamReader(
                    new ProcessBuilder()
                            .command(args)
                            .start()
                            .getInputStream()));

    while ((line = reader.readLine()) != null) {
        result.add(line);
    }

    return result;
}

public static void main(String[] args) {
    try {
        Thread.sleep(3000);

        String windowId = exec("xdotool", "getactivewindow").get(0);
        System.out.println(windowId);

        List<String> windowList = exec("xdotool", "search", "--name", "--class", "google-chrome");
        System.out.println(windowList.contains(windowId));
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }

正如barti_ddu所说,由于命令中的管道,这不起作用。您可以通过使用作为参数传递的命令创建一个 sh 进程来解决此问题:

    String cmd = "xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)";
    Process p = new ProcessBuilder("sh", "-c", cmd).start();
    String result = getCommandResult(p.getInputStream());

为什么要将命令硬编码到 class 中?而是将您的命令放在 shell 脚本中并改为调用它。然后您可以灵活地更改命令而无需重新编译。

Process proc = Runtime.getRuntime().exec("./opt/scripts/myscript.sh");

... 根据您的应用程序,将 shell 脚本作为参数传递可能会更好。

private void runCommandLine(String script) {
    try {
        Process proc = Runtime.getRuntime().exec(script);
        proc.waitFor();
        int character;
        while((character = proc.getInputStream().read()) != -1)  {
            System.out.write(character);
        }
        while((character = proc.getErrorStream().read()) != -1) {
            System.err.write(character);
        }
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

编辑:

如果您的目标是弄清楚 window 当前关注的是什么,那么与其尝试通过命令行执行某些操作,不如使用 JNA(Java Native Access)图书馆有可能做到这一点。

Find out what application (window) is in focus in Java

Java Native Access (Github)