How can I set focus to a specific window of a given application using applescript?
I have several iTerm2 windows running on different displays. I want to set focus to a specified window using applescript.
I need two things, one script that collects the window ID's and prints them to stdout. I've got this:
tell application "iTerm"
set wins to id of every window
end tell
which prints 6 integers: 3034, 2528, -1, -1, -1, -1
Bonus Question: What are the four -1's ?
Then I try:
tell application "System Events"
activate window 3034
end tell
Upon which the only thing happening is that I lose focus of my current terminal (in which I am typing these commands), not matter whether I specify 3034 or 2528 as the ID.
You almost have it. You can filter out the "-1" window IDs as by only looking at visible windows:
tell application "iTerm 2"
set wins to id of every window whose visible is true
end tell
I figured this out by looking at the results of:
tell application "iTerm 2" to properties of every window
I noticed that the "-1" windows have the property visible:false
Then you can tell the window ID directly to the iTerm application instead of system events:
tell application "iTerm 2"
activate window 13195
end tell
Related
Actually I have 3 questions about the same problem: controlling a window with applescript.
What should I do if I would press on button "Close Window" of application "Google Chrome"?
Is it possible to check if the window changes? For example, to see if appear a pop-up or something like that...
What about clicking on a specific place into a window? I mean, I know I can use
tell application "System Events"
click at {x,y}
end tell
but this command use the entire screen as reference system, and I want it works only on a specific window. For example, if at "{x,y}" i put "{1,1}", applescript will click on the first item on the menu bar. Is there a way I can say to "System Events" to click at "{1,1}", but on the window "Google Chrome"?
Here are three examples of how to close the front window of Google Chrome using AppleScript:
Note: The following assumes Google Chrome is running with at least one window open when you test each example AppleScript code in Script Editor.
Example one is the most straight forward way:
tell application "Google Chrome" to close front window
Example two directly clicks the close button:
tell application "System Events" to tell ¬
application process "Google Chrome" to ¬
click button 1 of front window
Example three calculates the center of the close button and clicks there:
activate application "Google Chrome"
delay 0.5
tell application "System Events" to tell ¬
application process "Google Chrome" to tell ¬
front window
set posB1 to (position of button 1)
set szB1 to (size of button 1)
set x to (item 1 of posB1) + (item 1 of szB1) / 2 as integer
set y to (item 2 of posB1) + (item 2 of szB1) / 2 as integer
end tell
tell application "System Events" to click at {x, y}
Note that in the first two examples, the front window of Google Chrome doesn't even need to be the frontmost window on the Desktop; however, with the third example it does, otherwise the click at {x, y} will not go to the intended target.
That said, example three really shouldn't be used when there it a straight forward way, as in example one, to get the job done. Example three was just a proof of concept to get the coordinates to click at. This method may be useful in some fringe cases, especially in an app that doesn't directly support AppleScript.
Note: The example AppleScript code is just that and does not contain any error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors.
In applescript GUI scripting you can simply refer to an element by name or index and tell it to click or to perform an action. For instance to click the close button on the first open window in Chrome you could use:
tell application "System Events"
tell process "Google Chrome"
tell window 1
tell button 1
click
end tell
end tell
end tell
end tell
You don't actually need to know its physical position to click one it; you just need to know that the first button in the window is the close button.
System Events always returns the position of any element in screen pixels, so if you want the position of an element in terms of its window, get the position of the element, get the position of the window, and do some addition or subtraction (e.g., if you want to click at {5,5} in a window whose position is {100, 125}, click at {105, 130})
AppleScript isn't really designed to monitor GUI changes, though if you want to be tricky and you know what change you're looking for you can do something like this:
tell application "System Events"
tell process "..."
tell window 1's pop up button 3
repeat until (exists menu 1)
delay 0.2
end repeat
-- menu 1 now exists, so the pop up button is open
end tell
end tell
end tell
...but note that this will hang the script until the menu is opened. A more elegant way to handle that is to write a script application with an idle handler, like so:
on run
-- whatever initialization is needed
end run
on idle
tell application "System Events"
try
tell process "..."
tell window 1's pop up button 3
if exists menu 1 then
-- menu 1 now exists
-- the pop up button is open
-- do what must be done
end if
end tell
end tell
on error errstr
display alert "Something went wrong" message "The script sent this error: " & errstr
end try
end tell
return 0.2
end idle
You can leave that running in the background watching for specific changes in the GUI (the 'try' statement is in case the app you're watching quits, the window closes, or something unexpected happens to the GUI).
If you haven't already, open the System Events scripting definition in Script Editor and look at the Processes Suite. That will show you all the things you can do with GUI scripting.
I am looking for a script that will place the cursor in the text field in the Messages App. I have looked for a keyboard shortcut to do this but cannot find one. Can anyone provide a script, or a similar one I can modify.
NB I am not a programmer or very familiar with AppleScript, but have been able to modify scripts that are close to my needs.
I need this as I am trying to make the messages app controllable using the built in dictation feature in Mac OS. I need a script I can assign to a voice command to place the cursor in the text field so that I can then dictate a message.
Many thanks.
If you are using dictation commands, in any application all you need to do is say the command “Show Numbers” and you will see this:
Then you would just say the command “Twenty” which will place your cursor right where you want it… in this case it would be the text field
Also speaking the command “Show Comands” Will open up this window listing tons of dictation commands.
The following was tested and works under OS X 10.8.5 and Messages 7.0.1 and may need to be adjusted for other versions of OS X/macOS/Messages:
tell application "Messages"
activate
tell application "System Events"
set focused of text area 1 of scroll area 4 of splitter group 1 of window 1 of application process "Messages" to true
end tell
end tell
Note: This is coded with the assumption that Messages is already open with an open window. Additional coding will be necessary, in the form of try and or delay and or on error statements as needed and appropriate otherwise.
Here's an example of how I'd code it otherwise, which handles whether or not Messages is open, has its window showing, etc.
on setFocusToTextArea()
tell application "System Events"
if (count of windows of application process "Messages") is equal to 0 then
click UI element "Messages" of list 1 of application process "Dock"
delay 0.25
end if
try
set focused of text area 1 of scroll area 4 of splitter group 1 of window 1 of application process "Messages" to true
end try
end tell
end setFocusToTextArea
tell application "Messages"
if running then
my setFocusToTextArea()
else
activate
delay 2
my setFocusToTextArea()
end if
activate
end tell
Note: If Messages is closed when this script is run, the delay 2 command gives time for Messages to open before the other code runs. The value of the delay command can be adjusted as appropriate for the speed of your system.
I am trying to get the foreground application from my second monitor (In Mavericks, second desktop). Here's my code that only gets the foreground application:
tell application "System Events"
set frontApp to name of first application process whose frontmost is true
end tell
How can I change it so it gets the application from a specific desktop / screen?
I don't think you can do as you want. If you look at the properties of frontApp there is no property that would indicate which screen it is on. However, what you can do is check the location of the application's windows. If you get the properties of a window of a process then you will see that it has a "position" property. You could check those coordinates to determine which screen it is on.
For example, I have 2 screens. My laptop is setup to be the main screen. I know the screen resolution of the main screen is 1680x1050. Therefore, if I check a window and it has a position outside of those coordinates then I know it must be on the second monitor. Here's how I could do that.
NOTE: I can tell which applications have windows on the second monitor, but not which application on the second monitor is frontmost... like you asked. You'll have to figure something else out for that. I'm showing you this as an idea that maybe you can make workable for your situation.
Here I am only getting the first application with a window on the second monitor. This should show you the idea and you can adjust the code to do as you need.
set mainScreenResX to 1680
set mainScreenResY to 1050
tell application "System Events"
set firstFoundAppOnSecondScreen to missing value
set visibleApps to application processes whose visible is true
repeat with visibleApp in visibleApps
try
tell visibleApp
set {x, y} to position of window 1
if x > mainScreenResX or x < 0 or y > mainScreenResY or y < 0 then
set firstFoundAppOnSecondScreen to name
exit repeat
end if
end tell
end try
end repeat
return firstFoundAppOnSecondScreen
end tell
I've seen a lot of posts for how to send a window to the front in applescript, but I want to be able to send it to the back. How do I write an applescript that will do this?
Maybe you don't actually need to move any windows. Maybe you can just hide your application so your window isn't showing. Since you don't want your window on the top then it's probably OK to just hide your application. It continues running and does its thing but its window doesn't cover any other windows.
Just change "Safari" to the name of your application.
set myAppName to "Safari"
tell application myAppName to activate
tell application "System Events"
-- wait until your application comes forward and then hide it
repeat
set p to first process whose frontmost is true
if name of p is myAppName then
set visible of p to false -- hide your application
exit repeat
end if
delay 0.2
end repeat
end tell
EDIT: if hiding your app doesn't work then you could just keystroke command-tab which is the application switcher command. Basically your app will come to the front and then the keystroke will make the previously frontmost application come to the front. So your window won't go all the way back but it won't be in the front. Maybe that will work.
set myAppName to "Safari"
tell application myAppName to activate
tell application "System Events"
-- wait until your application comes forward
repeat
set p to first process whose frontmost is true
if name of p is myAppName then exit repeat
delay 0.2
end repeat
-- use the application switcher to bring the previously frontmost application forward
keystroke tab using command down
end tell
Something like set index to 999 doesn't seem to work, but set index to (count windows) does:
tell application "TextEdit"
set index of window 1 to (count windows)
end tell
You might also raise all other windows:
tell application "System Events" to tell process "TextEdit"
repeat with w in windows 2 thru -1
perform action "AXRaise" of w
end repeat
end tell
This will move the front finder window to the back...
tell application "Finder" to set index of front Finder window to (count Finder windows)
I have not used "openFrameWorks" so I am not sure of how it works…
But rather than reinvent the wheel with Applescript.
Can you not set the window level in "openFrameWorks"
In xcode/Objective - c I would use the NSWindow Window Levels constants.
To set a normal window:
[awindow setLevel: NSNormalWindowLevel];
But set a window below other normal windows:
[awindow setLevel: NSNormalWindowLevel - 1000];
This will insure the window is always below any normal applications windows. Even when I click on it or drag it. It stays behind other windows.
I have an application with several windows opened at the same time.
I'd like to bring a specific window to foreground (I know its title).
At the moment I'm using a combination of keys to achieve this task but I'd like to try something different since I'm experiencing some problems with this approach.
tell application "System Events"
set frontmost of process "appIT" to true
keystroke "1" using command down
delay 0.2
end tell
This is possible by using the "AXRaise" action, except on certain window (applications that use X11 for example).
Try this.
set theTitle to "some title"
tell application "System Events"
tell process "appIT"
set frontmost to true
perform action "AXRaise" of (windows whose title is theTitle)
end tell
end tell
If your application is scriptable and allows setting the index of a window, you can do the following (based on an answer in How do I make a Safari window active using AppleScript (elegantly)?)
to raiseWindow of theApplicationName for theName
tell the application named theApplicationName
activate
set theWindow to the first item of ¬
(get the windows whose name is theName)
if index of theWindow is not 1 then
set index to 1
set visible to false
set visible to true
end if
end tell
end raiseWindow
The toggling of the visibility is necessary to deal with some weirdness that occurs with switching applications. If you don't toggle the visibility, the window won't be the first when you switch away from and back to the application. Unfortunately, this toggling shrinks the window to the dock then restores it, a very dramatic UI disruption.
Here's another way I've found to deal with the weirdness:
to raiseWindow2 of theApplicationName for theName
tell the application named theApplicationName
activate
set theWindow to the first item of ¬
(get the windows whose name is theName)
if the index of theWindow is not 1 then
set the index of theWindow to 2
tell application "System Events" to ¬
tell application process theApplicationName to ¬
keystroke "`" using command down
end if
end tell
end raiseWindow2
I don't think System Events can change the front window of a process. Of course you can close the front window until the window you want is on top. That's not really a solution though as you probably don't want to close windows. Really though the only way you could achieve this is if the application itself is apple-scriptable and allows you to do this.