KM8: How Do We Script Creation of KM Dictionaries & Keys?

jxa
dictionaries
km8
applescript

#1

Continuing the discussion from Creating KM dictionaries from Scripts:

@peternlewis, based on the script by @ComplexPoint, and my own testing (both AppleScript and JXA), it does not appear possible to create KM Dictionaries using direct scripting terminology in the KM Engine. @ComplexPoint had to resort to using dynamically created KM Macros, which were then executed using the doScript command.

If I’m missing something, and there is a more direct way in either AppleScript or JXA, please advise.

Here is my test script, based on the JXA functions provide by @ComplexPoint.
This works, but does require use of dynamically created KM Macro.

JXA Test Script to Create a Dictionary

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
@Creating @KM @Dictionaries from Script @JXA
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DATE:    2018-02-15

  REF:
    • Creating KM dictionaries from Scripts by @ComplexPoint
    • https://forum.keyboardmaestro.com/t/creating-km-dictionaries-from-scripts/8249
*/

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  Function to Create KM Dictionary with Key and Value
//    • Apparently this cannot be done with normal AppleScript or JXA
//    • Appears to Require Use of Dynamically Created KM Macro
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// kmDictValueSet :: String -> String -> String -> KM ()
const kmDictValueSet = (strDict, strKey, strValue) =>
    Application('Keyboard Maestro Engine')
    .doScript(plistMay([{
            MacroActionType: 'SetDictionaryValue',
            Dictionary: strDict,
            Key: strKey,
            Value: strValue
        }])
        .just);
            
// plistMay :: JS Object -> Maybe Plist String
const plistMay = jso => {
    var error = $();
    const maybeString = $.NSString.alloc.initWithDataEncoding(
        $.NSPropertyListSerialization
        .dataWithPropertyListFormatOptionsError(
            $(jso),
            $.NSPropertyListXMLFormat_v1_0,
            0,
            error
        ),
        $.NSUTF8StringEncoding
    );
    return Boolean(error.code) ? {
        nothing: true,
        msg: error.localizedDescription
    } : {
        nothing: false,
        just: ObjC.unwrap(maybeString)
    };
};
//~~~~~~~~~~~~~~~~~~~~~~ MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


var kmDictName   = "JXA_Dict1";
var kmKeyName    = "JXA_K1";
var kmKeyValue  = "Created by JXA";

var oDict = kmDictValueSet(kmDictName, kmKeyName, kmKeyValue)

var appKME = Application("Keyboard Maestro Engine")
var kmDictList = appKME.dictionaries.name();

kmDictList

If I am correct, please consider this as a feature request to provide explicit scripting commands to create KM Dictionaries, and KM Dictionary Keys.


How Can I Access Dictionary From JXA?
#2

When I use this command in AppleScript:

tell application "Keyboard Maestro Engine" to ¬
    make new dictionary with properties {name:"TestDict"}

the output returns the new dictionary id, suggesting it has been created. However, retrieving the dictionary fails, and get dictionaries reveals it does not exist.

I wonder if the dictionary does, at one point, get created, but then immediately destroyed for having no keys contained in it. After all, if I take an existing dictionary and set all of its keys’ values to an empty string, this immediately deletes the dictionary.


#3

Yep, I’ve observed the same behavior.
Furthermore, I have been unable to find a way using AppleScript to set the properties for make new dictionary that include a Dictionary Key and value.


#4

I have improved the AppleScript handling so that this will work:

tell application "Keyboard Maestro Engine"
	set m to make new dictionary with properties {name:"DictName"}
	tell m to make new dictionary key with properties {name:"KeyName", value:"TheValue"}
end tell

I have done this for a future version (after the next version).


#5

–> will now work ?


#6

Lucky I program better than I type :wink:


#7

This should work as described in 8.1.1, let me know if not.


#8

Confirmed.


#9

I've been playing around with dictionaries and wanted to see if anyone has had any success in created them with JXA. The following works fine for creating a dictionary:

var kme = Application("Keyboard Maestro Engine");
kme.includeStandardAdditions = true;
kme.strictParameterType = true

var dict = kme.Dictionary({name: "MyTest"}).make()

//Result:
//Application("Keyboard Maestro Engine").dictionaries.byId("MyTest")
dict

Where I'm running into issues is trying to append a DictionaryKey class into dict.dictionaryKeys. The closest I've gotten without running into the generic Error -10000: AppleEvent handler failed. is the following

kme.make({
	new: kme.DictionaryKey, 
	at: dict.dictionaryKeys,
	withProperties: {name:"KeyName", value:"TheValue"}
})

This results in a Error: Can't convert types.. Any suggestions on creating dictionaries in JXA?


#10

The Scripting interface to Dictionaries is known to fail on attempts to create new keys (it does succeed with updating existing keys)

I don't know if this helps (re-routing through .doScript, which does work):


#11

Thanks, but I'm looking to see if there's an actual solution rather than a workaround.


#12

Do you need to do it in JXA specifically, or are you happy using regular AppleScript, for which, I believe, scripting the creation of dictionaries and keys works fine.

AppleScript
tell application "Keyboard Maestro Engine"
	set D to make new dictionary ¬
		with properties {name:"TestDict", id:"TestDict"}
	
	tell D to make new dictionary key with properties ¬
		{name:"TestKey", id:"TestDict:TestKey", value:"It worked!"}
	
	get the value of every dictionary key in the dictionary named "TestDict"
end tell

#13

Thanks @CJK. I should have noted that I know it works fine in AppleScript. Mostly just trying to get JSX to work. I know it should work, it's just a matter of getting the syntax right.


#14

I'm just learning about Dictionaries so I may be mistaken, but this script worked for me while the script shown in the wiki did not.


#15

The script's all do different things. Peter's script was aimed a creating new dictionaries. The snippets in the Wiki are aimed at retrieving dictionaries or keys and setting values for keys of dictionaries that already exist.

I just tested the three snippets on the Wiki page to which you linked, and I can confirm that they each perform their function correctly.

What did you try that failed to work (and what were you hoping it would do that it didn't) ?


#16

I thought this script would allow me to create a Dictionary, Names and Values in one step. I was wrong.
tell application "Keyboard Maestro Engine"
set value of dictionary key "P" of dictionary "First Names" to "Fred"
end tell

But the script Peter shared, above, does do that.