Not “any app” but “any running apps”
Maybe I'm blind, but I cannot find the Action you show in your image. I have searched in the KM Editor and in the KM wiki and don't see it. In the KM Editor, what Category is this action in, and what is the exact name of it as it appears there?
It’s the “Manipulate a Window” action.
I would never have guessed, and although the options (operations) are listed in the KM Wiki, they seem easy to overlook (at least to me).
For everyone's benefit, here are the main options of the Manipulate a Window Action:
In my opinion it’s more convenient to manipulate windows with BetterTouchTool and gestures with magic mouse.
Hey Leonardo,
That's doable with AppleScript and System Events.
--------------------------------------------------------
# Edited 2023/03/08 01:22 CST
# Bring Named Window Forward.
--------------------------------------------------------
set searchString to text returned of (display dialog "Enter a Window Name:" default answer "")
set winNameList to {}
tell application "System Events"
repeat with theApp in (processes whose background only is false)
tell theApp
set appName to its name
set winList to name of (windows whose name contains searchString)
end tell
if length of winList > 0 then
repeat with winName in winList
set contents of winName to (contents of winName) & tab & " --» " & tab & appName
end repeat
set winNameList to winNameList & winList
end if
end repeat
end tell
if winNameList ≠ {} then
set theWindow to choose from list winNameList ¬
with title "Windows With Designated Name" with prompt ¬
"Pick One:" default items {item 1 of winNameList} ¬
without empty selection allowed
if theWindow ≠ false then
set theWindow to item 1 of theWindow
set AppleScript's text item delimiters to tab & " --» " & tab
set {theWindow, theApp} to (get text items of theWindow)
tell application "System Events"
tell process theApp
set frontmost to true
tell window theWindow
perform action "AXRaise"
end tell
end tell
end tell
end if
else
beep
end if
--------------------------------------------------------
Try it from the Script Editor.app.
If you install Shane Stanley's MyriadTables Library I could even make it halfway pretty.
-Chris
This is awesome, I can’t believe you took the time to do it Chris. Thank you so much, I hope others find this useful!
Very nice script, Chris. Thanks for sharing.
That would be a real treat!
Just for fun and parallel reading, a very stripped-down JavaScript version which jumps straight into activating the first match found, without offering a menu of options:
(function () {
'use strict';
var a = Application.currentApplication(),
se = Application("System Events"),
sa = (a.includeStandardAdditions = true, a),
o = ObjectSpecifier();
var lstWins = [].concat.apply(
[], se.processes.whose({
_match: [o.backgroundOnly, false]
})
.windows.whose({
_match: [o.name, {
_contains: sa.displayDialog("Window name:", {
withTitle: "Activate window by name",
defaultAnswer: '',
})
.textReturned
}]
})()
),
oWin = lstWins.length ? lstWins[0] : undefined;
if (oWin) {
se.perform(oWin.actions.byName('AXRaise'));
}
})();
Or a version which at least offers a simple menu for single or multiple selections:
• Ver 03: updated to make app of raised window frontmost, and add app name to menu
// ver 0.4 brings single matches straight to the front
// ver 0.3 includes app name (before window name) in menu
// ver 0.2 makes app frontmost, as well as raising window
(function () {
'use strict';
function raiseWin(oWin, appSE) {
(appSE || Application("System Events"))
.perform(oWin.actions.byName('AXRaise'));
oWin.attributes.byName('AXParent')
.value()
.frontmost = true;
}
var strTitle = "Activate windows by name",
a = Application.currentApplication(),
se = Application("System Events"),
sa = (a.includeStandardAdditions = true, a),
o = ObjectSpecifier();
a.activate();
var strText = sa.displayDialog("Part of window name:", {
withTitle: strTitle,
defaultAnswer: '',
})
.textReturned,
lstWins = [].concat.apply(
[], se.processes.whose({
_match: [o.backgroundOnly, false]
})
.windows.whose({
_match: [o.name, {
_contains: strText
}]
})()
),
lngWins = lstWins.length;
// VARIANT: OFFER MENU WHEN MATCHES ARE MULTIPLE
if (lngWins > 0) {
if (lngWins > 1) {
var lstNames = lstWins.map(function (w) {
return w.attributes.byName('AXParent')
.value.name() + ' > ' + w.name();
}),
varChoice = sa.chooseFromList(lstNames, {
withTitle: strTitle,
withPrompt: "Matching '" + strText + "'",
defaultItems: lstNames[0],
multipleSelectionsAllowed: true
});
if (varChoice) {
varChoice.map(function (s) {
return lstNames.indexOf(s)
})
.forEach(function (i) {
raiseWin(lstWins[i], se);
});
}
} else raiseWin(lstWins[0], se);
}
})();
Thanks for sharing, Rob.
I really appreciate translations of AppleScript to JXA. They really help my learning of JXA.
I hope you won't mind a few questions (if any) that I may have after reviewing and testing your JXA code.
This is heaps cool, I just found out about the “Execute Javascript for automation” action. Thanks for sharing!
Ver 0.2 updated (above) to make app of raised window frontmont
Thanks to Chris Stone for providing the AXParent attribute
route from window to app
Manipulate a Window is richer than most other software tools by themselves! I’m still posting questions that get answers pointing to Manipulate a Window, and I’ve been using KM since QuicKeys toppled over years ago.
I’m trying to follow the script and it looks like KBM is hard-coded. Before I try running it, I want to be able to at least read through it, and I'm stumbling.
I think there are a couple of changes that need to me made:
- comment out the line that sets
winName
to KBM - replace the KBM in the phrase "
whose name contains ...
" withwinName
. (I'm not sure what punctuation may be needed arouindwinName
.)
Is that correct? Is there anywhere else where the script is still in testing mode?
I seem to have flubbed that a bit. (Original fixed as well.)
-ccs
--------------------------------------------------------
# Bring Named Window Forward.
--------------------------------------------------------
set searchString to text returned of (display dialog "Enter a Window Name:" default answer "")
set winNameList to {}
tell application "System Events"
repeat with theApp in (processes whose background only is false)
tell theApp
set appName to its name
set winList to name of (windows whose name contains searchString)
end tell
if length of winList > 0 then
repeat with winName in winList
set contents of winName to (contents of winName) & tab & " --» " & tab & appName
end repeat
set winNameList to winNameList & winList
end if
end repeat
end tell
if winNameList ≠ {} then
set theWindow to choose from list winNameList ¬
with title "Windows With Designated Name" with prompt ¬
"Pick One:" default items {item 1 of winNameList} ¬
without empty selection allowed
if theWindow ≠ false then
set theWindow to item 1 of theWindow
set AppleScript's text item delimiters to tab & " --» " & tab
set {theWindow, theApp} to (get text items of theWindow)
tell application "System Events"
tell process theApp
set frontmost to true
tell window theWindow
perform action "AXRaise"
end tell
end tell
end tell
end if
else
beep
end if
--------------------------------------------------------
In terms of the OP original question, the current version of Manipulate a Window requires that the app of the window being manipulated either be the app that owns the frontmost window or the app must be chosen from a menu while the macro is being written.
@peternlewis, would it be possible to add an option to Manipulate a Window to allow the action to identify the app on the fly, like it does with "Frontmost", and to pick the app based on a variable containing a text string of the app name?
Thanks for the update. (Seven years?)
And counting...
I hate to tell you this, but the script isn't working for me. It's taking a hugely long time to run, minutes not seconds.
I took the above script and pasted it into an Execute AppleScript action in a new macro. I ran the macro. At the text-field prompt I typed "9" because I happen to know that there is a TextEdit window on my current desktop named "Untitled 9.rtfd
". I got the Multicolored Beachball of Death. Repeatedly, even after giving System Events permission through Accessibility to control the computer.
I guessed that it could have something to do with AXRaise, maybe because I'm on Mojave. So I started researching AXRaise.
It turned out that I had let the beachball spin while I was researcing because after a few minutes I got the choice prompt, showing the one TextEdit window. I picked it and it popped to the front. So it's not AXRaise.
And BTW, will this method work to find windows on other desktops (workspaces, not just multiple display screens)?