I searched for “group current app” and found
It does what I want, except that the group must already exist. How can I make it create a new group named for the current app and open that if I the group doesn’t already exist?
I searched for “group current app” and found
It does what I want, except that the group must already exist. How can I make it create a new group named for the current app and open that if I the group doesn’t already exist?
Here's a modified version of that macro that should do what you want (requires Keyboard Maestro 8):
Go-To:Create Front-App's Group in Keyboard Maestro v1.1.kmmacros (5.2 KB)
If you'd rather just change the AppleScript that powers it in the version you have, you can do that by copying it here:
--------------------------------------------------------------------------------
# Auth: Christopher Stone
# Mod: Gabe Glick
# dCre: 2016/11/14 16:15
# dMod: 2017/12/2 09:39
# Appl: Keyboard Maestro Editor
# Task: Select the first group whose name matches the name of the front application, and create it if it doesn't exist.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @System_Events, @Select, @Group, @Front, @Application
--------------------------------------------------------------------------------
try
tell application "System Events"
set procName to name of first process whose frontmost is true
end tell
tell application "Keyboard Maestro"
activate
if (exists of macro group procName) = false then
set newGroup to make new macro group with properties {name:procName}
select newGroup
else
select macro group procName
end if
end tell
on error e number n
set e to e & return & return & "Num: " & n
if n ≠ -128 then
try
tell application (path to frontmost application as text) to set ddButton to button returned of ¬
(display dialog e with title "ERROR!" buttons {"Copy Error Message", "Cancel", "OK"} ¬
default button "OK" giving up after 30)
if ddButton = "Copy Error Message" then set the clipboard to e
end try
end if
end try
--------------------------------------------------------------------------------
I can't take much credit for this, as this is all scripting that @ccstone did originally; I just copied AppleScript code he wrote for a different macro and tweaked it where appropriate for this one. It worked well enough in my own testing, but let us know if you run into issues with it, or need a version that works with KM7.
Thank you, Gabe, it’s just what I needed.
Hey Guys,
This method will be a trifle faster than using System Events:
----------------------------------------------------------------
# Faster than using System Events
----------------------------------------------------------------
set AppleScript's text item delimiters to {".app:", ":"}
set frontApp to (path to frontmost application as text)
set frontApp to text item -2 of frontApp
----------------------------------------------------------------
You also run into the problem of macro groups not being named exactly the same as the frontmost application, so I’ve used name contains <process name> to provide more leeway.
If more than one group is found a pick-list is presented to the user.
NOTE — I’m not creating the group as Gabe did above — just pointing out one of the pitfalls of this type of script.
----------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2017/12/02 03:42
# dMod: 2017/12/02 03:47
# Appl: Keyboard Maestro
# Task: Go to Macro Group Associated with the frontmost app.
# : Present pick-list if more than one group is found.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro, @Group, @Associated, @Frontmost, @App, @Pick-List
----------------------------------------------------------------
# Faster than using System Events
----------------------------------------------------------------
set AppleScript's text item delimiters to {".app:", ":"}
set frontApp to (path to frontmost application as text)
set frontApp to text item -2 of frontApp
----------------------------------------------------------------
tell application "Keyboard Maestro"
activate
set macroGroup to name of macro groups whose name contains frontApp
if length of macroGroup is 1 then
select macro group (item 1 of macroGroup)
else
# Presents a pick-list if more than one group is found.
set theChoice to choose from list macroGroup with title "Macro Group List" with prompt "Pick a Group to Select" default items {item 1 of macroGroup} without empty selection allowed
if theChoice is not false then
set theChoice to item 1 of theChoice
select macro group theChoice
end if
end if
end tell
----------------------------------------------------------------
Here’s a prettified list of the macro group result I get for Script Debugger:
{
"Script Debugger { JM }",
"Script Debugger 5",
"Script Debugger 6"
}
Most of my application groups are named exactly the same as the app, but there are a few that will yield multiple hits.
In my own go-to-macro-group script I’ve mapped these to a preferred macro-group rather than fooling with a pick-list.
Here’s one good reason to use System Events instead of the method above:
tell application "System Events"
tell (first process whose frontmost is true)
set frontAppBundleID to bundle identifier
set frontAppName to name
end tell
end tell
{frontAppName, frontAppBundleID}
Many apps are sensible enough to change the Bundle Identifier when a major version change occurs.
For instance:
Script Debugger 5
{
"Script Debugger",
"com.latenightsw.ScriptDebugger5"
}
Script Debugger 6
{
"Script Debugger",
"com.latenightsw.ScriptDebugger6"
}
By getting the Bundle Identifier you can easily discriminate between versions.
Unfortunately not all developers are as well behaved as Mark Alldritt, so this method isn’t infallible.
You can usually get adequate information out of the Finder and/or System Events:
----------------------------------------------------------------
tell application "System Events"
tell (first process whose frontmost is true)
set frontAppBundleID to bundle identifier
set frontAppName to name
end tell
end tell
tell application "Finder"
set appAlias to application file id frontAppBundleID as alias
end tell
tell application "System Events"
set appVersion to short version of appAlias
end tell
set frontAppName to frontAppName & space & appVersion
--> "Script Debugger 6.0.6"
----------------------------------------------------------------
But sometimes you might need a secret string like the CFBundleVersion hidden in the Info.plist of an app.
----------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2017/12/02 04:30
# dMod: 2017/12/02 04:39
# Appl: Frontmost Application
# Task: Get App Name, Short Version, and Bundle Version
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @App, @Name, @Short, @Version, @Bundle
----------------------------------------------------------------
use AppleScript version "2.4" -- Yosemite or later
use framework "Foundation"
use scripting additions
----------------------------------------------------------------
set AppleScript's text item delimiters to {".app/", "/"}
set frontAppPath to POSIX path of (path to frontmost application as text)
set frontAppName to text item -2 of frontAppPath
----------------------------------------------------------------
set plistPath to frontAppPath & "Contents/Info.plist"
set theDict to current application's NSDictionary's dictionaryWithContentsOfFile:plistPath
set shortVersionString to (theDict's valueForKeyPath:"CFBundleShortVersionString") as text
set bundleVersion to (theDict's valueForKeyPath:"CFBundleVersion") as text
return frontAppName & space & shortVersionString & space & "(" & bundleVersion & ")"
----------------------------------------------------------------
--> "Script Debugger 6.0.6 (6A212)"
----------------------------------------------------------------
Are your eyes crossed yet?
The bottom line?
One way or another this job can be done in a way that should satisfy most users.
** Ha! It’s later than I thought — so if I’ve rambled any it’s 'cause I’m a little tired.
-Chris
Thanks for weighing in, Chris! This was highly educational as always, and I can confirm that the speed difference in not using System Events to acquire the front app’s name is consistent and noticeable.
Hey Guys,
@JMichaelTX came up with a clever idea.
This script will get the macro groups that are associated with the name of the frontmost app, regardless of whether the group name contains the app name or not.
----------------------------------------------------------------
# Auth: @JMichaelTX - altered a bit by @ccstone
# dCre: 2017/12/02 15:34
# dMod: 2017/12/03 01:37
# Appl: Keyboard Maestro
# Task: Get Macro Group(s) of the frontmost application.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro, @KM, @Get, @Macro, @Group, @Frontmost, @Application
----------------------------------------------------------------
# Use the Keyboard Maestro Engine to get the name of the frontmost app.
# - This technique is much faster than using System Events.
tell application "Keyboard Maestro Engine" to set appName to process tokens "%Application%1%"
tell application "Keyboard Maestro"
set macroGroupList to macro groups whose available application xml contains appName
end tell
----------------------------------------------------------------
Thumbs-up to JM; that was a really smart idea.
Okay, let’s just run with that ball…
The XML of the Macro Group contains the Bundle ID of the app it’s associated with, so we can do something like this:
----------------------------------------------------------------
tell application "System Events" to set frontAppBundleID to bundle identifier of first process whose frontmost is true
tell application "Keyboard Maestro"
activate
set foundMacroGroups to macro groups whose available application xml contains frontAppBundleID
set frontAppGroup to item 1 of foundMacroGroups
select frontAppGroup
end tell
----------------------------------------------------------------
In my case I’m probably going to want to select a single group most of the time, however we can get creative and do something like this to select one or more found groups:
----------------------------------------------------------------
tell application "System Events" to set frontAppBundleID to bundle identifier of first process whose frontmost is true
tell application "Keyboard Maestro"
activate
set foundMacroGroups to select (macro groups whose available application xml contains frontAppBundleID)
end tell
----------------------------------------------------------------
This macro will select all Macro Groups that contain the Bundle ID of the frontmost app.
-Chris
Wow, way to go @JMichaelTX and Chris! I would never have guessed that using KM tokens to acquire the app name would be so fast, and using the XML to check for groups that are only available for the app name regardless of what the group is named really is a super smart idea. Thank you both for the illuminating examples!
I replaced my shortcut for launching Keyboard Maestro (⌥⌘↩) with a macro based on this:
try
set AppleScript's text item delimiters to {".app/", "/"}
set frontAppPath to POSIX path of (path to frontmost application as text)
set procName to text item -2 of frontAppPath
tell application "Keyboard Maestro"
activate
if (exists of macro group procName) = false then
set newGroup to make new macro group with properties {name:procName}
select newGroup
else
select macro group procName
end if
end tell
on error e number n
set e to e & return & return & "Num: " & n
if n ≠ -128 then
try
tell application (path to frontmost application as text) to set ddButton to button returned of ¬
(display dialog e with title "ERROR!" buttons {"Copy Error Message", "Cancel", "OK"} ¬
default button "OK" giving up after 30)
if ddButton = "Copy Error Message" then set the clipboard to e
end try
end if
end try
However, I’m really not trying to turn Keyboard Maestro into QuicKeys, I promise.
I modified your amazing macro to also include an action to instantly bring focus to macros. It's bette this way I think.
Here is the macro:
goto km group of the app.kmmacros (30.1 KB)
Thank for the kind words, @nikivi! This is a great idea, and fortunately, the version you posted can be optimized to be even faster. Here's a modified version that includes the AppleScript-only way (i.e. without using System Events) of getting the front app name that Chris suggested in post 4, and uses the new-to-KM8 (at least, I think it is) View > Select Macros Column menu command in a Select or Show Menu Item action instead of Chris's GUI script, which is no longer needed now that we have this native menu command, to bring focus to the macro. In my tests, the older version took on average 0.72 seconds to complete and this version takes 0.38 seconds, making it almost twice as fast:
goto km group of the app.kmmacros (30.4 KB)
I've left the timing actions I used to test the elapsed time in the macro (disabled by default) in case you'd like to test the difference for yourself. Thanks again for the smart idea on how to improve it!
I used Nikita's suggestion to focus the selection on macros and JM's and Chris Stone's idea of selecting all relative groups, and wound up with this.
set AppleScript's text item delimiters to {".app/", "/"}
set frontAppPath to POSIX path of (path to frontmost application as text)
set procName to text item -2 of frontAppPath
tell application "Keyboard Maestro"
launch
set tester to (exists of macro group procName)
end tell
if tester then
tell application "System Events" to set frontAppBundleID to bundle identifier of first process whose frontmost is true
tell application "Keyboard Maestro"
activate
set foundMacroGroups to select (macro groups whose available application xml contains frontAppBundleID)
end tell
else
tell application "Keyboard Maestro"
activate
set newGroup to make new macro group with properties {name:procName}
select newGroup
end tell
end if
Nice idea, @Lantro! This inspired me to tweak it a bit more and see if I could also accommodate for scenarios where groups that include the front app's bundle ID exist, but are not named after that app (for example, I have all the Microsoft Office apps lumped together in a single Office group, so I don't want the script making a new group for Excel), and I think I managed to come up with something that works and takes into account all of the ideas presented here. By default, this version presents a pick-list for cases where multiple macro groups contain either the name or bundle ID of the front app, but I've also included a script action to select all macro groups with the front app's bundle ID so that users can use whichever one they like:
Open KM in Group for Front App v1.3.kmmacros (8.5 KB)
[details=Show Code]
----------------------------------------------------------------
# Auth: Christopher Stone, @JMichaelTX, Laine Lee, Gabe Glick
# dCre: 2017/12/06 18:30
# Appl: Keyboard Maestro
# Task: Go to all macro groups associated with the frontmost app.
# : Create new macro group if none exists.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro, @Group, @Associated, @Frontmost, @App
----------------------------------------------------------------
try
tell application "System Events"
tell (first process whose frontmost is true)
set frontAppBundleID to bundle identifier
set frontAppName to name
end tell
end tell
tell application "Keyboard Maestro"
launch
set XMLtester to (exists of (macro groups whose available application xml contains frontAppBundleID))
set nameTester to (exists of macro group frontAppName)
end tell
if XMLtester = true then
tell application "Keyboard Maestro"
activate
set foundMacroGroups to select (macro groups whose available application xml contains frontAppBundleID)
end tell
else if nameTester = true then
tell application "Keyboard Maestro"
activate
set foundMacroGroups to select (macro groups whose name contains frontAppName)
end tell
else
tell application "Keyboard Maestro"
activate
set newGroup to make new macro group with properties {name:frontAppName}
select newGroup
end tell
end if
on error e number n
set e to e & return & return & "Num: " & n
if n ≠ -128 then
try
tell application (path to frontmost application as text) to set ddButton to button returned of ¬
(display dialog e with title "ERROR!" buttons {"Copy Error Message", "Cancel", "OK"} ¬
default button "OK" giving up after 30)
if ddButton = "Copy Error Message" then set the clipboard to e
end try
end if
end try
----------------------------------------------------------------
```[/details]
###Pick-List Version AppleScript
[details=Show Code]
```applescript
----------------------------------------------------------------
# Auth: Christopher Stone, @JMichaelTX, Laine Lee, Gabe Glick
# dCre: 2017/12/06 18:48
# Appl: Keyboard Maestro
# Task: Go to all macro groups associated with the frontmost app.
# : Create new macro group if none exists.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Keyboard_Maestro, @Group, @Associated, @Frontmost, @App
----------------------------------------------------------------
try
tell application "System Events"
tell (first process whose frontmost is true)
set frontAppBundleID to bundle identifier
set frontAppName to name
end tell
end tell
tell application "Keyboard Maestro"
launch
set XMLtester to (exists of (macro groups whose available application xml contains frontAppBundleID))
set nameTester to (exists of macro group frontAppName)
end tell
if XMLtester = true then
tell application "Keyboard Maestro"
activate
set macroGroup to name of macro groups whose available application xml contains frontAppBundleID
if length of macroGroup is 1 then
select macro group (item 1 of macroGroup)
else
# Presents a pick-list if more than one group is found.
set theChoice to choose from list macroGroup with title "Macro Group List" with prompt "Pick a Group to Select" default items {item 1 of macroGroup} without empty selection allowed
if theChoice is not false then
set theChoice to item 1 of theChoice
select macro group theChoice
end if
end if
end tell
else if nameTester = true then
tell application "Keyboard Maestro"
activate
set macroGroup to name of macro groups whose name contains frontAppName
if length of macroGroup is 1 then
select macro group (item 1 of macroGroup)
else
# Presents a pick-list if more than one group is found.
set theChoice to choose from list macroGroup with title "Macro Group List" with prompt "Pick a Group to Select" default items {item 1 of macroGroup} without empty selection allowed
if theChoice is not false then
set theChoice to item 1 of theChoice
select macro group theChoice
end if
end if
end tell
else
tell application "Keyboard Maestro"
activate
set newGroup to make new macro group with properties {name:frontAppName}
select newGroup
end tell
end if
on error e number n
set e to e & return & return & "Num: " & n
if n ≠ -128 then
try
tell application (path to frontmost application as text) to set ddButton to button returned of ¬
(display dialog e with title "ERROR!" buttons {"Copy Error Message", "Cancel", "OK"} ¬
default button "OK" giving up after 30)
if ddButton = "Copy Error Message" then set the clipboard to e
end try
end if
end try
----------------------------------------------------------------
```[/details]
Thank you to everyone who posted here for all the great ideas!