Activate Application by Name String

This variant of the built-in Activate a specific application action allows you to specify/change the name of the application to be activated at run-time, for example from a variable or clipboard.

Activate an Application by Name.zip (7.6 KB)

Custom Keyboard Maestro Plug-in

NAME

  • Activate an Application by Name

VERSION

  • 0.1

SYNOPSIS

  • Activates a specific application by its name, which can be specified at run-time, for example from a KM variable.
  • Offers the same set of options as the built-in Activate a Specific Application action

REQUIREMENTS

  • Yosemite
    • The core script activatedApp.sh is mainly written in Javascript for Applications

OPTIONS

  • Name of Application
    • Full application name, for example Google Chrome rather than just Chrome, or Microsoft Excel rather than just Excel.
    • If the name is not correctly spelled, or the named application is not installed, the action will give a brief notification, using the system Sosumi sound.
  • All windows ? (checkbox)
  • Reopen initial windows ? (checkbox)
  • If already at the front:
    • leave it at the front
    • switch to last application
    • hide the application
    • quit the application
  • Results
    • If the application is found, the results (which can be ignored, displayed or captured in variable or clipboard) will consist of the Keyboard Maestro XML (as in a .kmactions or .kmmacros file) corresponding to this action and set of options.
    • This XML can be pasted into code and executed by the Keyboard Maestro Engine .doScript() function.
    • Menu of result-handling options
      • Ignore results
      • Display results in a window
      • Display results briefly
      • Save results to variable
      • Save results to clipboard

INSTALLATION

  • Drag the .zip file onto the Keyboard Maestro icon in the OS X toolbar.
  • (if updating a previous version of the action, first manually remove the previous copy from the custom actions folder)
    • ~/Library/Application Support/Keyboard Maestro/Keyboard Maestro Actions

CONTACT

13 Likes

For reference – the unminified .js source of the plugin.

( Assembles and then executes some .kmactions XML )

// Activate named application
// Custom action plugin for Keyboard Maestro 7 on OS X 10.10+
// Rob Trew twitter: @ComplexPoint 2015

(function (strAppName, strAll, strReopen, strAlready) {
  strAppName = strAppName || "Finder";
  strAlready = strAlready || "leave it at the front";


  // ITS BUNDLE ID, AND APP FILE PATH ?
  var fnHotAppDetails = function (strAppName) {
      // running app ...
      var procs = Application(
          "System Events"
        ).applicationProcesses.where({
          name: strAppName
        }),
        procApp = procs.length ? procs[0] : null;

      return procApp ? {
        id: procApp.bundleIdentifier(),
        path: procApp.file.posixPath().toString()
      } : null
    },

    fnColdAppDetails = function (strAppName) {
      // unlaunched app ...
      var a = Application.currentApplication(),
        sa = (a.includeStandardAdditions = true, a),
        lst;

      try {
        lst = sa.doShellScript(
          [
            'osascript <<AS_END 2>/dev/null',
            'set strID to id of application "' + strAppName + '"',
            'tell application "Finder"',
            ' set strPath to POSIX path of (application file id strID as alias)',
            'end tell',
            'strID & linefeed & strPath',
            'AS_END'
          ].join('\n')
        ).split(/[\r\n]+/);
      } catch (e) {
        lst = [];
      }

      return (lst.length > 1) ? {
        id: lst[0],
        path: lst[1]
      } : null;
    },

    fnDoAction = function (dctAction) {
      // XML FOR KM ACTION DICTIONARY
      var dctXMLfn = {
          array: function (a) {
            return a.length ? "<array>" + a.reduce(function (a, c) {
              return a + dctXMLfn[typeof c](c);
            }, "") + "</array>" : "<array/>";
          },
          boolean: function (a) {
            return a ? "<true/>" : "<false/>";
          },
          dict: function (a) {
            var b = Object.keys(a);
            return "<dict>" + (b.sort() && b).reduce(function (c, b) {
              var d = a[b];
              return c + "<key>" + b + "</key>" + dctXMLfn[typeof d](d);
            }, "") + "</dict>";
          },
          number: function (a) {
            return "<real>" + (a ? a : "0.0") + "</real>";
          },
          object: function (a) {
            return dctXMLfn[a instanceof Array ? "array" : "dict"](a);
          },
          string: function (a) {
            return "<string>" + a + "</string>";
          }
        },
        strXML = dctXMLfn['dict'](dctAction);

      return Application("Keyboard Maestro Engine").doScript(
        strXML
      ) || strXML;
    },

    dctApp = fnHotAppDetails(
      strAppName
    ) || fnColdAppDetails(
      strAppName
    ),
    strID = dctApp ? dctApp.id : null;

  return fnDoAction(
    strID ? {
      "AllWindows": (strAll === '1'),
      "AlreadyActivatedActionType": ({
        'leave it at the front': 'Normal',
        'switch to last application': 'SwitchToLast',
        'hide the application': 'Hide',
        'quit the application': 'Quit'
      })[strAlready],
      "Application": {
        "BundleIdentifier": strID,
        "Name": strAppName,
        "NewFile": dctApp.path
      },
      MacroActionType: "ActivateApplication",
      ReopenWindows: (strReopen === '1')
    } : {
      'MacroActionType': 'Notification',
      'SoundName': 'Sosumi',
      'Subtitle': 'Application not found as spelled',
      'Text': 'Custom KM Action: Activate application by name',
      'Title': '"' + strAppName + '"'
    }
  );

})(
  "$KMPARAM_Activate",
  "$KMPARAM_All_windows",
  "$KMPARAM_Reopen_initial_windows",
  "$KMPARAM_If_already_at_the_front"
);
2 Likes

Hey Rob! Great Plugin! :+1:
Many thanks.

This is what I call just-in-time-programming!

I was just building the iPhone Phone Dialer, and wanted to return to the app where I got the number from. After checking out all of the Application Actions and searching the wiki, I was very frustrated. :frowning:
Luckily, I searched the forum and found your wonderful Action plugin.
Built to my spec! LOL

So, I D/L it and plugged it in, and it works great!

Thanks again for all the great work and sharing you do in this forum.
You are a tremendous resource, my friend.

1 Like

Dropping in almost four years later to say this is exactly what I was just hoping existed somewhere, so that I could tell macros to open URLs with %Variable%my_default_browser%; thank you so much!

1 Like

I've been trying to get this to work under Big Sur and KM 9, but it doesn't seem to.

Yes, I'm seeing that too. I'll take a look.

In JavaScript, code like that below still works.

All we need to do, in principle, is replace details like the com.apple.finder bundle identifier used below for the Finder with those of some other application.

(() => {
    "use strict";

    const main = () => {
    
    const xml = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>AllWindows</key>
        <true/>
        <key>AlreadyActivatedActionType</key>
        <string>Normal</string>
        <key>Application</key>
        <dict>
            <key>BundleIdentifier</key>
            <string>com.apple.finder</string>
            <key>Name</key>
            <string>Finder</string>
            <key>NewFile</key>
            <string>/System/Library/CoreServices/Finder.app</string>
        </dict>
        <key>MacroActionType</key>
        <string>ActivateApplication</string>
        <key>ReopenWindows</key>
        <false/>
        <key>TimeOutAbortsMacro</key>
        <true/>
    </dict>
</array>
</plist>`

        Application("Keyboard Maestro Engine").doScript(xml);
        
    }

This gift just keeps on giving! And still at ver 0.1..that says good things about both you and Keyboard Maestro

Just what I needed this morning, thanks again. (Seems to be working okay in Monterey…)

Just what I was looking for :+1:

Would something like this be possible for Type a Keystroke or Select a Menu Item?

I'm trying to use a For Each loop to check whether each app is full screen or not and set any apps that aren't to fullscreen in the background. Would be useful after restarting with many apps open when they tend to re-open in not-full-screen mode.

Cheers