WOW! When did this happen? Triggering a Macro from JXA can return a result!

Did you know that you can call a macro from JXA code, and have the macro return a value back to JXA?

I swear this didn't used to work, but it does now.

Consider this macro:

image

 
And this JXA code:

(() => {

const kmEngine = Application("Keyboard Maestro Engine");
const result = kmEngine.doScript("My doScript Result Test Macro", { withParameter: "This is a test" });
console.log(result);
})()

Here's the console output:

This is a test - Returned

Mind. Blown. This is SO DAMN USEFUL!


5 Likes

I want to be excited about this! Can you give us a usage example?

LOL. I had a similar reaction to another post - looked cool, but I needed help understanding its coolness.

I think it's one of those things that you'll know when you need it. Anytime you're in JXA and need to get some information that KM could do better by itself.

One simple (if anything with JXA could be considered simple) example is if you have some JXA code that calls a macro, and that macro might encounter errors - now you can return the error back to the JXA code so it knows the macro failed.

I'll think on it and see if I come up with anything else that can be explained easily.

2 Likes

image

2 Likes

LOL.

1 Like

Returning values mainly allows, of course, for composition of larger assemblies from smaller ones.

On the face of it, we can do that within JavaScript anyway, with value-returning functions, but perhaps there might be arguments / uses for building complex macros from reusable atomic macros ?

On the other hand, that sounds pretty much like Keyboard Maestro's subroutines and blocks ...

Perhaps the most obvious application might be in calling JXA from the command line with

osascript -l JavaScript [-e *command*] [-s *flags*] ...

and getting back a command line value (or system effect) to which the Keyboard Maestro Engine has contributed ?

1 Like

Would I be dreadfully naïve to hope this might mean we could update KM (or AS) progress bars as part of a shell script?

I don't think this is related to that, but I'll bet you could do that now. I'm not sure how to code it, but someone will probably know how.

Here's an example of calling some KM macros from JXA, and handling the responses.

And yes, this workflow could also be done using just KM actions, but the point is to show some things you could do from JXA.

The macros whose names start with "Ω" are called from the JXA in the first macro.

JXA DoScript Examples Macros.kmmacros (11.3 KB)

Click to view the JXA source
(() => {

const kmEngine = Application("Keyboard Maestro Engine");

try {
	const result = getConfirmation("OK to continue?");
	if (result !== "OK")
		throw new Error("Canceled");

	const value = promptForValue(
		"Gimme Some Lovin'",
		"(Sorry, that song's been running through my head)",
		"I love you!");

	const msg = value != "" ? `Awwww, you said "${value}"!` : `Well, I still love you`;
	showMessage(msg);

	// I was going to limit this to certain file types,
	// but I wasn't sure what files people might have lying around,
	// so instead, I'm passing "" for the "Allowed Types" parameter.
	const filePath = promptForFile("Choose a File", "", "");
	if (!filePath)
		throw new Error("Canceled");

	showMessage(`File: ${filePath}`);

} catch (e) {
	showMessage(e.message);
}

return "";

// --------------------------------------------------------------

function doScript(script, parameter) {
	return kmEngine.doScript(script, { withParameter: parameter });
}

function getConfirmation(text) {
	return doScript("5234D271-B1F1-4883-9336-2E905FD4960C", text);
}

function showMessage(message) {
	doScript("98DFFAD4-4DAE-421A-B84B-9426BEE448CA", message);
}

function promptForValue(title, promptText, text) {
	const parameter = {
		Title: title,
		PromptText: promptText,
		Value: text
	};
	const result = doScript("631D1BDD-56A2-43BC-8A7B-F7C1A161665E", JSON.stringify(parameter));
	if (result.startsWith("Error:"))
		throw new Error(result);
	return result;
}

function promptForFile(title, allowedTypes, folder) {
	const parameter = {
		Title: title,
		AllowedTypes: allowedTypes,
		Folder: folder
	};
	return doScript("F71C6D85-5776-43A7-B141-9183401A53A3", JSON.stringify(parameter));
}

})()
3 Likes

Thanks for taking the time to put this together. :pray:t3:

1 Like

You could for example use a KM Macro as a Stream Deck Widget in BTT without saving the return value into a KM variable and then read that value from BTT.

Or basically every time you need a value from KM macro in another script. Could be done before but this way it's nicer :slight_smile: