How to Save a Selection of Variables Like Presets


#1

Continuing the discussion from [KM] DELETE List of KM Variables [SUB-MACRO]:

I started a new topic for this.

I've regularly wished there was some sort of Name/Value storage system available to KM. It would be awesome if someone could produce a generic version of this.

But since that isn't available (to my knowledge), I'm going to give you one answer, but I can guarantee that someone else will come up with a better idea. Always happens when I reply to something like this. And honestly, I hope they do, because this isn't the most elegant solution.

The answer depends a lot on two questions:

  1. How bullet-proof does this need to be? Are you the only one who's going to use it? Are you OK with fixing issues as they come up?

If we assume the answer to #1 is that you're using it for yourself, and if it breaks, you'll fix it, then let's go on to #2.

  1. What kind of data will you be storing?

a) For example, if each of your variables can be guaranteed to be a single line, then you could write them out to a text file, one value on each line. When you read the file back in, you'd have to make sure you "got the variables out" in the same order you put them in.

This isn't very bullet-proof. For example, if you no longer need a particular variable, you'd still need to continue to read it and write it back out. New variables would always have to be added to the end. And if a stray NEWLINE got introduced into a variable somehow, everything breaks.

b) I have one workflow where I store various settings, each in their own file, inside folders for each "preset". This is pretty easy. I do it this way in this particular workflow, because many of the variables are lists, so it's a lot easier to deal with one file per variable.

c) Another idea is, you could develop some JSON objects and use JXA to store and retrieve them. I know this is possible, I don't know how to do it myself, but there are some examples embedded in various macros and plugins on the forum.

That's all I got. Interested to see what comes of this topic. I know I'll learn something new - I always do!


#2

Perhaps the simplest approach might be to use a few ‘top-level’ KM variables which store JSON strings.

The sets of key-value pairs can be:

  • retrieved in JavaScript for Automation with JSON.parse(strJSON)
  • farmed out (at run-time) to temporary satellite variables with Application('Keyboard Maestro Engine').setvariable(strVarName, {to: strValue})
  • updated with JSON.stringify(dctObject)

Can you think of a minimal application that could be sketched up as a simple demo ?


#3

Here’s one example of the data I’d be saving/ recalling: %Variable%Take Counter Mode%|Continuous|Return To 1.


#4

Is there some reason using a standard Mac .plist wouldn’t work?
You could implement using an actual file, or the data just stored in a KM Variable.


#5

I suppose I could do this:

And use it to save the values of all the variables to a spreadsheet.


#6

How about ignorance? How would I do this?


#7

Sorry I don’t have anything specific to offer, but I believe there have been a number of post in this forum on using plists with AppleScript and JXA, although using JSON with JXA might be a better approach.

As always, you do an Internet search on “AppleScript plist”, and you will find lots of hits.

Here’s one:
Read/Write Property Lists


#8

@DanThomas, here is one example AppleScript that gets a list of PLIST “name” items.

set plistFilePath to "~/Library/Application Support/Keyboard Maestro/Keyboard Maestro Recent Applications.plist"

tell application "System Events"
  tell property list file plistFilePath
    tell property list items
      set recentAppList to value of property list item "Name"
    end tell
  end tell
end tell
set AppleScript's text item delimiters to "
"

return recentAppList as text

#9

Hey Folks,

I think that ultimately JSON may be the easiest medium to manage and manipulate, because JavaScript has so many tools for managing it – but you’ve got to get over the learning-curb first.

In the meantime we use the tools we know…

This AppleScript will save all Keyboard Maestro variable name-value pairs to a plist on the Desktop.

It is of course quite easy to filter out specific variables.

---------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2016/06/01 00:35
# dMod: 2016/06/01 00:49
# Appl: Keyboard Maestro, System Events
# Task: Store Keyboard Maestro variables' names and values in a plist file on the Desktop.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro, @System_Events, @Store, @Variables, @Plist
---------------------------------------------------------------------------------

tell application "Keyboard Maestro Engine"
  tell variables
    set {kmVarNameList, kmVarValueList} to {name, value}
  end tell
end tell

tell application "System Events"
  tell (make new property list file with properties {name:"~/Desktop/TEST.plist"})
    repeat with i from 1 to length of kmVarNameList
      set kmVarName to item i of kmVarNameList
      set kmVarValue to item i of kmVarValueList
      make new property list item with properties {name:kmVarName, value:kmVarValue} at the end of property list items
    end repeat
  end tell
end tell

---------------------------------------------------------------------------------

Retrieval is something like this:

---------------------------------------------------------------------------------
set plistFile to "~/Desktop/TEST.plist"

tell application "System Events"
  tell property list file plistFile
    
    set plistItemList to property list items
    set plistItemNameList to name of property list items
    set plistItemValueList to value of property list items
    
    set filteredPlistItemList to property list items whose name contains "test"
    
    set testVarValue to value of property list item "testVar"
    
  end tell
end tell
---------------------------------------------------------------------------------

-Chris


Save and recall a selection of variables
#10

Here's a test script by @JMichaelTX I found:

I haven't tried it and am not super familiar with JXA. If anyone could break it down, I would love that! Specifically, I have dynamically stored variables, and I'd like to be able to get the stored value of all individual variables starting with the string "STOREVAL", and save all those values as a snapshot. Then I'd like to recall multiple variable states as "presets" I can reuse.

Another scenario, I would like to get the stored value of all variables starting with "STOREVAL" and increase the numeric value of each by 1. Is this possible? Thank you!!


#11

Hey Jay,

You'll have to provide a more complete picture of your workflow to get realistic help.

If you haven't read this it's worth a couple of minutes of your time.

Tip: How Do I Get The Best Answer in the Shortest Time?

Getting variable names and values is easily done with AppleScript.

----------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2019/01/11 14:23
# dMod: 2019/01/11 14:23 
# Appl: Keyboard Maestro
# Task: Extract Keyboard Maestro Variable Name and Value for Variable Names with a Prefix.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro_Engine, @Extract, @Variable, @Names, @Values, @Prefix
----------------------------------------------------------------
# Extract variable names and variable values.
----------------------------------------------------------------

tell application "Keyboard Maestro Engine"
   tell (variables whose name starts with "STOREVAL")
      set {varNameList, varValueList} to {name, value}
   end tell
end tell

----------------------------------------------------------------
# Convert AppleScript List Objects into Text.
----------------------------------------------------------------

try
   varNameList / 0
on error eMsg
   set varNameList to removeErrorNotation(eMsg) of me
end try
try
   varValueList / 0
on error eMsg
   set varValueList to removeErrorNotation(eMsg) of me
end try

----------------------------------------------------------------
--» HANDLERS
----------------------------------------------------------------
on removeErrorNotation(errStr)
   set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"Can't make ", " into type real."}}
   set returnValue to text item 2 of errStr
   set AppleScript's text item delimiters to oldTIDS
   return returnValue
end removeErrorNotation
----------------------------------------------------------------

Now we have the issues of where to store the data and how to retrieve it.

-Chris


#12

Thanks for your help Chris. I had seen your post before and appreciated the code! I've kind of wanted to stay away from AppleScript.. somehow I thought JS would be a better solution, but maybe KM has everything I need to store and recall variables.

In this example I store value of the letter G, which has multiple options depending on another variable that provides a prefix (creating dynamic variables I can recall and store).

However, I would like to change the value of all stored dynamic variables stored in this way by an increment or decrement of 1. Does anyone know how to accomplish this with regex or some other solution? Thank you guys!


#13

Hey Jay,

Since you don't know JavaScript already you're looking at a bigger learning curve than plain old AppleScript.

If you use Keyboard Maestro actions why can't you use a calculation action to add your +1?

There is no concept of dynamic variable in Keyboard Maestro, so I'm guessing you mean a dynamically created variable – yes?

Here's how you can do such a thing with AppleScript:

----------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2019/01/11 17:08
# dMod: 2019/01/11 17:08 
# Appl: Keyboard Maestro
# Task: Increment Stored Variable Integer Values
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro_Engine, @Increment, @Stored, @Variable, @Integer, @Values
----------------------------------------------------------------

tell application "Keyboard Maestro Engine"
   set varList to variables whose name starts with "STOREVAL"
   
   repeat with theVar in varList
      set value of theVar to (get value of theVar as integer) + 1
   end repeat
   
end tell

----------------------------------------------------------------

-Chris


#14

Chris thank you your solutions are totally spot on. Calculation +1 is all I needed, I think I was making life more complicated than it needed to be! But amazing you can do that with AppleScript in such few lines!


#15

@jayknowstheway, don't use that script. It is very old and should be deprecated as of KM 7.1+.

Please see

@jayknowstheway, I would have to disagee with Chris about this.
IMO, it is much easier to learn JavaScript than to learn AppleScript, from scratch. JavaScript is much more like all other common-use languages, and has many, many more built-in functions that AppleScript is missing. There are also many books and onine courses to help you learn JavaScript.

JavaScript for Automation (JXA) use the core JavaScript language, but with an Apple Events context rather than a web context like you have when using JavaScript in a Browser.

If you want to ask more questions about JavaScript in this forum, it would be best to start a new topic with your question.


#16

Perhaps not easy to really justify that statement.

Applescript is bound to feel "plain" and "old" to people who have been working with it for a decade or two, but that doesn't give us much insight into how it really looks to a beginner.

It's syntactically a very quirky outlier with lots of edge cases that take some time to fully digest.

"English-like", as any learner of English knows, often means puzzling, inscrutable and inconsistent.

JS is mainstream to the point of boring in its syntax – and very well documented and supported with learning materials and courses. It's also more widely usable, a lot faster, and much better equipped with basic libraries.

To do a lot of rather basic stuff in Applescript (regexes for example) you have to learn to use the FFI to the Objective C libraries, which it would be quite a stretch to usefully describe as "plain old".

Another problem with Applescript is, probably sadly, that it's basically finished. Apple will preserve it in formaldehyde for some time, but have no further plans to develop it. Their revenues and focus are now centred on iOS. You can use JavaScript on iOS (Drafts, 1Writer, OmniGraffle, OmniOutliner, Scriptable, etc etc) but you can't use AppleScript on iOS at all.


#17

Fantastic, those are great resources! I figured as much about JS, thank you for the encouragement!