2

How can I set the focus (e.g. cmd+tab) of an arbitrary application (Java or not) from a Java program, on OSX?

Looking for an answer to this question, I came across this question, but it doesn't really help for OSX.

EDIT: one possibiltiy seems to be to use something like Quicksilver, and a Robot to send it keypresses with modifiers. I'd prefer something more portable, though, that requires less setup to make changes after it's compiled....

Community
  • 1
  • 1
ericsoco
  • 24,913
  • 29
  • 97
  • 127
  • Can you explain what you mean "the focus of an application"? Do you mean you want to make another application frontmost, or you want to set the keyboard focus to a particular text field that happens to be in another application, or what? – Chuck Feb 13 '13 at 17:56
  • no need to focus in a specific textfield (as described by the poster of the other question i linked to); just focus as with cmd+tab. – ericsoco Feb 13 '13 at 18:01
  • 1
    `Runtime.exec("open /path/to/Whichever.app")` should reactivate the app if it's running already. It will however also start an app if it's not. – millimoose Feb 13 '13 at 18:19
  • @millimoose -- beautiful. please post this as an answer and i'll accept it. – ericsoco Feb 13 '13 at 18:25

3 Answers3

4

You should be able to reactivate an already running app using the open command that comes with OS X:

Runtime.exec("open /path/to/Whichever.app");

(Or some equivalent overload of that function.) This will also open an app if it's not running yet.

millimoose
  • 39,073
  • 9
  • 82
  • 134
  • wish you would have answered 43 mins ago. – ericsoco Feb 13 '13 at 18:31
  • 2
    if there are any spaces in the app filename, Runtime.exec will break it apart into separate arguments. using `Runtime.exec(String[])` fixes this: `String[] cmd = { "open", appPath };` `Runtime.getRuntime().exec(cmd);` – ericsoco Feb 13 '13 at 22:20
  • @ericsoco Yup, that's why I mentioned "equivalent overload". I assumed familiarity with the quirks of `Runtime.exec()`. – millimoose Feb 13 '13 at 22:22
  • That answer should have so many upvotes, 9 years later and still helping :) – Morph21 Apr 12 '22 at 06:11
2

You can use the javax.script API to run AppleScripts. So you can write a script along the lines of "tell application "WhateverApp" to activate", filling in your arbitrary application for WhateverApp, and it should do what you want.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • interesting. a little googling turned up a mailing list thread with some info on passing a param to an applescript: http://lists.apple.com/archives/java-dev/2008/Aug/msg00094.html – ericsoco Feb 13 '13 at 18:10
  • @ericsoco: You shouldn't need to pass a parameter for this particular task. Since you construct your AppleScript program as a string, just build it with the application name already in place. – Chuck Feb 13 '13 at 18:13
  • sorry, i should have clarified -- my java application will need to switch between multiple applications. will edit my question. – ericsoco Feb 13 '13 at 18:23
  • @ericsoco: I'm saying you could simply construct a string for each application with the application name in the appropriate place. E.g. `String program = "Tell application \"" + appName + "\" to activate"`. I mean, whatever works for you, obviously. That just seemed like the simplest solution to me if passing parameters is difficult. – Chuck Feb 13 '13 at 18:32
2

Chuck's answer tipped me off to osascript, so I decided to give it a shot straight from the command line. Managed to get it working with Runtime.exec(), osascript, and AppleScript.

Java launches an AppleScript and passes it the application name, using osascript from the command line, via Runtime.exec():

try {
    List<String> shellCommandList = new ArrayList<String>();
    shellCommandList.add("osascript");
    shellCommandList.add("activateApplication.scpt");
    shellCommandList.add(appName);

    String[] shellCommand = (String[])shellCommandList.toArray(new String[0]);
    Process p = Runtime.getRuntime().exec(shellCommand);

    // if desired, pipe out the script's output
    BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String cmdOutStr = "";
    while ((cmdOutStr = in.readLine()) != null) {
        System.out.println(cmdOutStr);
    }

    // if desired, check the script's exit value
    int exitValue = p.waitFor();
    if (exitValue != 0) {
        // TODO: error dialog
        System.err.println("Invalid application name: "+ appName);
    }
} catch (Exception e) {
    e.printStackTrace();
}

And the AppleScript uses a run handler to capture the incoming argument:

on run (arguments)
    set appName to (item 1 of arguments)
    tell application appName to activate
    return 0
end run
ericsoco
  • 24,913
  • 29
  • 97
  • 127