Revised September 2009
Like AppleScript, F-Script can communicate with scriptable application, making it possible to automate processes using these applications and to create workflows spanning multiple applications. This system-wide scripting capability relies on a standard Mac OS X technology called the Scripting Bridge:
Scripting Bridge is a framework and a technology that makes it much easier for Cocoa developers to control and communicate with scriptable applications. [...] The Scripting Bridge framework makes it possible to send and receive Apple events using Objective-C messages instead of AppleScript commands or Apple-event descriptors. For Cocoa programmers, Scripting Bridge provides a simple and clear model for controlling scriptable applications. It makes Cocoa programs that send and receive Apple events more efficient, and it doesn't require you to have detailed knowledge of the target application's Apple event model. Scripting Bridge integrates well with existing Objective-C code and works with standard Cocoa designs, such as key-value coding, target-action, and declared properties.
Basically, the scripting bridge allows manipulating scriptable applications as if they were Cocoa objects, automatically taking care of the communication details (e.g. creating and sending Apple Events). This allows using F-Script to manipulate other applications through their standard scripting interface.
Note: for a refresher about AppleScript, Apple Events and so on, one very good read, providing a unique historical perspective, is AppleScript, written by William R. Cook for the HOPL III conference.
iTunes := SBApplication applicationWithBundleIdentifier:'com.apple.iTunes'
The applicationWithBundleIdentifier: method automatically introspects the scripting interface of the target application, dynamically creates the classes and methods needed to interact with it and returns an object that represents the application. This is the object we then use to start manipulating the application from F-Script. In the example below, we assign it to a variable named "iTunes". This object will automaticaly take care of communicating with the application when needed.
Now that we have a connection to an application, we can interact with it from F-Script. For example, let's ask iTunes for the name of the current track:
iTunes currentTrack name
If there is no current track, an error is returned by the scripting bridge and displayed by F-Script. Otherwise, the name of the current track is returned.
Now, ask iTunes to go to the next track:
iTunes nextTrack
Connect to the Finder and query it for the names of the files on the desktop:
Finder := SBApplication applicationWithBundleIdentifier:'com.apple.finder'.
Finder desktop files name
Display these file names in the array inspector:
Finder desktop files name inspect
Ask the Finder for the names of the files on the desktop which have been modified today:
files := Finder desktop files.
files name where:files modificationDate >= 'today' asDate
As you see, we can make use of F-Script's array programming model as usual.
In the following example, we ask the Finder for the number of files in the Applications folder on the startup disk:
(Finder startupDisk folders objectWithName:'Applications') files count
In the following example, we connect to Mail and ask for the subjects of the messages that are currently in our inbox and to which we have already replied:
Mail := SBApplication applicationWithBundleIdentifier:'com.apple.mail'.
Mail inbox messages subject where:Mail inbox messages wasRepliedTo
The following script is based on a example in the Scripting Bridge Programming Guide for Cocoa. It plays the currently selected iTunes track (if the application is running) and then modulates the volume of the sound, eventually restoring it to the original level.
iTunes := SBApplication applicationWithBundleIdentifier:'com.apple.iTunes'.
iTunes isRunning ifTrue:
[
|rampVolume originalVolume|
originalVolume := iTunes soundVolume.
iTunes setSoundVolume:0; pause; playpause.
rampVolume := 0.
[rampVolume < originalVolume] whileTrue:
[
iTunes setSoundVolume:rampVolume.
"Pause 1/10th of a second between adjustments"
NSThread sleepUntilDate:(NSDate dateWithTimeIntervalSinceNow:0.1).
rampVolume := rampVolume + (originalVolume / 32).
].
iTunes setSoundVolume:originalVolume.
]
The following script is also based on a example in the Scripting Bridge Programming Guide for Cocoa. It copies the textual content of each selected Mail message to a TextEdit document.
TextEdit := SBApplication applicationWithBundleIdentifier:'com.apple.TextEdit'.
Mail := SBApplication applicationWithBundleIdentifier:'com.apple.Mail'.
Mail messageViewers do:[:viewer|
viewer selectedMessages do:[:message|
doc := (TextEdit classForScriptingClass:'document') alloc init.
TextEdit documents addObject:doc.
doc setText:message content get.
]
]
Each application has its own specific scripting interface. The F-Script object browser comes in handy for exploring and experimenting with the available methods for a particular application. If we have already established a connection with an application, we can open the object browser programmatically, passing it the object representing the application, as in the following example:
sys browse:iTunes
Alternatively, we can establish the connection right from the object browser itself, by following these steps:
SBApplication class. This displays the class methods of SBApplication.applicationWithBundleIdentifier: method and provide the required argument (i.e., a string containing the identifier of the application you want to connect to); for example, enter 'com.apple.iTunes'.We can then use the object browser to explore and experiment with the scripting interface of the application.
As shown in the screenshot, the browser displays the methods of the Cocoa object automatically created by the Scripting Bridge to represent the iTunes application. To invoke a particular method, all we have to do is to click on it (the browser will asks for arguments if needed). Once the method returns, the result is displayed in a new column in the browser and we can further manipulate it. The object browser provides a lot of features to help exploring and navigating objects. You'll find a detailed tutorial in Exploring Cocoa with F-Script.
To get more information about the scripting interface of an application, we can generate an Objective-C interface file (that is, a .h file) that describes the application scripting interface. This is done by using together the sdef (scripting definition extractor) and sdp (scripting definition processor) commands provided by Mac OS X . We first use sdef to asks an application for its scripting definition, and we then pass this definition to sdp to produce an Objectice-C interface file. For example, to get a detailed description of how iTunes can be controlled with the Scripting Bridge, we can execute the following command in a UNIX shell:
sdef /Applications/iTunes.app | sdp -fh --basename "iTunes"
This will create a file named iTunes.h. Here is a short extract of this file, as displayed by Xcode:
The sdp command might not work well with some applications. In such cases, looking at the output of sdef can still provide useful information about an application interface.
Combining information we get using sdef and sdp with interactive exprimentation, we can learn how to control an application from F-Script (as well as from Objective-C) and hopefully write cool scripts.
Happy scripting!
Copyright © 2009 Philippe Mougin