Portable UI Applescript zum Auswählen eines beliebigen Menüpunkts durch eine beliebige Hierarchie von Untermenüs

Unten auf dieser Seite erklärt Apple, wie man UI-Scripting verwendet, um die Auswahl von Menüelementen zu automatisieren. Es gibt zwei hartcodierte Beispiele, auf die ich zurückgreife, um ein generisches Bibliotheksskript zur Verwendung in einer Reihe von Projekten zu schreiben, das jeden Menüpunkt aus jedem Menü durch jede Hierarchie von Untermenüs auswählen kann.

Die TL;DR-Version dieser Frage lautet: Wie mache ich das? 😉

Aber für ein paar Details, falls gewünscht ...


... Ich habe einige Fortschritte gemacht und mir ein paar Ansätze dafür ausgedacht, aber jeder von ihnen hat den einen oder anderen fatalen Fehler ...

Option 1.

Wenn alle Parameter Text oder Textlisten sind: zB:

on ChooseMenuItem(theApp, theMenuName, theSubMenusNamesList, theMenuItemName)

was aufgerufen werden könnte mit zB:

ChooseMenuItem("TextEdit", "Format", {"Font", "Ligatures"}, "Use Default")

dann kann ich eine Reihe von Textanalysen und -verkettungen usw. verwenden - einschließlich einer Wiederholungsschleife durch den theSubMenusNamesListParameter, um sorgfältig ein Skript in einer Zeichenfolge wie "tell menu ... click ... tell menu item ... click ... tell menu item ... click ..."usw. zu erstellen, und dann:

run script theScript in AppleScript

Voila! Und das funktioniert. Außer wenn einer dieser Parameter - insbesondere der Menüname - nicht existiert. z.B. versuchen, ein Bluetooth-Gerät über das Bluetooth-Menü Extra zu verbinden oder zu trennen. So...

Option 2.

Wenn das Menü namenlos ist, ändern wir theMenuName in theMenu und übergeben es als Referenz. z.B:

tell application "System Events" to tell process "SystemUIServer" to set theMenu to (menu bar item 1 of menu bar 1 whose description contains "bluetooth")
...
ChooseMenuItem("SystemUIServer", theMenu, {"Magic Keyboard"}, "Connect")

Beachten Sie, hier theMenuVariable und Parameter im Gegensatz zu theMenuName. Nach der Ausführung der setAnweisung theMenuist die Variable kein Text, sondern ein AppleScript-Objekt, etwa so:

menu bar item 6 of menu bar 1 of application process "SystemUIServer"

Von hier ausgehend schlägt dies auf eine von drei Arten fehl.

2a. Wenn ich versuche, ein Skript zu konstruieren, das folgendes enthält, tell theMenu ...sagt es mir, nicht überraschend, dass ... die Variable theMenu nicht definiert ist.

2b. Wenn ich theMenuaus den Anführungszeichen ziehe: "tell " & theMenu & "..."oder "tell \"" & theMenu & "\"..."es Fehler mit: Can't make «class mbri» 6 of «class mbar» 1 of «class pcap» "SystemUIServer" of application "System Events" into type Unicode text.

dh. Es kann den oben erwähnten Menüleisteneintrag 6 der Menüleiste 1 nicht in Text umwandeln (anders als in Option 1, wo ich das Menü beim Namen aufrufen könnte).

2c. Wenn ich versuche, die Tell-Anweisung von theMenu aus dem konstruierten Textskript herauszuziehen, so ist die Textvariable theScript so etwas wie tell menu item ... click ... tell menu item ... click(ohne den Anfangsbuchstaben tell menu ... click) und dann:

tell theMenu
    click
    run script theScript in AppleScript
end tell

dann sagt es mir the variable "click" is not defined. Ich glaube, es bezieht sich auf den ersten "Klick" in der Script-Variablen, die run scriptversucht, ... na ja ... zu laufen. run script...kann anscheinend keinen Kontext von dort aufnehmen, woher es aufgerufen wird, oder wenn es möglich ist, habe ich nicht herausgefunden, wie.

Möglichkeit 3

Ich habe versucht, darüber nachzudenken, wie ich tatsächliche tell menu item theSubMenuName ...Anweisungen (dh keine Textzeichenfolgen derselben, die ich dann versuche run) in die oben erwähnte repeatSchleife einfügen könnte, aber da es sich um eine Hierarchie von Tells handelt, kann ich es nicht ganz herausfinden wie das funktioniert. Vielleicht gibt es hier eine rekursive Lösung, aber mein Gehirn tut zu sehr weh, um das herauszufinden.

Abschluss

Also, ich bin ratlos ... Ich kann das nicht herausfinden, aber ich kann auch nicht glauben, dass es keinen Weg gibt, dies zu tun. Meine Neigung ist, dass es eine Möglichkeit geben muss, auf Menüleistenelement 6 von Menüleiste 1 von ... in meiner theScriptVariablen irgendwo zu verweisen ... aber wie? Oder wenn das wirklich nicht der Fall ist, dann gibt es hier eine andere ultimative Lösung?

Antworten (1)

Nachdem ich tagelang damit gerungen habe, bevor ich die obige Frage gepostet habe, sieht es so aus, als hätte ich eine Lösung gefunden - ich denke, die Frage tatsächlich im Detail zu beschreiben, um sie zu posten, hat mich zum Nachdenken gebracht.

Ich teile es zum Wohle aller anderen, die etwas Ähnliches treffen ...

Mein Kampf war mit der Idee, dass die hierarchische Natur bedeutet, die Ebene von tellfür jedes Element in zu erhöhen theSubMenusNamesList. Ich konnte nicht herausfinden, wie ich das in eine Schleife einfügen konnte, ohne dass jede Iteration der Schleife auf dieser Ebene hineinging, aber dann auf derselben Ebene wieder herauskommen musste, also nicht tiefer ging.

Hier war Option 3 von Anfang an ein Fehlschlag, was dazu führte, dass ich den Kaninchenbau hinunterging, um zu versuchen, das Skript im Text zu konstruieren, um es dann mit auszuführen run script.

Option 3 ist jedoch eigentlich die Antwort - codieren Sie es direkt, ohne zu versuchen, es in Text zu konstruieren -, aber ich musste noch etwas damit ringen, um dorthin zu gelangen.

Irgendwann wurde mir klar, dass ich das subMenu jeder Iteration in eine Variable einfügen kann, die auf menu item ... ofdie vorherige Iteration von sich selbst gesetzt ist . Das geht erfolgreich tiefer in jede Hierarchieebene hinein, ohne sich zu früh zurückzuziehen.

Wenn das natürlich keinen Sinn macht, dann ist hier der Code, den Sie natürlich gerne stehlen und anpassen können und der möglicherweise mehr Sinn macht oder auch nicht ... ;)

on chooseMenuItem(theApp, theMenu, theSubMenusNamesList, theMenuItemName)
    set theAppName to the name of theApp
    activate theApp
    tell application "System Events" to tell process theAppName
        tell theMenu to click

        repeat with theMenuName in theSubMenusNamesList
            set theMenu to menu item theMenuName of menu 1 of theMenu
            tell theMenu to click
        end repeat

        set theMenuItem to menu item theMenuItemName of menu 1 of theMenu
        tell theMenuItem to click
    end tell
end chooseMenuItem

Das funktioniert für mich - versucht mit einer Reihe von verschiedenen Optionen. Zum Beispiel: Nennen Sie es wie in der ursprünglichen Frage mit etwas wie:

ChooseMenuItem("TextEdit", "Format", {"Font", "Ligatures"}, "Use Default")

Oder ein Beispiel ohne Untermenüs, lassen Sie den dritten Parameter einfach als leere Liste:

ChooseMenuItem("TextEdit", "File", {}, "New")

Hoffe, das hilft jemandem.

Bin heute erst auf deine Frage gekommen. Wollte demonstrieren, wie das geht, aber Sie haben eine Lösung gefunden, und Sie werden viel mehr gelernt haben, wenn Sie es selbst tun, als wenn es jemand für Sie tut. Also gut gemacht. Wenn ich mich erinnere, kann ich ein paar alternative Methoden posten, die Ihren nicht allzu unähnlich sind, aber die möglicherweise schneller sind. Schauen Sie später noch einmal vorbei.
Hallo @CJK. Ja, ich habe definitiv viel gelernt, um das herauszufinden, trotz des Haarausfalls auf dem Weg. Lol. 😉 Aber... Alternativlösungen auf jeden Fall willkommen - dort auch mehr zu erfahren. Ich würde mich freuen, wenn Sie Ihre Alternativen posten würden. Danke!