MacOS: how to run AppleScript script from a Qt app?



  • MacOS X. I want to automate an AppleScript-scriptable application, i.e. to execute applescript without using any native apps or command-line tools.

    There're some pieces of relevant code "here":http://habrahabr.ru/blogs/qt_software/104633/, but Carbon is used. And I'd like to use Cocoa



  • At least you must call the AppleScript interpreter or create an executable of your script and call it with QProcess.



  • [quote author="Volker" date="1291395979"]At least you must call the AppleScript interpreter[/quote]

    I clearly understand that :) The question is how exactly to do that? code samples would be great

    [quote author="Volker" date="1291395979"]or create an executable of your script and call it with QProcess[/quote]

    That's not desirable. Some API would be better.



  • There is no API in Qt to do that. You must include native API calls (Objective C, most probably) or call some command line tool (osascript) via QProcess.



  • Of course there's no API in Qt for that :)



  • Then I don't understand you problem. What are you trying to do?



  • I'm asking someone to point out to proper MacOS API or, ideally, some 3rd party Qt lib for that (which, most likely, doesn't exist, but nevertheless).



  • This may give you a start:

    @
    #include <QApplication>
    #include <QProcess>

    int main(int argc, char **argv)
    {
    QApplication a(argc, argv);

    QString aScript =
            "tell application \"System Events\"\n"
            "    activate\n"
            "    display dialog \"Hello world\"\n"
            "end tell\n";
    
    QString osascript = "/usr/bin/osascript";
    QStringList processArguments;
    processArguments << "-l" << "AppleScript";
    
    QProcess p;
    p.start(osascript, processArguments);
    p.write(aScript.toUtf8());
    p.closeWriteChannel();
    p.waitForFinished();
    

    }
    @



  • I've added a wiki page (http://developer.qt.nokia.com/wiki/Call_an_AppleScript_from_Qt) in the how to section for this.



  • The wiki now contains a sample how to read the output of the script.



  • Volker, great! thank you



  • You're welcome. If you have any further questions, don't hesitate to ask.



  • Well, I'm thinking about binding Qt's JavaScript to AppleScript, mixing Qt objects and AppleScript-scriptable apps. About executing AppleScript line-by-line. About accessing AppleScript's scripting runtime environment.



  • I don't know if that's possible. I doubt one can "translate" JavaScript to AppleScript in that way.



  • [quote author="Volker" date="1291404790"]I don't know if that's possible. I doubt one can "translate" JavaScript to AppleScript in that way.[/quote]

    It depends. For instance the following code

    @tell application "System Events"
    activate
    display dialog "Hello world"
    end tell;@

    obviously can be expressed in Java/ECMAScript



  • I mean if we know the object model and grammar of a scripting language, we can tell if some script valid. And subset of features that is common for both scripting languages can be supported



  • [quote author="infoctopus" date="1291468109"]I mean if we know the object model and grammar of a scripting language, we can tell if some script valid. And subset of features that is common for both scripting languages can be supported[/quote]

    From what I understood, you want to create a transformer app that kind of "translates" JavaScript to/from AppleScript. That seems to be a pretty huge task.



  • Well, I have own simplified scripting language (and simple IDE for it) that is mapped to JavaScript.
    I'm thinking about switching to JavaScript completely, i.e. IDE has to be seriously upgraded.
    And also to engane AppleScript as much as possible. For this, own scripting language can be left untouched, but mapping to AppleScript can be added. The problem is that I don't know how to control (exec line by line, debug, etc.) AppleScript execution, if it's possible at all. Most likely I have to dig apple docs



  • I don't know if thats possible with AppleScript at all. I wish you good luck for your research!



  • Volker, thank you :) I think that the task is solvable, but not sure about the amount of time/money needed for the solution, even roughly



  • Hi Volker, I've tried your solution on Mac OS X 10.9.1 using a simple AppleScript to retrieve a mail subject from Apple Mail. The script needs around 1 sec to execute with the AppleScript Editor application, but around 20-30 secs when using QProcess/osascript. Running osascript from a shell window also needs around 1 sec for the script.

    Is this a known problem with QProcess or do you have any idea where this massive delay is coming from?

    Thanks,

    Thomas



  • I have no problems running OSAScript via QProcess. It's just as snappy as the command line for me. Perhaps you should review your QProcess code? Try a simple shell command as a comparison?



  • The following code cannot succeed to open the proxy settings. but the apple script works fine in AppleScript Editor. Any advice? using Qt 5.2 and OSX10.9
    @QString aScript = "tell application "System Preferences"\nactivate\nset current pane to pane "com.apple.preference.network"\n activate\n end tell\n"
    "tell application "System Events" to tell process "System Preferences" to tell window 1 \n click button 8 \n"
    "click radio button 6 of tab group 1 of sheet 1 \n end tell";

    QString osascript = "/usr/bin/osascript";
    QStringList processArguments;
    processArguments << "-l" << "AppleScript";
    QProcess p;
    p.start(osascript, processArguments);
    p.write(aScript.toUtf8());
    p.closeWriteChannel();
    p.waitForFinished();@
    

    [quote author="Volker" date="1291398206"]This may give you a start:

    @
    #include <QApplication>
    #include <QProcess>

    int main(int argc, char **argv)
    {
    QApplication a(argc, argv);

    QString aScript =
            "tell application \"System Events\"\n"
            "    activate\n"
            "    display dialog \"Hello world\"\n"
            "end tell\n";
    
    QString osascript = "/usr/bin/osascript";
    QStringList processArguments;
    processArguments << "-l" << "AppleScript";
    
    QProcess p;
    p.start(osascript, processArguments);
    p.write(aScript.toUtf8());
    p.closeWriteChannel();
    p.waitForFinished();
    

    }
    @[/quote]



  • What does QProcess::exitStatus() give you after start()? And QProcess::errorString()?



  • QProcess::exitStatus(), 0;
    QProcess::errorString() , Unkonwn error;

    my code works imperfect ( which is system preferences->Network; but I want it to be system preferences->Network->advanced...->Proxies)

    And I find chrome does it in a different way, not applescript maybe.(you could check it out by clicking settings->show advanced settings->change proxy settings)
    because I cannot find chrome.app at System Preferences->Security&Privacy->Privacy->Accessibility(Allow the apps below to control youe computer).



  • I suggest you try debugging in the terminal, where you'd get warnings/errors right away, and work your way from there.

    As for Chrome and other browsers: I strongly believe they take their default settings from the system ones, ie. those presented in the System Preferences.


  • Lifetime Qt Champion

    Hi,

    From a look at osascript's documentation, I would say that you are not feeding it correctly. I think you should be using several -e to build your multiline script.

    Hope it helps



  • Multiline is not a problem, at least not in my case. I'm NL'ing with \n as well. I think QProcess is taking care of that part as long as it's in the argument list.


  • Lifetime Qt Champion

    Since you have an example working, can you compare what parameters you give to oascript ? There may be something like a missing "-" to tell oascript to read from stdin



  • Sure, although it seems very identical to me. I think the problem is in the script itself.

    @QStringList args;
    QProcess p;
    scriptText =
    "tell application "iTunes"\n"
    "if not (exists user playlist "%1") then\n"
    " make new user playlist with properties {name:"%1"}\n"
    "end if\n"
    "set newFile to (POSIX file "%2")\n"
    "set newTrack to (add newFile to playlist "%1")\n"
    "set comment of newTrack to "%3""
    "\n"
    "end tell";
    fileName = fileName.replace(""", "\"");
    args << "-l" << "AppleScript";
    scriptLauncherBinary = "/usr/bin/osascript";
    p.start(scriptLauncherBinary, args);
    p.write(scriptText.arg(plName).arg(fileName).arg(getComment()).toUtf8());
    p.closeWriteChannel();@



  • I mean the way how chrome opens the network setting dialog, not how it sets proxies...have a look "here":http://dougscripts.com/itunes/2013/10/os-x-10-9-applescripts-and-accessibility-control/ so if chrome uses applescript to open the proxies settings dialog, it should be in the list of "Allow the apps below to control your computer". I am very curious how chrome could skip it.
    [quote author="janfaroe" date="1390211636"]
    As for Chrome and other browsers: I strongly believe they take their default settings from the system ones, ie. those presented in the System Preferences. [/quote]



  • Yes, but why would you be interested in opening Chromes network settings, if the system settings can override it?

    Edit: Ah, because of the "allow the apps below..." setting. Sorry, not an Applescript expert.



  • because I think it is a good user experience, I wanna add a button like that in my app.



  • Thanks anyway, that's very kind of you for giving me the advice.

    [quote author="janfaroe" date="1390294144"]Yes, but why would you be interested in opening Chromes network settings, if the system settings can override it?

    Edit: Ah, because of the "allow the apps below..." setting. Sorry, not an Applescript expert.[/quote]



  • You're welcome :-)

    Well, it depends on the scope of your application. If it's necessary, then it's necessary.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.