No internet connection
  1. Home
  2. Support

MacOS 15.4 broken sheets navigate to path

By Forrester Savell @Forrester_Savell
    2025-04-10 02:15:42.284Z

    Title

    MacOS 15.4 broken sheets navigate to path

    What do you expect to happen when you run the script/macro?

    Loads I/O settings

    Are you seeing an error?

    Element was not found - line 39

    Script fails to open the 'go' sheet using sf.keyboard.type({ text:'/')}

    What happens when you run this script?

    Script fails to open the 'go' sheet using sf.keyboard.type({ text:'/')}

    How were you running this script?

    I clicked the "Run Script" or "Run Macro" button in SoundFlow

    How important is this issue to you?

    5

    Details

    {
        "inputExpected": "Loads I/O settings",
        "inputIsError": true,
        "inputError": "Element was not found - line 39 \n\nScript fails to open the 'go' sheet using sf.keyboard.type({ text:'/')}",
        "inputWhatHappens": "Script fails to open the 'go' sheet using sf.keyboard.type({ text:'/')}",
        "inputHowRun": {
            "key": "-MpfwYA4I6GGlXgvp5j1",
            "title": "I clicked the \"Run Script\" or \"Run Macro\" button in SoundFlow"
        },
        "inputImportance": 5,
        "inputTitle": "MacOS 15.4 broken sheets navigate to path"
    }

    Source

    const ioSettingsFolder = "~/Documents/Pro Tools/IO Settings/";
    
    
    function importBusSettings(presetName) {
    
        //Activate Pro Tools Window
        sf.ui.proTools.appActivateMainWindow();
    
        //Open I/O Window
        sf.ui.proTools.menuClick({
            menuPath: ["Setup", "I/O..."],
        });
    
        const ioWin = sf.ui.proTools.windows.whoseTitle.is('I/O Setup').first;
    
        //Select "Bus" Tab
        ioWin.radioButtons.whoseTitle.startsWith('Bus').first.elementClick();
    
        //Wait for Tab ("Active Busses" text is unique to the bus tab)
        ioWin.children.whoseRole.is("AXStaticText").whoseValue.is('Active Busses:').first.elementWaitFor();
    
        //Click 'Import Settings...'
        ioWin.buttons.whoseTitle.is('Import Settings...').first.elementClick();
    
        const openWin = sf.ui.proTools.windows.whoseTitle.is('Open').first;
        //const openWinLocation = sf.ui.proTools.windows.whoseTitle.is("Open").first.popupButtons.whoseTitle.is("Where:").first
    
        //Wait for 'Open' window
        openWin.elementWaitFor()
        //openWinLocation.elementWaitFor()
    
        //Wait Again
        //sf.wait({intervalMs: 200})
    
        //Open 'go' sheet
        sf.keyboard.type({ text: '/' });
    
        //Wait for Open window
        openWin.sheets.first.elementWaitFor();
    
        const sheet = openWin.sheets.first;
    
        if (sheet.comboBoxes.first.exists) {
            //Set preset name
            sheet.comboBoxes.first.value.value = presetName;
            //Click "Go"
            sheet.buttons.whoseTitle.is('Go').first.elementClick();
    
        } else {
            //Set presetPath
            sheet.textFields.first.value.value = `${ioSettingsFolder}${presetName}`;
            sf.keyboard.press({ keys: 'return' });
        }
    
        sheet.elementWaitFor({ waitType: "Disappear" });
    
        const openBtn = openWin.buttons.whoseTitle.is("Open").first;
    
        let tryCount = 0;
        while (!openBtn.isEnabled || tryCount >= 10) {
            sf.wait({ intervalMs: 20 });
            tryCount++
        }
    
        //Click Open
        openWin.buttons.whoseTitle.is("Open").first.elementClick();
    
        //Wait for Dialog window
        sf.ui.proTools.confirmationDialog.elementWaitFor();
    
        //Delete unused buses prompt
        sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('No').first.elementClick();
    
        //Click OK
        ioWin.buttons.whoseTitle.is('OK').first.elementClick();
    }
    
    importBusSettings("Keys Gates.pio");
    
    
    
    

    Links

    User UID: sKu19XXNXHYSdEMmZtHz8CozbdS2

    Feedback Key: sffeedback:sKu19XXNXHYSdEMmZtHz8CozbdS2:-ONSTon7HvPpspVFkmNK

    Feedback ZIP: 9cI0LArKCpC9VBHSfENZMOoxoD11g9yh+I5KuAkuZGiB5fn2/t+8U2lQl2GPfmBJ7eLx+U3uVSgO1BPRyoKNf/dWdyadRr8qfwPYP3S4F3oVvn/CsuALjwBQ52LlZxcsQpVvY6vRzt8alwFe665XGYPeOG67K2u9PSz1sxfnHl+rjkb5cKdBIsIZd/fBL3xnnNaUZRCmDYRdwffnw3Ih5jh9RItLNc4I5KBeAok8URni9zlS/3gQqNDH00PYDW8bZA3McMegMizg9imPDS/eqsNSYCCKZL8Vkf2SrSYmD4tk2XGdQK9OLoKjaRxLHPSvMXprAym8tXJsAXR3mH8IzZVeUAuBCXbEn+SXY4GLOJ0=

    Linked from:

    1. M4 with Sequoia?
    • 9 replies
    1. F
      Forrester Savell @Forrester_Savell
        2025-04-10 02:21:01.205Z

        This is easily fixed with sf.wait({intervalMs: 200}) before calling the 'go' window.

        However, I'm intrigued as to what element is not focused and needs to be waited for before 'slash' is pressed to open 'Go' window. I thought it might be the .popupButtons.whoseTitle.is("Where:") but that's not it.

        1. Kitch Membery @Kitch2025-04-10 17:50:29.048Z

          Hi @Forrester_Savell

          In this case, I believe the failure is occurring because the script has to wait for the OS to complete the animation of the dialog opening. Therefore, a manual wait might be necessary here.

          1. FForrester Savell @Forrester_Savell
              2025-04-13 21:47:18.726Z

              Hey @Kitch

              I'm seeing some variation in the wait time necessary for the Go sheet to work across different scripts/sessions. Is this something that would likely be addressed in a Soundflow update relevant to changes in MacOS15.4, so that the openWin.elementWaitFor() specifically waits for the animation to complete before moving on?

              1. Kitch Membery @Kitch2025-04-14 17:10:02.540Z

                Thanks @Forrester_Savell,

                When I have a moment, I'll have to dig deeper to see if there's a way to identify when the Go sheet appears.

          2. S
            SoundFlow Bot @soundflowbot
              2025-04-14 17:10:20.406Z

              This issue is now tracked internally by SoundFlow as SF-1699

              1. F
                Forrester Savell @Forrester_Savell
                  2025-08-04 08:19:57.782Z

                  Hey @Kitch have you had any luck with this?

                  I'm still getting issues trying to handle the process of navigating to a folder, specifically waiting for the "Go" sheet, that works across a range of sessions.

                  Using a sf.wait({intervalMS:1000}) works 90% of the time, but with the odd session that is large and slow, it will fail due to the arbitrary wait.

                  I've tried all manner of callbacks and waitFor's but nothing seems to work.

                  // Open "Go to" sheet
                      sf.waitFor({
                          callback: () => {
                              sf.keyboard.press({ keys: 'slash' });
                              return openWin.sheets.first.exists;
                          },
                          pollingInterval: 100,
                          timeout: 2000
                      });
                  

                  @raphaelsepulveda , when I use your callback method, I find it enters an unwanted '/' in the textfield about 50% time, I presume due to some sort of lag in the callback process. Have you experienced that?

                  1. @Forrester_Savell, ah yes. I didn't notice this in the context of the full script where this is taken from, since it immediately replaces the text with the desired file path.

                    It just needs a slight tweak to avoid that extra slash:

                    // Open "Go to" sheet
                    sf.waitFor({
                        callback: () => {
                            if (openWin.sheets.first.exists) return true;
                            sf.keyboard.press({ keys: 'slash' });
                        },
                        pollingInterval: 100,
                        timeout: 2000
                    });
                    
                    1. FForrester Savell @Forrester_Savell
                        2025-08-05 04:58:12.876Z

                        Thanks as always @raphaelsepulveda !

                        I have another learning question. I was stumbling on waiting for an overwrite confirmation dialog during file exporting. Initially I was using

                        sf.waitFor({
                                        timeout: 2000,
                                        pollingInterval: 100,
                                        callback: () => {
                                            sf.ui.proTools.confirmationButtonDialog.buttons.whoseTitle.is("Yes").first.exists;
                                            // I also tried checking for the window
                                            //sf.ui.proTools.confirmationButtonDialog.children.whoseRole.is("AXStaticText").whoseValue.contains("already exists.  Do you want to replace it?").first;
                                        },
                                    });
                        

                        However the above code doesn't work.

                        It wasn't until I added the if statement. and return, like your example above, that it worked.

                        sf.waitFor({
                                        callback: () => {
                                            if (sf.ui.proTools.confirmationButtonDialog.buttons.whoseTitle.is("Yes").first) return true;
                                        },
                                        pollingInterval: 100,
                                        timeout: 2000
                                    });
                        

                        So I'm confused as to why the first example doesn't work, when I can see many uses of callbacks that don't use the if/return. eg. I/O Setup New Path name field interaction broken with PT2024.10 #post-11

                        Is it the nature of the element its checking or?

                        1. @Forrester_Savell, it's due to the different ways a value can be returned in an arrow function.

                          In your first example, since you're using brackets in the arrow function, then you need to add return in order to return a value, like so:

                          sf.waitFor({
                              timeout: 2000,
                              pollingInterval: 100,
                              callback: () => {
                                  return sf.ui.proTools.confirmationButtonDialog.buttons.whoseTitle.is("Yes").first.exists;
                              },
                          });
                          

                          If the brackets are omitted then return is not necessary as anything you put after the arrow will be returned. This is what is happening in the callback examples you've seen:

                          sf.waitFor({
                              timeout: 2000,
                              pollingInterval: 100,
                              callback: () => sf.ui.proTools.confirmationButtonDialog.buttons.whoseTitle.is("Yes").first.exists,
                          });
                          

                          Hope that clears up things a bit!