CustomHTMLPrompt - Get KM Macro Response

CustomHTMLPrompt - Get KM Macro Response

REQUIRES

THE PROBLEM:

Custom HTML Prompts (hereafter referred to as "The Prompt") can trigger Keyboard Maestro macros using window.KeyboardMaestro.Trigger(). Unfortunately, this does not return a result. You can't get a response back using AppleScript, either.

THE SOLUTION:

When the Prompt triggers the macro, the macro can then use Execute JavaScript in Browser to return the result.

There's several ways to accomplish this, but here's a method that uses an asynchronous method so your code can use an "await", and it has a timeout in case the macro fails:

THE CODE:

Click to expand

In this code, I wrote a function called "roundTrip". It triggers the macro, and waits for the response. It includes a timeout for safety, in case the macro crashes.

Here's the basic code, without anything extraneous:

Button Element:

Clicking this button calls the btnTriggerClicked event.

<button id="btnTrigger" type="button" onclick="btnTriggerClicked()">Trigger</button>

Button Clicked Event:

This is an async function, which allows us to use the await keyword, so our code will stop and wait for the response.

async function btnTriggerClicked(action = "") {
	console.log(`btnTriggerClicked: triggering the macro and waiting for the response`);

	const result = await roundTrip();

	console.log(`btnTriggerClicked: Got result: "${result}"`);
}

function roundTrip()

This function sets up the parameter triggerData for the macro, then triggers the macro, then returns the result. It uses a timeout of 3000 ms, or 3 seconds.

async function roundTrip()  {
	try {
		var triggerData = {
			kmwindowid: "GetKMResponse CustomHTMLPrompt",
			text: "This is a test"
		};
		window.KeyboardMaestro.Trigger("4FE6B6EE-0583-4D1E-A5E4-1A12A86EA53C", JSON.stringify(triggerData));

		const result = await getResponse(3000);

		return result;
	} catch (e) {
		console.log(`Error in roundTrip: ${e.message}`);
		return null;
	}
}

function getResponse(timeout)

This is where the magic happens. You don't need to understand exactly how it works.

Suffice it to say that it sets up a timer for the timeout portion, and waits for a custom event we're calling "kmResponse".

function getResponse(timeout) {
	return new Promise(function(resolve, reject) {
		const timer = setTimeout(() => {
			document.removeEventListener('kmResponse', handleResponse);
			console.error(`Response timed out`);
			reject(new Error("Response timed out"));
		}, timeout);

		function handleResponse(e) {
			clearTimeout(timer);
			console.log(`event listener got response "${e.detail}"`);
			document.removeEventListener('kmResponse', handleResponse);
			resolve(e.detail);
		}

		document.addEventListener('kmResponse', handleResponse);
	});
}

function insertResponse(response)

This is what the macro calls using Execure JavaScript in Browser. The function takes the parameter, and fires off the custom event "kmResponse" that getResponse (above) is waiting for:

function insertResponse(response) {
	console.log(`insertResponse called with "${response}"`)
	document.dispatchEvent(new CustomEvent("kmResponse", { detail: response }));
}

The Macro

And finally, here's the macro:

image

INSTALLATION

UPGRADE INSTRUCTIONS:

  1. Delete the old macros, or just delete the entire group.
  2. Install the new macros.

Download the zip file, unzip it, and double-click the .kmmacros file.

CustomHTMLPrompt - Get KM Macro Response.v1.0.kmmacros.zip (5.1 KB)


5 Likes