Keyboard Maestro and UI scripting
November 6, 2014 at 10:22 PM by Dr. Drang
Update 11/6/14
I’m not sure how long the Presets popup has been in the Print sheet, but I suspect was there before I returned to the Mac in 2004. For some reason, I never paid any attention to it, but the response I’ve gotten to this post in the 20 minutes it’s been up has certainly changed that. Virtually everything in this post could be done by setting the options I want and saving them as a preset.
Oh, well. The techniques in the AppleScript are still useful for other situations.
Keyboard Maestro generally does a good job of simulating user interaction, but sometimes it’s better to drop down into AppleScript to get things done. A good example is a macro I’ve been using for a while to speed the printing of my expense reports.
I’ve written before about the Numbers template I use for my expense reports. I use Numbers because:
- I can use the same template on the Mac in my office and on my iPhone while I’m on the road.
- It lets me include scanned receipts in the same document as the spreadsheet.
- For billable expenses, I can turn it into a PDF and attach it to the invoice I send to the client.
Despite the nice ability to generate PDFs, I still print out paper expense reports to submit to our bookkeeper for reimbursement. We’re a small company with a heterogeneous computing environment, and paper is the path of least resistance. I do like to save paper, though, so I paste the scanned receipts onto the second page and print double-sided. And because my expense reports are in landscape mode, I like using short-edge binding.
The click-click-click of changing the default print settings to what I want bothered me enough that I built a Keyboard Maestro macro so I could change the settings and print with one keystroke: ⌃⌥⌘P.
Here’s the macro, which you can download:
I invoke the macro when I’m in the preview mode that Numbers shows when you choose
in the normal mode.I start from here because I like to make sure I’ve sized and arranged the receipts to fit on the second page, if possible. When I type ⌃⌥/⌘P, the macro performs three steps:
- It selects again, which brings up the Print sheet.
- It runs an AppleScript that selects the two-sided printing options I like.
- It clicks the button at the bottom right corner of the sheet, sending the job off to the printer.
The AppleScript in the second step is this:
applescript:
1: tell application "System Events"
2: tell process "Numbers"
3: tell sheet 1 of window 1
4: tell checkbox "Two-Sided"
5: if not (its value as boolean) then click
6: end tell
7: tell (pop up button 1 whose accessibility description is "PDE")
8: click
9: click menu item "Layout" of menu 1
10: end tell
11: tell (pop up button 1 whose accessibility description is "Two-Sided")
12: click
13: click menu item "Short-Edge binding" of menu 1
14: end tell
15: end tell
16: end tell
17: end tell
Line 1 opens System Events to make the UI commands available. Lines 2 and 3 do the tell
s necessary to focus the subsequent UI scripting actions on the Print sheet. Then we start the trickier parts.
Lines 4–6 click the “Two-Sided” checkbox if it isn’t already selected. The state of that checkbox depends on whether I’ve already printed something two-sided during the current Numbers session. So the state of the checkbox has to be tested before clicking it—that’s easy to do in AppleScript but not so easy in Keyboard Maestro.
The best way to be sure of the name of a button or checkbox is to run Accessibility Inspector and move the mouse over the item of interest. You can address the item with the name in the AXTitle field.
Currently, Layout is the initial setting of the options popup button in the middle of the Numbers Print sheet, but that could change in the future. To ensure that its options are available, Lines 7–10 select Layout from that popup button.
The popup buttons in the Print sheet don’t have an AXTitle field, so we have to address them a different way. We could find the index of a popup button by repeatedly trying lines like
tell pop up button 1
click
click menu item "Layout" of menu 1
end tell
and
tell pop up button 2
click
click menu item "Layout" of menu 1
end tell
and
tell pop up button 3
click
click menu item "Layout" of menu 1
end tell
and so on until one of them worked. I’ve used this approach in the past, but I’ve also been burned when a new version of the application is released and the developers have reordered the popup buttons.
A more robust way to get the right popup button is to select it according to its accessibility description
. This is one of the properties of a UI element, found in the AppleScript dictionary for System Events.
Its value can be found by moving the mouse over the popup button and looking at the AXDescription field in Accessibility Inspector.
Of course, this being AppleScript, you can’t just say
tell pop up button "PDE"
Instead you have to get the list of all pop up buttons, filter it down to those with an accessibility description
of “PDE” (which is just the one), and then pluck out the single item in that list. You can think of Line 7 as the end point of a sequence of ever-narrowing selections:
get pop up buttons
get pop up buttons whose accessibility description is "PDE"
get item 1 of (pop up buttons whose accessibility description is "PDE")
get pop up button 1 whose accessibility description is "PDE"
The last one is just a shorter and more English-like version of the one before it. They accomplish the same thing.
Lines 11–14 work just like Lines 7–10, but on a different popup button. As before, I got its accessibility description
from the AXDescription field in Accessibility Inspector.
As best I know, Keyboard Maestro doesn’t have a direct method of selecting an item from a popup button. The best solution I know is described in an old blog post on the Stairways Software site:
- Simulate a click on the popup button (probably by using an image).
- Simulate keystrokes to select the desired menu item.
- Simulate the Return key
Unless you’re really averse to programming, the AppleScript is easier once you know the general technique.