1

I would like to create an executable file that opens an application if it is not currently open, and quits the application if it is already open.

I would also like the window of the application to be hidden after it opens.

I already figured out that the terminal command osascript -e 'tell application "Finder"' -e 'set visible of process "KeyboardCleanTool" to false' -e 'end tell'

will hide an application after it is open, so this command would also need to be integrated into the executable file.

The application is called KeyboardCleanTool and is stored at /Applications/KeyboardCleanTool.app

(macOS Catalina)

2
  • You've picked a particularly awkward app to do this with. How are you going to trigger the Quit process once it's running? Just leave the script.app on the desktop & double-click it? – Tetsujin Nov 27 '19 at 12:11
  • I already figured out how to export a script to a file, which then can be double clicked on in order to activate it. – Peter Schorn Nov 27 '19 at 13:19
2

You would be best advised to either create the application from within Script Editor as an actual AppleScript app written in AppleScript; or to create an executable shell script program that is written in shell script without calling out to osascript. There's nothing wrong per se about mixing it up, and indeed there's lots of situations where it's needed or useful, but this isn't one as both scripting languages have their own dedicated mechanisms for doing what you need. I'll show you both example scripts:

AppleScript

First, I'd recommend running a quick line of AppleScript to obtain the bundle identifier of KeyboardCleanTool, which is one way to allow AppleScript to reference an application without having that application launch as a result without an explicit request for it to do so (some applications do this because their AppleScript dictionary only avails itself to be read by AppleScript if the application is running).

So, run this line, then you can dispose of it after taking a note of the result:

return the id of the application named "KeyboardCleanTool"

It'll probably be something like "com.hegenberg.KeyboardCleanTool". That's what I'll use in the script below, which you can replace with the correct bundle identifier:

property id : "com.hegenberg.KeyboardCleanTool"
property A : a reference to application id id

if A is running then return quit A
run A

There are three ways to open applications using AppleScript, each with different results:

  • activate opens the application, brings it to the foreground, and gives it focus;
  • launch opens the application and reveals the windows but doesn't bring them into the foreground, nor gives it focus. The windows will be obscured behind whatever application currently has focus, and possibly others (I don't recall fully, but the newly launched app might sit at the back of the application z-ordering);
  • run opens the application but neither shows its windows nor gives it focus. For applications that have neither a dock nor menu bar icon, you won't be given any signal that it has been opened. This is the command it sounds like you want.

Using tell application "Finder" to set visible of process "KeyboardCleanTool" to false is not a great method. Firstly, you shouldn't use Finder for controlling the GUI, which is what this is doing; use System Events, which was created specifically to take the job away from Finder because Finder can't even do its own job properly without having a melt down, let alone trying to prioritise calls to manipulate the UI.

It also requires additional permissions that I'm sure you've already granted, but is worth mentioning for other users who don't wish to do this.

Lastly, if you don't need call in outside help to do something, it's much more advantageous (quicker, more efficient, less demanding on resources) to use a means already availed to you by the core scripting commands.

To create an Application using the above script: Save the script in Script Editor, selecting the type from the drop down list in the Save dialog that is called something like "Application bundle" or "AppleScript Applet". You'll know it when you see the four options. It can be saved anywhere you like, but a sub-directory in your user applications folder would be a sensible choice, i.e. ~/Applications, or the root applications folder, /Applications if you prefer.

Shell Script, e.g. bash

Let me know if you use a shell other than bash, and I'm aware Catalina is packaged with zsh and I, myself, preferentially use Fish and recommend you check it out.

The bash script for the task at hand can be this:

pkill -i 'KeyboardCleanTool' || lsappinfo launch nofront=true async=true /Applications/KeyboardCleanTool.app

This can be saved as anything you like, and ideally in a directory that is listed in your $PATH environment variable, such as _/usr/local/bin. It will also need to be made executable. Taking the above script, here's the entire bash code that will do all this:

echo '#!/usr/bin/env bash

A="${1-KeyboardCleanTool}" # Default app name if none given
[[ -e "${fp="/Applications/$A.app"}" ]] || fp="$( locate -l 1 -i "*/$A.app" )"
pkill -i "$A" || lsappinfo launch nofront=true async=true "$fp"' > /usr/local/bin/rd; chmod +x /usr/local/bin/rd

Once that's done, you can invoke the program like this:

rd textedit           # Will run or quit TextEdit
rd keyboardcleantool  # Will run or quit KeyboardCleanTool
rd                    # (Default) Will run or quit KeyboardCleanTool

And, of course, you don't need to save the program in /usr/local/bin. Saving it in your main /Applications folder is perfectly fine. It will have an icon representing a Terminal shell, but you can treat it like any other application: double-click to run from within Finder and it will exit when it's done.

0
1

This is a fairly simple if (running) quit, else launch structure.
You'd have to leave the Script.app somewhere you can find it with the mouse, as KeyboardCleanTool will, of course, deactivate the keyboard input entirely if it is set to start cleaning mode automatically at launch.

set appName to "KeyboardCleanTool"

if application appName is running then  
    tell application id (id of application appName) to quit
    return "Quit"
else
    tell application appName  to activate
    tell application "Finder" to set visible of process appName to false
    return "Launch & hide"
end if

The returns are just for debug. You can leave them out.

4
  • Wow! That works Perfectly. I wasn't expecting such a quick response. However, is there a way to open the app hidden instantaneously rather than opening and then hiding it? Because this code causes the app to appear on the screen for a split second. I found this terminal command which open spotify hidden: " -a /Applications/Spotify.app -gj " but it doesn't work with KeyboardCleanerTool – Peter Schorn Nov 27 '19 at 13:01
  • I also found this terminal command: open -a /Applications/Spotify.app --hide but it doesn't work with KeyboardCleanTool. Also, how do you run simple terminal commands from apple script without a terminal window opening? @Tetsujin @CJK – Peter Schorn Nov 27 '19 at 13:17
  • It seems to be the way the app responds when launched. Usually you could use run or launch instead of activate but as it's designed to always float on top, that breaks the hiding altogether. I don't know a better way to do it. – Tetsujin Nov 27 '19 at 13:36
  • Ok, that'll work then. Thanks for the help Here's another question: apple.stackexchange.com/q/376180/352349 – Peter Schorn Nov 27 '19 at 13:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .