1

I'm very new to scripting and using AppleScript. I'm on MacOS 10.14. I have been messing around with it making a few scripts to automate clicking Apple and 3rd-party menu bar items.

I have the following script written that clicks a certain menu bar item, presses the down arrow key and presses the return key.

The problem is, the click seems to be creating a 5-6 second delay before the key presses can fire. I searched for a solution but only found a couple posts talking about the issue. They both said the solution is to wrap the click command in ignoring application responses and end ignoring statements, however that doesn't seem to solve the problem for me.

I also looked up the delay command and tried specifying a delay of 1 second, but that didn't work either. It just adds another second of delay to the already-existing 5-6 second delay.

The code I've got is:

tell application "System Events"
    tell process "Enjoyable"
        click (menu bar item 1 of menu bar 2)
        key code 125
        key code 36
    end tell
end tell

With the ignore statements, I've written:

tell application "System Events"
    tell process "Enjoyable"
        ignoring application responses
            click (menu bar item 1 of menu bar 2)
        end ignoring
        key code 125
        key code 36
    end tell
end tell

With the delay statement, I've written:

tell application "System Events"
    tell process "Enjoyable"
        click (menu bar item 1 of menu bar 2)
        delay 1
        key code 125
        key code 36
    end tell
end tell

What other options could I try to get rid of the delay between the click and the key presses?

6
  • Are you doing this simply as an exercise in scripting? It seems a heavy-handed way of calling a menu item. If not, what precisely is it you are trying to achieve?
    – Tetsujin
    Jun 30 '21 at 16:20
  • Well, I originally made a few other scripts just addressing the menu items directly, which for this case would be like: tell application "System Events" tell process "Enjoyable" set enjoyableMenu to (menu bar item 1 of menu bar 2) tell enjoyableMenu click tell (menu item 1 of enjoyableMenu) click end tell end tell end tell end tell Sorry! Can't get the code to format correctly. But the point is, it wouldn't work this way despite working with 1st-party Apple menu bar items it worked with. So, I found this method and it works except the annoying delay. Jun 30 '21 at 17:35
  • That doesn't really answer my question. What exactly are you trying to achieve? At the moment you're asking about how to achieve what you think is the answer… which is what's known as an XY Problem
    – Tetsujin
    Jun 30 '21 at 17:40
  • I'm trying to achieve automated toggling of the enable/disable toggle in the Enjoyable menu bar dropdown menu. Jun 30 '21 at 17:43
  • As I don't know what 'Enjoyable' is, I cant check how the menus work, but why not just use the Keyboard prefs & add a key command? No scripting required.
    – Tetsujin
    Jun 30 '21 at 17:50
2

The example AppleScript code, shown below, was tested three different ways, run in Script Editor, run as a standalone AppleScript application, and run as an Automator Service/Quick Action under macOS Mojave with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.

  • 1 Assumes necessary and appropriate setting in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.

Example AppleScript code:

ignoring application responses
    tell application "System Events" to ¬
        click menu bar item 1 of ¬
            menu bar 2 of ¬
            application process "Enjoyable"
end ignoring

delay 0.1
do shell script "killall 'System Events'"
delay 0.2

tell application "System Events"
    launch
    click menu item 1 of ¬
        menu 1 of ¬
        menu bar item 1 of ¬
        menu bar 2 of ¬
        application process "Enjoyable"
end tell

Notes:

Using Accessibility Inspector, a part of Xcode, it reveals there is no action assigned to menu bar item 1 of menu bar 2 of application process "Enjoyable" and is probably why it hangs with the original code, how you tried it.

To work around the 5 ~ 6 seconds delay using ignoring application responses I wrapped the first tell application "System Events" command with just a single task to perform, which allowed the script to proceed, and then killing the System Events application process allows the second tell application "System Events" command to perform its tasks with the minimal delay of ~1 second combined for the running of the whole script. This is of course much better than the 5 ~ 6 seconds delay without doing it in this manner.

The very small delay commands before and after the do shell script "killall 'System Events'" command are to allow time for the menu bar item to show its menu and for System Events to terminate before calling it again to click the target menu item. The value of the delay command may need to be slightly adjusted and if so do as necessary.

As previously mentioned, this worked for me without issue1, however, if for some reason the example AppleScript code, shown above, does not work for you, then here is a programatic way to click the target menu bar item on the menu bar using either the cliclick or MouseTools third-party utility.

  • I have cliclick and MouseTools located in /usr/local/bin/, so change it in the code if you have them located elsewhere.


Using: cliclick

Example AppleScript code:

tell application "System Events" to ¬
    set thePositionSizeList to ¬
        the {position, size} of ¬
            menu bar item 1 of ¬
            menu bar 2 of ¬
            application process "Enjoyable"

set xPos to ¬
    (item 1 of item 1 of thePositionSizeList) + ¬
    (item 1 of item 2 of thePositionSizeList) / 2 ¬
    as integer

set yPos to ¬
    (item 2 of item 1 of thePositionSizeList) + ¬
    (item 2 of item 2 of thePositionSizeList) / 2 ¬
    as integer

set shellCMD to {¬
    "/usr/local/bin/cliclick -r c:", ¬
    xPos, ",", yPos, " w:50 c:", ¬
    xPos, ",", (yPos + 22)} as string

do shell script shellCMD

Notes:

With cliclick one can string multiple events together and why the code ends at the do shell script shellCMD command as it clicks both the menu bar item and the menu item, especially since it's the first menu item being targeted.

cliclick is available as a precompiled binary executable, source code, and also can be installed using Homebrew.

The current precompiled binary executable release of cliclick (5.0) will not run on macOS Mojave and I used an older version I already had (Version 4.0.1, released 2018-04-10). If you cannot acquire an earlier version you can use MouseTools instead.



Using: MouseTools

Example AppleScript code:

tell application "System Events" to ¬
    set thePositionSizeList to ¬
        the {position, size} of ¬
            menu bar item 1 of ¬
            menu bar 2 of ¬
            application process "Enjoyable"

set xPos to ¬
    (item 1 of item 1 of thePositionSizeList) + ¬
    (item 1 of item 2 of thePositionSizeList) / 2 ¬
    as integer

set yPos to ¬
    (item 2 of item 1 of thePositionSizeList) + ¬
    (item 2 of item 2 of thePositionSizeList) / 2 ¬
    as integer

set shellCMD to {¬
    "/usr/local/bin/MouseTools -x ", ¬
    xPos, " -y ", yPos, " -leftClick"} as string

do shell script shellCMD

delay 0.2

tell application "System Events" to ¬
    click menu item 1 of ¬
        menu 1 of ¬
        menu bar item 1 of ¬
        menu bar 2 of ¬
        application process "Enjoyable"

Notes:

With MouseTools one can only perform one event at a time and why after clicking the menu bar item on the menu bar I just switched back to using System Events to click the target menu item, vs. calling MouseTools a second time, either within the first do shell script command or a second do shell script command possibly after a short delay.

For example, you could change the shellCMD to:

set shellCMD to {¬
    "/usr/local/bin/MouseTools -x ", ¬
    xPos, " -y ", yPos, " -leftClick;", ¬
    "/usr/local/bin/MouseTools -x ", ¬
    xPos, " -y ", (yPos + 22), " -leftClick"} as string 

Then remove everything after the do shell script command.

MouseTools is available as a precompiled binary executable and source code.



Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

4
  • 2
    Not only did you offer a working solution, you offered several working solutions. Good job dude +1
    – wch1zpink
    Jul 3 '21 at 12:53
  • Wow! What an excellent and thorough answer. Thank you so much and I sincerely apologize that it took me almost a month to respond. I got the code working with the first example. Now I'm trying to get that code to run at login. I tried putting the .scpt file in my login items, but it won't run. I tried minute of delay before the code to give everything time to load. I also tried making an Automator app and putting that in my login items, but that didn't work either, even with a confirmation pop up before running. Oh well! I might make another post about it. Thanks again so much for your help! Jul 30 '21 at 17:26
  • @SwineBurglar, RE: "Now I'm trying to get that code to run at login. I tried putting the .scpt file in my login items, but it won't run." -- Putting a .scpt file in the Login Items is not the way to go as it just opens the script up in Script Editor. You need to use an executable, i.e., an application. That said, because you never mentioned running this as a Login Items, then yes, it belongs the topic of another question. I will of course respond to it with what else will be necessary to accomplish the goal. Jul 30 '21 at 17:41
  • @user3439894 I was writing a new question but then I figured it out! I thought more about what you said, opened the Script Editor and found Export>Application and created an app, gave it the system permissions and put it in my login items. I also added key "LSUIElement" and value "true" in the Info.plist in the app to hide it from the app switcher during the delay. I now have it running at start up with no issues. Thank you again so much for your help! Should I make a post to answer that question still or is it too basic to bother with? I couldn't find the info when I searched, so maybe yes? Jul 30 '21 at 19:22

You must log in to answer this question.

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