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

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.

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.

1 Like

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.

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).

8 Likes

--> will now work ?

1 Like

Lucky I program better than I type :wink:

3 Likes

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

1 Like

Confirmed.

1 Like

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?

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):

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

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

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.

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.

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) ?

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.