0

I'm starting with the disclaimer that this is my first time posting, so if I breach etiquette, I promise it's by accident; just let me know.

I'm trying to make an AppleScript to change the sound output on my Mac with a voice command (I hurt my arms recently and have been programming automations and tying them to dictation). And while I've been able to make a lot of things work, I've had trouble with this one.

The really frustrating thing is, I can, technically, get it to work. I have made the script as follows:

tell application "System Preferences"
    reveal anchor "output" of pane id "com.apple.preference.sound"
end tell

tell application "System Events" to tell process "System Preferences"
    tell table 1 of scroll area 1 of tab group 1 of window 1
        select (row 1 where value of text field 1 is "Andrea Comm USB-SA Headset")
    end tell
end tell

quit application "System Preferences"

I can run this, and it will change my sound output to my headset. The problem is that once that's done, I can't change it to anything else until I do it manually. I literally duplicated the script and replace the name of the headset with "headphones", but when I run it, it says it can't get tab one of group 1. I even made a completely identical copy, one that also switches the output to the headset, and had the same exact problem.

But, if I go and manually reset the output, I can run this same script to change to the headphones, and it will work. Then it's the other script that won't work until I've manually changed the output again.

I've looked all over, and I cannot find a solution to this problem. No one else seems to have this issue, but I've had it across multiple scripts. And while I'm normally all about being my own special little snowflake, in this case it's not helping me any.

Any help you can provide would be great. Thanks so much!

  • I wrote this a while ago - apple.stackexchange.com/a/218223/85275 - it works on line numbers rather than names – Tetsujin May 8 at 6:33
  • Ahh, it was based on a solution to a similar problem... repeat until exists tab group 1 of window "Sound" is the key, I think apple.stackexchange.com/questions/209352/… – Tetsujin May 8 at 6:37
  • I apologize for taking so long to respond -- Life Happened :P But this is great! Thanks very much! It's a bit odd that I would have to check to see if something exists, but whatever gets the job done, right? I really appreciate it :) – Simon McEntire May 15 at 4:43
1

While the other answer does in fact work for me on my system running macOS High Sierra nonetheless, I have to post a KISS principle answer.

Simply add the following code to your existing code:

repeat until exists tab group 1 of window "Sound"
    delay 0.1
end repeat

So your code will now look like:

tell application "System Preferences"
    reveal anchor "output" of pane id "com.apple.preference.sound"
end tell

tell application "System Events" to tell process "System Preferences"
    repeat until exists tab group 1 of window "Sound"
        delay 0.1
    end repeat
    tell table 1 of scroll area 1 of tab group 1 of window 1
        select (row 1 where value of text field 1 is "Andrea Comm USB-SA Headset")
    end tell
end tell

quit application "System Preferences"

There most definitely is a level of sophistication to the other answer; however, I'd imagine it may be a bit difficult to understand for those who are new to AppleScript and why a KISS principle answer is being provided.

0

I tested your script on my systen (System info: AppleScript version: 2.7 System version: 10.13.6), and it worked perfectly. My only thought is an echo of @tetsujin's suggestion about building in sufficient checks to ensure UI elements exists before trying to do things with them.

It could be that your system is taking longer to load the System Preferences window and its contents and therefore the script proceeds to execute the subsequent lines of code prematurely, thus resulting in a "can't get tab group 1" error.

However, this doesn't satisfactorily explain why this happens on alternate runs of your script, which is very odd sounding.

I redrafted your script and used my personal, standardised format that I use with all of these System Preference UI AppleScripts. It has built in checks to prevent the script from proceeding unless the UI element in question is confirmed to exist (it gives up waiting after a short period, and terminates the script returning false, whereas any successful run of the script returns true).

use Prefs : application "System Preferences"
use sys : application "System Events"

property pane : a reference to pane id "com.apple.preference.sound"
property anchor : a reference to anchor "output" of my pane

property process : a reference to application process "System Preferences"
property window : a reference to window "Sound" of my process
property tab group : a reference to tab group 1 of my window
property scroll area : a reference to scroll area 1 of my tab group
property table : a reference to table 1 of my scroll area
property row : a reference to row 1 in my table

property Headphones : a reference to (my row where the value of ¬
    text field 1 = "Headphones")
property Headset : a reference to (my row where the value of ¬
    text field 1 contains "Andrea Comm")

on zzz(x, |ξ| as boolean)
    local x, |ξ|

    repeat 20 times -- 20 x 0.2s = 4s max. wait
        if |ξ| = (x exists) then return true
        delay 0.2
    end repeat

    false
end zzz

on quit e as boolean
    continue quit Prefs
    return e
end quit

--① quit 1
--② if zzz(my process, no) = false then return quit 0

reveal my anchor
if zzz(my row, yes) = false then return quit 0

select Headset --OR: Headphones
--③ quit 1

There are three lines commented out, which I've numbered. These can remain commented out during testing of the script, which will ensure the System Preferences window stays visible (once you've brought it into the foreground manually), so you can physically see whether the output device is being selected or not. If the script appears to run properly, you can remove the comment marks and bring those three lines back into play, which will allow System Preferences to remain hidden, out-of-sight during a normal run of the script, quitting System Preferences at the end.

The penultimate line is the one where you will edit the name of the device to be selected—either Headphones or Headset (no quotation marks), both of which are declared as properties at the start of the script and already house the appropriate references to their respective device's UI element.

  • Don't get me wrong, I love level of sophistication your answer provides, but it's obvious the OP is new to AppleScript and why I had to post a KISS principle answer. While both answers work for us nonetheless, not at all sure what is causing the other issue (having to manually select after the fact... ) mentioned in the OP. – user3439894 May 8 at 14:33
  • Thanks so much for your help! This is a bit above my current level of comprehension, but I've copied it down -- I maintain a running archive of things that I've found that I don't understand which I periodically return to. It's a great feeling when I can go back to one and actually parse my way through it (so to speak). Thanks so much! – Simon McEntire May 15 at 4:45

You must log in to answer this question.

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