Mark Sanvitale wrote:
This should be a super basic question. Alas, I have spent many hours banging my head against this problem.
[...]{position:{0, 280}, maximum value:missing value, name:"Print ", size: {259, 19}, subrole:missing value, class:menu item, minimum value:missing value, enabled:false, selected:false, role:"AXMenuItem", help:missing value, title:"Print ", value:missing value, entire contents:{}, description:"menu item", focused:missing value, orientation:missing value} I want to access the enabled property. I eventually discover that I can access a property like so: return name of (get properties of printMenuItem) which correctly returns "Print ". Now, I replace name with enabled and I get an error. A few properties work in the above statement (e.g. class, size) but most do not, including my precious enabled property.
Welcome to the obfuscated mess that is AppleScript's context-sensitive grammar. Your problem is a result of all the cunning compiler trickery that AppleScript uses to create that nice, English-like syntax (where white space is both a keyword delimiter and a legal character within keywords), and Apple's chronic inability/failure to adequately explain its behaviour and limitations to users.
Basically, 'tell application "NAME" ... end' blocks serve two purposes: 1. to identify a default target for runtime commands, and 2. to make the parser recognise keywords defined in the specified application's terminology resource in addition to the keywords defined in the AppleScript language's terminology resource.
Outside of that 'tell application' block, only AppleScript's built-in terminology is available to the parser. So any time you write an application-defined keyword in a script it must appear within a 'tell' block (or 'using terms from' block) that identifies the application at compile-time, or else it won't compile correctly (the only exceptions being keywords that are also defined by AppleScript, e.g. 'name', 'class'). e.g. This compiles as intended:
tell application "System Events" set props to properties of menu item "Print…" of menu "File" of ¬ menu bar item "File" of menu bar 1 of process "Safari" return enabled of props end tell
but this doesn't:
tell application "System Events" set props to properties of menu item "Print…" of menu "File" of ¬ menu bar item "File" of menu bar 1 of process "Safari" end tell return enabled of props
Look real closely in Script Editor, and (assuming you haven't changed the default colours) you'll notice AppleScript's pretty printer uses different colours to indicate application-defined keywords versus user-defined identifiers. 'enabled' needs to be an application-defined keyword, not an identifier, same as the application-defined 'enabled' property in the record returned by System Events.
...
FWIW, other Apple event bridges are largely immune to these sorts of problems as they use existing language structures to construct Apple event queries, commands and symbols, e.g. Ruby appscript does all its terminology translation at runtime: queries and commands are constructed using Ruby methods, and type/enumerator/property name symbols are represented by instances of Ruby's Symbol class.
require "appscript"; include Appscript require 'pp'
se = app("System Events") app("Safari").activate print_menu_ref = se.processes["Safari"].menu_bars[1].menu_bar_items["File"].menus["File"].menu_items["Print\342\200\246"]
pp print_menu_ref.enabled.get # result: true
record = print_menu_ref.properties_.get pp record # result: {:class_=>:menu_item, :role=>"AXMenuItem", :minimum_value=>:missing_value, :focused=>:missing_value, :subrole=>:missing_value, :position=>[0, 280], :value=>:missing_value, :name=>"Print\342\200\246", :maximum_value=>:missing_value, :description=>"menu item", :entire_contents=>[], :selected=>false, :enabled=>true, :orientation=>:missing_value, :help_=>:missing_value, :size=>[259, 19], :title=>"Print\342\200\246"} pp record[:enabled] # result: true
HTH
has
p.s. If you're comfortable with other languages, it's worth noting that OS X's Carbon/Cocoa accessibility APIs can be accessed directly from C/ObjC; you don't have to go through System Events if you don't want to. (Though programmatically controlling other applications via their GUIs is still fundamentally evil, of course.) -- Control AppleScriptable applications from Python, Ruby and ObjC:
|