I'm calling a KM Macro via external ApplesScript. As part of the call, I'm also passing a parameter—which KM drops into the Trigger variable.
But I want to pass 32 variables when I call the Macro. What's the best way to do that in my AppleScript calling code, and where would the data go in KM? Ideally, I would pass an array. (Well, most ideally would be passing a pointer to an array, but that could get messy.)
EDIT: Here is a more structured description of the issue that I posted on MIDI Translator's forum:
Note that AppleScript records are prone to change the case of your key names, and that the references are case sensitive.
(JavaScript's records/objects are more flexible and relaxed):
Expand disclosure triangle to view example AppleScript
use framework "Foundation"
use scripting additions
on run
set recVars to {Alpha:1, Beta:2, Gamma:3, Delta:"Some change or other"} & ¬
{Epsilon:"Something tiny", lambda:"Something functional"} & ¬
{omnicron:"smaller o", omega:"larger O"}
set jsonString to my showJSON(recVars)
tell application "Keyboard Maestro Engine"
setvariable "jsonVar" to jsonString
end tell
jsonString
end run
-- showJSON :: a -> String
on showJSON(x)
set c to class of x
if (c is list) or (c is record) then
set ca to current application
set {json, e} to ca's NSJSONSerialization's dataWithJSONObject:x options:1 |error|:(reference)
if json is missing value then
e's localizedDescription() as text
else
(ca's NSString's alloc()'s initWithData:json encoding:(ca's NSUTF8StringEncoding)) as text
end if
else if c is date then
"\"" & ((x - (time to GMT)) as «class isot» as string) & ".000Z" & "\""
else if c is text then
"\"" & x & "\""
else if (c is integer or c is real) then
x as text
else if c is class then
"null"
else
try
x as text
on error
("«" & c as text) & "»"
end try
end if
end showJSON
Thank you for the additional information. MIDI Translator is a wonderful application—I just wish its scripting semantics and syntax matched KB's maturity…I cannot use JavaScript in MT.
You mentioned arrays in another thread, and AppleScript lists are certainly less tricky than records.
The AppleScript end is much the same (pass a list to showJSON)
and at the KM end, the indexing is 1-based
( index 0 holds the length of the array)
Expand disclosure triangle to view AppleScript for Arrays
use framework "Foundation"
use scripting additions
on run
set someList to {"alpha", "beta", "gamma", "delta", "epsilon", "zeta"}
set jsonArray to my showJSON(someList)
tell application "Keyboard Maestro Engine"
setvariable "jsonArray" to jsonArray
end tell
jsonArray
end run
-- showJSON :: a -> String
on showJSON(x)
set c to class of x
if (c is list) or (c is record) then
set ca to current application
set {json, e} to ca's NSJSONSerialization's dataWithJSONObject:x options:1 |error|:(reference)
if json is missing value then
e's localizedDescription() as text
else
(ca's NSString's alloc()'s initWithData:json encoding:(ca's NSUTF8StringEncoding)) as text
end if
else if c is date then
"\"" & ((x - (time to GMT)) as «class isot» as string) & ".000Z" & "\""
else if c is text then
"\"" & x & "\""
else if (c is integer or c is real) then
x as text
else if c is class then
"null"
else
try
x as text
on error
("«" & c as text) & "»"
end try
end if
end showJSON
Thank you, kindly. Understood on all. My only other question (I think) is about the most efficient way to do it, as this is a realtime system operating over AppleScript. The best solution might be to allocate 32 global variables, and have the sending application write to them—and then KB read them?
The globals could be allocated in the sending application (MIDI Translator) or in KM. Or, maybe an intermediate data structure (e.g. JSON object or AS list). Whatever provides persistent data storage that (from the apps' perspectives) doesn't move around, therefore avoiding some of the penalties normally associated with interpreted languages.
You will learn by testing, but if latency really is an issue (solidity always saves more time than speed, over the course of a year) then the trick will be to minimize the number of AppleEvents, which are slow, and form a bottle-neck.
Returning a single compound object like a list or record from AS is likely to be a better bet than 32 distinct events.
Rob has covered using JSON, so here's a quick example using delimited text. (You can change the delimiter to any character.)
set dataIn01 to "one"
set dataIn02 to "two"
set dataIn03 to "three"
set dataIn04 to "four"
set dataIn05 to "five"
set myList to {dataIn01, dataIn02, dataIn03, dataIn04, dataIn05}
set AppleScript's text item delimiters to ","
tell application "Keyboard Maestro Engine"
setvariable "g_DataTransfer" to myList as text
end tell