Using KM variables in Yosemite Javascript for Applications (JXA)

The scripting references to Javascript in the KM Help file cover accessing KM variables through the document object in a browser context.

For the non-browser ‘JXA’ Javascript for Applications in Yosemite, you can do something like this:

function run() {

	var appKM = Application("Keyboard Maestro Engine"),
		lst = [],
		strList;

	appKM.variables().forEach(function (kmVar) {
		lst.push({
			'name': kmVar.name(),
			'value': kmVar.value(),
			'id': kmVar.id()
		});
	});

	strList = JSON.stringify(lst, undefined, 2);

	appKM.includeStandardAdditions = true;
	appKM.setTheClipboardTo(strList);

	return "Formatted JSON listing of KM variables in Clipboard";
}
3 Likes

EXAMPLE (Reading and toggling a KM VAR boolean flag from JXA Javascript)

function run() {

	var strKMVarName = "debug";

	var appKM = Application("Keyboard Maestro Engine"),
		oVars = appKM.variables,
		oFlag,
		blnFlag;


	function findOrMakeKMVar(strName) {
		
		try {
			oVars[strName].name();
		} catch (e) {
			appKM.variables.push(
				appKM.Variable({
					'name': strName
				})
			);
		}
		return oVars[strName];
	}

	function jsBool(strBool) {
		return strBool === "true";
	}

	// GET A REFERENCE TO A KM VARIABLE BY NAME
  // ( CREATING THE KM VAR IF NOT FOUND )
  
	oFlag = findOrMakeKMVar(strKMVarName);

	// READ THE VALUE OF THE KM VAR (as a .js Boolean)
	blnFlag = jsBool(oFlag.value());

	// TOGGLE ITS VALUE
	oFlag.value = !blnFlag;

	// RETURN THE TOGGLED RESULT
	return oFlag.value();

}
1 Like

Thanks! This is very good to know. I’m experimenting with JXA since I read a post about it, but still can’t fully wrap my head around it.

You may already have seen it, but if not I think the JXA Cookbook is a useful resource.

1 Like

FOOTNOTE:

Listing and reading the values of Keyboard Maestro variables without using

Application("Keyboard Maestro Engine")

As an alternative (particularly if any other environment variables also interest us) we can inspect environment variables directly from JXA with:

$.NSProcessInfo.processInfo.environment

Some sample functions:

// Javascript dictionary representing key:values in the OS X environment
var dctEnv = ObjC.unwrap($.NSProcessInfo.processInfo.environment)

// The value (if any) of a variable by its name in KeyBoard Maestro
function kmValue (strKMname, dctEnv) {
	var dctEnv = dctEnv || ObjC.unwrap($.NSProcessInfo.processInfo.environment)
	return ObjC.unwrap(dctEnv[shellName(strKMname)]) || null;
}

// Alphabetically sorted list of Keyboard Maestro variables
function kmVars(dctEnv) {
	var dctEnv = dctEnv || ObjC.unwrap($.NSProcessInfo.processInfo.environment),
		isKMVar = function(x) {return x.indexOf('KMVAR_') === 0};
	
	return Object.keys(dctEnv).filter(isKMVar).sort().map(kmName);
}

// A dictionary containing only the Keyboard Maestro subset of environment variables,
// keyed by their KM native names rather than by their shell names, with their values
function kmDict(dctEnv) {
	var dctEnv = dctEnv || ObjC.unwrap($.NSProcessInfo.processInfo.environment),
		isKMVar = function(x) {return x.indexOf('KMVAR_') === 0},
		dctKM = {};
	
	Object.keys(dctEnv).forEach(
		function (k) {
			if (isKMVar(k)) {dctKM[kmName(k)] = ObjC.unwrap(dctEnv[k])};
		}
	);
	
	return dctKM;
}

// "KMVAR_Some_variable_name" --> "Some variable name"
function shellName(strVarName) {
	return "KMVAR_" + strVarName.replace(' ', '_');
}

// "Some variable name" --> "KMVAR_Some_variable_name"
function kmName(strShellName) {
	return strShellName.slice(6).replace('_', ' ');
}

// return a dictionary of KM Variable key:value pairs
kmDict()

Updated the gist on reading and writing KM variables to avoid dependence on (try ... catch) error handling when checking whether a variable exists.

// Get a reference to a Keyboard Maestro variable (existing or new)
function kmVar(k) {
	var	kme = Application("Keyboard Maestro Engine"),
		vs = kme.variables,
		vks = vs.where({name:k});
			
	return vks.length ? vks[0] :
		vs.push(kme.Variable({'name': k})) && vs[k];
}

With 7.1 you can now access Keyboard Maestro variables from JXA using the newly simplified AppleScript interface:

var kme = Application("Keyboard Maestro Engine");
kme.getvariable('Var');
kme.setvariable('Var', { to: "Hello World!" });
4 Likes