20.4. Raw Four-Letter CodesWhen AppleScript compiles a script, it uses the dictionary to translate your English-like terminology into Apple events. When AppleScript decompiles a compiled script, it uses the dictionary to translate Apple events to English-like terminology. It is possible to do AppleScript's job for it and type a raw Apple event directly into a script. There is then no translation to be performed, and no dictionary is needed. Apple events, as we observed in Chapter 3, are constructed of four-letter codes. The notation is a keyword stating what "part of speech" this four-letter code is (such as constant, property, class or event), followed by a space, followed by the four letters (or, in the case of an event, eight letters). The entire thing is wrapped in guillemets, also called chevrons («»). On the U.S. keyboard layout, these are typed using Option-\ and Shift-Option-\ (backslash). Using raw Apple events, we can target an application using its own terminology but without a tell block and without AppleScript's making any use of the application's dictionary. For example:
get name of «class cdis» 1 of application "Finder" -- "feathers" The term name is defined by AppleScript, but the term disk is not. Yet we can use the term disk outside a tell block by entering it in its raw form. There are not many situations where this sort of thing is necessary, but it can be a useful strategy to know about. There are times when it can be a way of resolving a terminology conflict . Recall that earlier I mentioned a longstanding conflict between BBEdit and the offset scripting addition command. A similar problem exists when trying to use the path to scripting addition command while targeting System Events (I owe this example to John Gruber): path to application support from user domain -- alias "feathers:Users:mattneub:Library:Application Support:" tell application "System Events" path to application support from user domain -- alias "feathers:Library:Application Support:" end tell The very same scripting addition command gives a different answer depending on whether the context targets System Events or not. The System Events answer is wrong, and is caused by the fact that System Events defines a user domain property, which conflicts with the user domain enumerator in StandardAdditions. (It's the same four-letter code with the same English-like terminology, but used as a different "part of speech.") You can work around the problem by using raw four-letter codes:
tell application "System Events"
path to application support from «constant fldmfldu»
-- alias "feathers:Users:mattneub:Library:Application Support:"
end tell You may find use of four-letter codes not very satisfactory as a solution to terminology conflict, because the original problem recurs the next time the script is compiled. Take the previous example. When we run the script, the four-letter code decompiles to user domain. That's fine as long as the script doesn't need recompilation; but if the script is edited, then the next time we compile, this term is misunderstood by the compiler in the same way as before, and the raw Apple event has to be substituted again. One easy fix is to capture the enumerator as a variable:
set userdomain to user domain
tell application "System Events"
path to application support from userdomain
-- alias "feathers:Users:mattneub:Library:Application Support:"
end tell An even more robust approach is to use run script to get a second level of evaluation. It's true that run script is expensive, but we can mitigate this somewhat by calling it in a script property initializer, so that the result is obtained just once (until we recompile, of course). The four-letter code appears as a literal string, which has the further advantage of clarifying the purpose of our trickery:
property userdomain : run script ("«constant fldmfldu»")
tell application "System Events"
path to application support from userdomain
-- alias "feathers:Users:mattneub:Library:Application Support:"
end tell If decompilation of a script runs into trouble, you may see bits and pieces of original Apple events as raw four-letter codes. We saw earlier ("Missing External Referents" in Chapter 3) what happens if an application or scripting addition is present when a script file is compiled but is missing when you open the compiled script file in a script editor application. AppleScript needs the dictionary in order to decompile the script. If a scripting addition is missing, or if AppleScript can't find an application and you nominate some other application, the script opens anyway, but any Apple events that can't be translated into English appear as raw four-letter codes: tell application "Finder" get «class euSu» of «class euMS» 1 of «class euMB» "Trash" end tell Something similar can happen in the display of a dictionary, if the dictionary is defective. For instance, BBEdit's print settings class has a property cover page whose class is described as lwec (or, in older presentations of the dictionary, «class lwec»). Evidently this refers to some class or enumeration whose definition is missing from the dictionary, so it has to be displayed using its four-letter code. Because the definition is missing, it is impossible to learn what BBEdit expects here. In a compiled script executed by a script runner, or in an applet, no decompilation takes place. Therefore, if you ask AppleScript to do something involving translation through a dictionary, you may end up seeing four-letter codes. Here's an example. This works in a script editor application:
tell application "iTunes"
display dialog (kind of source 1 as string) -- library
end tell The kind property of a source in iTunes is an enumeration, so what comes back from iTunes here is a constant. A constant can't be shown by display dialog, but it can be coerced to a string (Chapter 17) and then shown. iTunes does not implement this coercion, so AppleScript performs it (see "Coercion by a Scriptable Application" in Chapter 14). In a script editor application, it can do this satisfactorily, thanks to decompilation: AppleScript has access to iTunes's dictionary, so it knows that the English-like term for this constant is library and can coerce it to the string "library". But when executing in a script runner or an applet, there is no decompilation, and AppleScript is left holding the bag. All it knows is the four-letter code for this constant, because that's what came back from iTunes. It has no way to translate it into English, so it coerces the four-letter code to a string:
tell application "iTunes"
display dialog (kind of source 1 as string) -- «constant ****kLib»
end tell The workaround in this situation is to construct a table of constants and their string equivalents and perform the translation yourself:
set R to {«class kACD»:"audio CD", «class kLib»:"library",
«class kTrk»:"track listing"}
tell application "iTunes"
set k to (get kind of source 1)
display dialog (get property k in R) -- library
end tell (The next-to-last line uses Late Night Software's List & Record Tools scripting addition to make the lookup process more elegant. It allows a record property to be expressed as the value of a variable.) All this assumes, of course, that you have a way to learn what the four-letter codes are. One very easy way is to use Script Debugger, whose dictionary display and Apple Event Log allow you to view the four-letter codes directly. Alternatively, if the dictionary is a text file, you can read it in any text editor; if it is (or if you can turn it into) an 'aete' resource in a resource fork, you can read it with the freeware Eighty-Rez. |