I've scanned through Keyboard Maestro actions and forum and cannot see an equivalent way of doing in Keyboard Maestro, although I imagine it's possible. Apologies in advance if I have missed anything obvious.
Is there an equivalent way of doing this in Keyboard Maestro?
each line (key-value pairing) separated by a comma,
each key and string value in "double quotes"
each key: value separated by :
Once you have your dictionary in the JSON exchange format, you can either use it as a KM Dictionary (one approach below), or use it in an Execute JavaScript for Automation action.
(() => {
"use strict";
// value__key lines for KM 'Prompt from List' actions
// obtained from a JSON dictionary of key:value pairs.
const main = () =>
either(
alert("Prompt list from JSON dictionary")
)(
x => x
)(
bindLR(
jsonParseLR(
Application("Keyboard Maestro Engine")
.getvariable("jsonDict")
)
)(
dict => Right(
Object.keys(dict).map(
k => `${dict[k]}__${k}`
)
.join("\n")
)
)
);
// ----------------------- JXA -----------------------
// alert :: String => String -> IO String
const alert = title =>
s => {
const sa = Object.assign(
Application("System Events"), {
includeStandardAdditions: true
});
return (
sa.activate(),
sa.displayDialog(s, {
withTitle: title,
buttons: ["OK"],
defaultButton: "OK"
}),
s
);
};
// --------------------- GENERIC ---------------------
// Left :: a -> Either a b
const Left = x => ({
type: "Either",
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: "Either",
Right: x
});
// bindLR (>>=) :: Either a ->
// (a -> Either b) -> Either b
const bindLR = m =>
mf => m.Left ? (
m
) : mf(m.Right);
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl =>
// Application of the function fl to the
// contents of any Left value in e, or
// the application of fr to its Right value.
fr => e => e.Left ? (
fl(e.Left)
) : fr(e.Right);
// jsonParseLR :: String -> Either String a
const jsonParseLR = s => {
// Either a message, or a JS value obtained
// from a successful parse of s.
try {
return Right(JSON.parse(s));
} catch (e) {
return Left(
`${e.message} (line:${e.line} col:${e.column})`
);
}
};
return main();
})();
Yes. Chris @ccstone showed you a great way if you need for the user to pick the shortcut. I use this method in a number of my Macros, and it works quite well, even with large (>1,000) lists in a file.
If you need to find the text for a given key, you can use a simple list (can be KM Variable or file) of one line for each key: <key>TAB<text>
and then search this list using RegEx.
I have a number of Macros that use this method, and it is easy to use, and very fast.
Let me know if you'd like more info.
Hi thanks for reply. I possibly didn't make it clear, but I don't want Keyboard Maestro to prompt me a for bird species. Instead I want Keyboard Maestro to use text I have selected as the bird species. Hopefully the attached screenshot makes it more clear.
I have spent last hour in Keyboard Maestro trying to figure out how to do this, but haven't been successful so far. Any advice would be appreciated.
(() => {
"use strict";
ObjC.import("AppKit");
// main :: IO ()
const main = () =>
either(
alert("Open page from clipboard")
)(
url => url
)(
bindLR(
clipTextLR()
)(
clip => bindLR(
jsonParseLR(
Application("Keyboard Maestro Engine")
.getvariable("jsonBirds")
)
)(
dict => {
const
url = dict[
toTitle(clip).trim()
] || "";
return url.startsWith("http") ? (
Right(url)
) : Left(`No link found for '${clip}'`);
}
)
)
);
// ----------------------- JXA -----------------------
// alert :: String => String -> IO String
const alert = title =>
s => {
const sa = Object.assign(
Application("System Events"), {
includeStandardAdditions: true
});
return (
sa.activate(),
sa.displayDialog(s, {
withTitle: title,
buttons: ["OK"],
defaultButton: "OK"
}),
s
);
};
// clipTextLR :: () -> Either String String
const clipTextLR = () => (
v => Boolean(v) && 0 < v.length ? (
Right(v)
) : Left("No utf8-plain-text found in clipboard.")
)(
ObjC.unwrap($.NSPasteboard.generalPasteboard
.stringForType($.NSPasteboardTypeString))
);
// --------------------- GENERIC ---------------------
// Left :: a -> Either a b
const Left = x => ({
type: "Either",
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: "Either",
Right: x
});
// bindLR (>>=) :: Either a ->
// (a -> Either b) -> Either b
const bindLR = m =>
mf => m.Left ? (
m
) : mf(m.Right);
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl =>
// Application of the function fl to the
// contents of any Left value in e, or
// the application of fr to its Right value.
fr => e => e.Left ? (
fl(e.Left)
) : fr(e.Right);
// jsonParseLR :: String -> Either String a
const jsonParseLR = s => {
// Either a message, or a JS value obtained
// from a successful parse of s.
try {
return Right(JSON.parse(s));
} catch (e) {
return Left(
`${e.message} (line:${e.line} col:${e.column})`
);
}
};
// toTitle :: String -> String
const toTitle = s =>
// NB this does not model any regional or cultural conventions.
// It simply simply capitalizes the first character of each word.
words(s)
.map(w => w[0].toUpperCase() + w.slice(1).toLowerCase())
.join(" ");
// words :: String -> [String]
const words = s =>
// List of space-delimited sub-strings.
s.split(/\s+/u);
return main();
})();
I like JSON strings, but don't find them that useful in KM. I use them mostly in JavaScripts.
IMO, it is easier to build and maintain a simple tab-delimited list than a complicated JSON string.
So, here is another solution that uses a tab-delimited list with RegEx (which is very fast) to lookup the text value for a given key.
I have also provided some options that are disabled for setting the source string and for selecting the key.
Below is just an example written in response to your request. You will need to use as an example and/or change to meet your workflow automation needs.
Demo how to use simple tab-delimited list with RegEx to find the text for a given key
HOW TO USE
First, make sure you have followed instructions in the Macro Setup below.
See the below "How to Use" Comment Action
This macro is just an example written in response to your request. You will need to use as an example and/or change to meet your workflow automation needs.
MACRO SETUP
Carefully review the Release Notes and the Macro Actions
Make sure you understand what the Macro will do.
You are responsible for running the Macro, not me. ??
. Make These Changes to this Macro
Assign a Trigger to this Macro .
Move this macro to a Macro Group that is only Active when you need this Macro.
ENABLE this Macro, and the Macro Group it is in.
For more info, see KM Wiki article on Macro Activation
.
REVIEW/CHANGE THE FOLLOWING MACRO ACTIONS:
(all shown in the magenta color)
If I was to use JSON for this sort of thing, I'd use Keyboard Maestro's built-in lookup mechanism – the only thing that's a trifle complex is getting the clipboard into the lookup token. You have to escape the delimiter characters and use a process tokens filter action for that.
I don't really like to use JSON for simple lookups like this, because it adds significant effort to maintaining a lookup table.
The method I prefer is to use a RegEx search of a tab-delimited text table, which can be in a Keyboard Maestro variable of offloaded to a text file. (For really big tables it's much more convenient to edit a text file than a KM variable.)