DekGenius.com
[ Team LiB ] Previous Section Next Section

22.2 GUI Scripting Examples

This section describes a couple of examples of GUI scripting from my own life.

Our first example will be to toggle File Sharing on or off. This is something I need to do quite often, and System Preferences isn't sufficiently scriptable to automate it. I have to open System Preferences, go the right pane, and press all the right buttons, every time; this, as they say, gets old real fast. But AppleScript can automate it for me, thanks to GUI scripting.

System Preferences is sufficiently scriptable to get us to the Sharing pane, so let's consider that problem solved. To write our script, then, the first step is to open the Sharing pane manually and explore it in terms of its UI element objects.

For example, we're initially interested in the Personal File Sharing row of the scrolling list in the Services tab. UI Element Inspector describes it this way:

<AXApplication: "System Preferences">
 <AXWindow: "Sharing">
  <AXTabGroup>
   <AXScrollArea>
    <AXTable>
     <AXRow>
      <AXTextField>

Attributes:
   AXRole:  "AXTextField"
   AXRoleDescription:  "text field"
   AXHelp:  "(null)"
   AXValue (W):  "Personal File Sharing"
   AXEnabled:  "1"
   AXFocused:  "0"
   AXParent:  "<AXRow>"
   AXWindow:  "<AXWindow: "Sharing">"
   AXPosition:  "x=228 y=341"
   AXSize:  "w=195 h=18"
   AXSelectedText:  "(null)"
   AXSelectedTextRange:  "(null)"

Actions:
   AXConfirm - AXConfirm

PreFab UI Browser displays the element hierarchy more graphically, using AppleScript terminology; Figure 22-1 shows the result.

Figure 22-1. UI Browser describes a window
figs/as_2201.gif

The procedure of exploration continues in just the same way, examining each interface item to which we might wish to send a message; I'll spare you the remaining details.

Once we know enough about the target window, we proceed to develop the actual script. This is generally quite straightforward because the repertory of actual commands is very small; you are pretending to be a mouse and a keyboard, after all, so the main things you can do are click and type. Here's the script:

tell application "System Preferences"
        activate
        set current pane to pane "com.apple.preferences.sharing"
end tell
tell application "System Events"
        tell application process "System Preferences"
                tell tab group 1 of window "Sharing"
                        click radio button "Services"
                        select row 1 of table 1 of scroll area 1
                        click button 1
                end tell
        end tell
end tell

Let's sum up what happens in that example. First we open System Preferences and bring it to the front; then we open the Sharing pane. So much for System Preferences' own scriptability.

Now the Accessibility API takes over. Notice the structure of what follows: we target System Events, and within the targeting of System Events we target the desired application process. That's crucial. We target System Events because that's the locus of the terminology and the functionality for driving the Accessibility API. We speak of an application process, rather than an application, because we need to specify the application with actually targeting it! You can see that I also like to include a tell block specifying common UI elements, simply as a way of reducing the chain of ofs.

The rest is just a matter of doing programmatically what we would do in real life with the mouse. We click the Sharing tab (called a "radio button" in the dictionary) to make sure we're in the correct tab view, select the first row of the scrolling list, and click the button at the right. This might be captioned Start or Stop; that's why we refer to it by index rather than by name.

The next example has to do with Mailsmith. I've got Mailsmith set up to leave large mail messages on the server, so that they don't take up time and bandwidth when I'm checking my mail. If a large message is of interest, I later download it and delete it from the server. Unfortunately, there is no single menu item that lets me do this; I must manually choose a menu item to download the large message, wait until it has arrived, and then manually choose another menu item to delete it from the server. Since this is a frequent sequence of actions, I'd like to reduce it to a script. But although Mailsmith is pretty heavily scriptable, the developers neglected to define events for these actions. GUI scripting provides the solution:

tell application "Mailsmith" to activate
tell application "System Events"
        tell application process "Mailsmith"
                tell menu "Message" of menu bar 1
                        click menu item "Get from Server"
                        tell application "Mailsmith"
                                delay 5
                                repeat until not connection in progress
                                        delay 2
                                end repeat
                        end tell
                        click menu item "Remove from Server"
                end tell
        end tell
end tell

Observe the mixture of GUI scripting with normal scripting in that example. GUI scripting is used to choose the relevant menu items, but in between, normal scripting is used to wait until the connection with the server has had time to open and close, implying that the download is complete.

It should be noted, in closing, that GUI scripting is not a panacea. It doesn't work everywhere: a particular interface item, a window, or an entire application might not use the standard interface elements. In that case, the Accessibility API can do nothing for you. Also, even though it's a lot of fun, GUI scripting should be considered a workaround; real scriptability is always better. If you're reduced to using GUI scripting to accomplish some goal, and if the target application is still being actively developed, then consider writing to the developer and requesting that the application be made genuinely scriptable.

    [ Team LiB ] Previous Section Next Section