A KM Prompt in a Python Script

Having played with using a KM "Progress" action to display the progress of a python script, the obvious next question is -- can we use a similar trick to get data into a script via a KM "Prompt for User Input" action?

Since I'm bothering to post this, you can probably guess the answer :wink:

We can make our macro in KM -- in this case collecting three values and "Return"ing them as three lines of text:

image

...then Copy the macro's XML:

...and strip the top and bottom so we are left with just the array of actions. Wrap that in a tell application "Keyboard Maestro Engine" to do script... and use the lot as an argument in a Python 3 subprocess call...

And here's the Python script, which will put up the prompt and print the three values entered in different ways:

pyPromptDemo.py
import time
import subprocess

theScript = """
tell application \"Keyboard Maestro Engine\" to do script \"<array>
		<dict>
			<key>ActionUID</key>
			<integer>100012895</integer>
			<key>Buttons</key>
			<array>
				<dict>
					<key>Button</key>
					<string>OK</string>
				</dict>
				<dict>
					<key>Button</key>
					<string>Cancel</string>
					<key>Cancel</key>
					<true/>
				</dict>
			</array>
			<key>MacroActionType</key>
			<string>PromptForUserInput</string>
			<key>Prompt</key>
			<string>Please enter the details for these variables.</string>
			<key>TimeOutAbortsMacro</key>
			<true/>
			<key>Title</key>
			<string>Enter your name and age</string>
			<key>Variables</key>
			<array>
				<dict>
					<key>Default</key>
					<string></string>
					<key>Type</key>
					<string>Automatic</string>
					<key>Variable</key>
					<string>Local_First Name</string>
				</dict>
				<dict>
					<key>Default</key>
					<string></string>
					<key>Type</key>
					<string>Automatic</string>
					<key>Variable</key>
					<string>Local_Surname</string>
				</dict>
				<dict>
					<key>Default</key>
					<string></string>
					<key>Type</key>
					<string>Automatic</string>
					<key>Variable</key>
					<string>Local_Age</string>
				</dict>
			</array>
		</dict>
		<dict>
			<key>ActionUID</key>
			<integer>100012900</integer>
			<key>MacroActionType</key>
			<string>Return</string>
			<key>Text</key>
			<string>%Variable%Local_First Name%\n%Variable%Local_Surname%\n%Variable%Local_Age%</string>
		</dict>
	</array>\"
	"""

theAnswer = subprocess.check_output(['osascript', '-e', theScript])
theAnswerList = theAnswer.decode('utf-8').split('\n')
print("First Name: " + theAnswerList[0])
print("Surname: " + theAnswerList[1])
print("Age: " + theAnswerList[2])
print()
print(theAnswerList[1] + ", " + theAnswerList[0] + " -- age " + theAnswerList[2])

When running the script from Terminal, the dialog pops for the user to fill:

...and back in Terminal:

image

Simples!

Obviously, if you want a full GUI when Pythoning you'll use Tkinter or similar. But if you only want the occasional dialog this method could come in handy...

<ObDisclaimer>
Even the above is a real stretch for my very limited Python skills -- I'm sure someone who knows what they are doing could improve this a lot!
</ObDisclaimer>

2 Likes

Whoa, this is a seriously cool trick, @Nige_S!

I love how you're calling a Keyboard Maestro prompt from inside a Python script. It's such a neat way to get user input without having to mess with extra libraries and their dependencies. I'm definitely going to play around with this.

I could see this being applied to other actions as well, like using "Prompt With List" and Prompt for Snippet to offer a set of choices or simple forms. It's a useful technique for building scripts that need a bit of user interaction while keeping things straightforward for anyone who might use or modify the macro.

Great stuff. Thanks for sharing these ideas!