Re: Feature request to solve a problematic AppleScript behavior with raw Apple Event codes
Re: Feature request to solve a problematic AppleScript behavior with raw Apple Event codes
- Subject: Re: Feature request to solve a problematic AppleScript behavior with raw Apple Event codes
- From: has <email@hidden>
- Date: Fri, 22 Oct 2010 13:35:05 +0100
Scott Babcock wrote:
> I have a request for a feature that would solve a problematic AppleScript behavior - conversion of raw Apple Event codes to their "friendly" equivalents and rendering the affected code non-compile-able.
>
> I ran into a situation in which I needed to branch based on the form of a specified object reference (named/index/id). Getting the reference form is obscure but relatively easy (coerce the reference to a record and grab the <<class form>> property).
Coercing an AEDesc of typeObjectSpecifier to typeAERecord is supported
by the Apple Event Manager APIs, but it's not a documented behaviour
within the AppleScript language so you gets exactly what you pays for.
(If anything, coercing a reference to a record within AS ought to
raise a coercion error rather than cause AS to spill its private
implementation all over the place; feel free to file a bug report on
that.)
The correct way to do this (i.e. relying on documented APIs only)
would be to write an osax that uses the AEM APIs to decompose the
AEDesc for you. That's quite easy to do; the only minor catch is that
to pass an arbitrary application reference in an osax command, you
need to wrap it in a script object first, then have the C code pull it
out again on the other side.
If you don't have the option of deploying custom osaxen then your only
other option is to continue exploiting undocumented AS 'features', and
hope that they don't blow up on you:
on getprop(obj, fourcharcode)
-- Caution: exploits undocumented behaviour; use at own risk!
-- Caution: four-char code string is _not_ checked or sanitised before eval!
script wrapper
property rec : obj as record
end script
return run script "
on run {wrapper}
return «class " & fourcharcode & "» of rec of wrapper
end run" with parameters {wrapper}
end getprop
tell application "System Events"
set procRef to process "Finder"
end tell
set refRecord to procRef as record
{getprop(refRecord, "want"), getprop(refRecord, "form"),
getprop(refRecord, "seld"), getprop(refRecord, "from")}
--> {application process, named, "Finder", «script»}
> These hacks do the trick, but there's a property in the reference record that can't be dealt with this way - <<class from>>. This property contains a reference to the object's parent - in this case, System Events.
No, in this case it contains a typeNull descriptor, as that is the
root descriptor for an object specifier that represents an absolute
reference. I don't believe there's any way to get that information
from an AppleScript reference object, short of going through the
official APIs. (AS supports a 'qualified' specifier format whose root
descriptor is an AEAddressDesc, for use by attachable apps such as
Automator that need to pass arbitrary application references in and
out of the AS component via the OSA APIs.)
Matt Neuburg wrote:
> In Ruby, your script is just text; merely opening the script or running it doesn't mysteriously cause its contents to get changed. And inspecting the form of the canonical reference returned by an application doesn't require any magic tricks. Here's the rb-appscript equivalent of your script:
>
> procRef = Appscript.app("System Events").processes["Finder"]
> ref = procRef.get
> if ref.AS_aem_reference.to_s.include? 'by_name("Finder")'
> puts "a named reference to the Finder"
> end
That's not a robust solution though. A better approach would be to
repack the reference as an AEDesc, and then extract the required
information via AEDesc#get_param (with extra points awarded for
converting those descriptors back into Ruby values):
se = app('System Events')
codecs = se.AS_app_data
ref = se.processes['Finder']
# => app("/System/Library/CoreServices/System Events.app").processes["Finder"]
desc = codecs.pack(ref.AS_aem_reference)
# => #<AE::AEDesc type="obj " size=92>
[KAE::KeyAEDesiredClass, KAE::KeyAEKeyForm, KAE::KeyAEKeyData,
KAE::KeyAEContainer].each do |code|
p codecs.unpack(desc.get_param(code, '****'))
end
# => :process
# => AEM::AEEnum.new("name")
# => "Finder"
# => nil
Alternatively, you could use the AEM ref's #AEM_resolve API to
'replay' the sequence of method calls used to construct it, passing it
a suitable visitor object. While it's technically a private API it's
quite stable and safe to use (as are the other AS_ and AEM_ APIs).
HTH
has
--
Learn AppleScript, 3rd edition, Sanderson & Rosenthal:
http://apress.com/book/view/9781430223610
Control AppleScriptable applications from Python, Ruby and ObjC:
http://appscript.sourceforge.net
_______________________________________________
Do not post admin requests to the list. They will be ignored.
AppleScript-Users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
Archives: http://lists.apple.com/archives/applescript-users
This email sent to email@hidden