AppleScript -> Activate window of a non-scriptable application - applescript

I have opened 2 "Finder" window A & B, A is in the front while B underneath, the following snippet brings B to the front the topmost:
tell application "Finder"
activate
activate window 2
end tell
But for applications that do not support scripting, the code just mentioned won't help.
Any ideas for activating a window of non-scripting application.

You can usually turn to system events in these cases. System events knows about the windows of running processes and you can usually manipulate those windows. Something like this will show you some of the things you can do. Just play around with the code and see if you can do what you want.
tell application "System Events"
tell process "Whatever"
properties of windows
end tell
end tell
EDIT: One of the properties of a window is its "title". So you might be able to use that. This approach uses the fact that many applications have a "Window" menu and under that menu many times the name of the windows are listed and you can switch windows by clicking the approprite menu item. So something like this might work... my example uses TextEdit.
tell application "TextEdit" to activate
tell application "System Events"
tell process "TextEdit"
set windowTitle to title of window 2
click menu item windowTitle of menu 1 of menu bar item "Window" of menu bar 1
end tell
end tell

What is your definition of non-scriptable? Just about everything is scriptable to some degree, but for the sake of an example lets use, does not contain an AppleScript dictionary, e.g. AppName.sdef within its application bundle.
For example, the macOS included Stickies application does not contain the Stickies.sdef file, and when trying to add it to the Library in Script Editor is says, "Unable to add the item because it is not scriptable."
In a case such as this, then System Events is needed to talk to the application process, e.g.:
Example AppleScript code:
if running of application "Stickies" then
tell application "System Events"
tell application process "Stickies"
set frontmost to true
if exists window 2 then ¬
perform action "AXRaise" of window 2
end tell
end tell
end if
Notes:
I've included error handling in the example AppleScript code, which can be removed if you prefer.

Related

How do I tell if the frontmost window is a NSOpenPanel / file open dialog in MacOS using Applescript?

I'm trying to automatically change the directory of the frontmost "file open dialog" or NSOpenPanel dialog with AppleScript, whether that window is part of any application. The idea is that I hit a hotkey, and it will control that dialog to switch to a particular folder.
I can't seem to find out how to find the attributes of a window that would filter it for a "file open dialog". Using the Accessibility Inspector I can find that the "class" is NSOpenPanel. How can I get the class of a window using Applescript?
If you run the following AppleScript, you can see the properties of the foremost window:
tell application "anApp" to activate
delay 1
tell application "System Events"
tell process "anApp"
properties of window 1
end tell
end tell
The app has to be active to see the properties of the windows; You will not get consistent results if the app is in the background.
The NOOpenPanel ought to be recognizable by testing for some combination of the following properties:
role description:"dialog"
title:"Open"
subrole:"AXDialog"
name:"Open"
description:"dialog"
Personally, I'd probably rely on name and role description, which should be the same anytime an app throughs up a standard 'Open' dialog. 'Save' dialogs will be the same, except that title and name will be 'save' rather than 'open'.
If you have an app that presents a open or save sheet (a sub window attached to the titlebar), not a separate dialog, then you'll shift things a little. The AppleScript to get the properties looks like this:
tell application "anApp" to activate
delay 1
tell application "System Events"
tell process "anApp"
tell window 1
properties of sheet 1
end tell
end tell
end tell
and the relevant testable properties are as follows:
accessibility description:"save"
role description:"sheet"
role:"AXSheet"
description:"save"
You'll probably have to add logic to test whether the front window has a sheet, which should distinguish between dialogs and sheets.
Some apps use non-standard open/save dialogs, and you'll have to account for them on a case-by-case basis. There's no magic bullet for that.

Show/hide Finder, and create new window if none exist via AppleScript

I'd like to create an AppleScript to trigger via key command in Keyboard Maestro that allows me to toggle showing or hiding the Finder window(s) directly. And if when toggling to show the Finder, if there are no existing windows, create one and open it up to my home directory.
The following AppleScript works. However, there seems to be a race condition between activating the finder and detecting if there are any open windows with if not (window 1 exists), hence the delay 0.5.
The problem (which I think is a race condition in detecting the presence of an existing Finder window) results in this script frequently creating new Finder windows when one already existed. The if not (window 1 exists) doesn't always get it right.
Any thoughts, tweaks, or affirmations that this is just the way it is would be appreciated!
tell application "System Events"
set activeApp to name of application processes whose frontmost is true
if ((activeApp as string) is equal to "Finder") then
set visible of process "Finder" to false
else
tell application "Finder"
activate
delay 0.5
if not (window 1 exists) then
make new Finder window
set thePath to POSIX file "/Users/jon"
set the target of the front Finder window to folder thePath
end if
end tell
end if
end tell
Please try this simpler syntax, it uses only Finder terminology
tell application "Finder"
if frontmost then
set visible of process "Finder" to false
else
if (count windows) is 0 then reveal home
activate
end if
end tell
Edit:
To run a Keyboard Maestro macro, open Keyboard Maestro Editor, select the macro and then select Copy as > Copy UUID from the Edit menu.
Then in AppleScript write
tell application "Keyboard Maestro Engine" to do script "<Script-UUID>"
replacing <Script-UUID> with the copied real UUID
Ultimately I needed to activate Finder before running the count windows command or I'd get inconsistent window counts. Sometimes it'd be 0 even when there was a window open already. This code is working well for me so far.
tell application "Finder"
if frontmost then
set visible of process "Finder" to false
else
activate
if (count windows) is 0 then
open home
tell application "Keyboard Maestro Engine" to do script "<Script-UUID>"
end if
end if
end tell

Using AppleScript automation how can I get currently opened Adobe reader file name

I tried below code
activate application "Adobe Reader"
tell application "System Events"
tell process "Adobe Reader"
set currentFile to active Document
end tell
end tell
But I couldn't get active document name, I tried this code by already with opened document. I don't even find any dictionary for adobe reader in script Editor. Any suggestions will be much appreciated
The Adobe Reader app does not have an AppleScript dictionary file within it's application bundle and as such is not AppleScript scriptable beyond a very limited number of Standard Suite commands and UI Scripting its menu bar with System Events.
If you just want to get the name of the document that has focus, then the following example AppleScript code can do that:
if running of application id "com.adobe.Reader" then
try
tell application "System Events" to ¬
set docName to ¬
(get name of every menu item of menu 1 of menu bar item ¬
"Window" of menu bar 1 of application process ¬
"Acrobat Reader" whose value of ¬
attribute "AXMenuItemMarkChar" = "✓") as string
return docName
end try
end if
The use of return docName was for testing purposes and can be removed as appropriate. Additionally, it was not necessary for Adobe Reader to have focus and its window could even be minimized, the script still retrieved the name as shown on its Window menu.
Note: This was tested on macOS High Sierra using US English and Adobe Acrobat Reader DC (Continuous Release | Version 2019.021.20058.) and works as is. Adjustments may be needed for other languages and or different versions of Adobe Reader.
Note: The example AppleScript code is just that and does not contain any additional 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. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.
Here are a few AppleScript options that may work for you. I don’t have Adobe Reader so I am not able to test the code.
tell application "Adobe Reader" to set currentFile to name of document 1
If that doesn’t work for you, you can try this…
tell application "Adobe Reader" to activate
repeat until application ""Adobe Reader" is frontmost
delay 0.1
end repeat
tell application (path to frontmost application as text) to set currentFile to name of document 1

Applescript - Close Pages Document Automatically

I am trying to create a script that will automatically close the frontmost window of Apple Pages.
on run {}
tell application "System Events"
if (window 1 of process "Pages" exists) then
try
tell application "Pages"
--display dialog "Hello World!" --TODO: remove, test code only.
--Keywords I have tried: file, document, window,
close window 1 saving no
end tell
--close window 1 of process "Pages" saving no
on error errMsg
display dialog "ERROR: " & errMsg
end try
end if
end tell
end run
Whenever I run this, it gives me the following error:
ERROR: Pages got an error: window 1 doesn’t understand the “close”
message.
I have looked at this article, and have used the following command:
sudo defaults write /Applications/Pages.app/Contents/Info NSAppleScriptEnabled -bool YES
However, it still fails to work. Any advice?
Details:
System Version: OS X 10.9.1 (13B42)
Kernel Version: Darwin 13.0.0
Pages: 5.0.1
If Pages isn't scriptable, you're kind of out of luck. If it were scriptable, you wouldn't need System Events to close a window; that kind of functionality is usually included in a scriptable app's dictionary.
System Events can help with apps that aren't scriptable, but you have to rely on the actual UI. But if that's the solution, you can't use tell application "Pages" for the inner block (like you have it); you have to use:
tell process "Pages"
If you go that route, now you have to use either the close button on window 1 or use the close menu command. Something like:
activate application "Pages"--note that this will probably be NECESSARY (if it's not frontmost, it prob won't work)
tell application "System Events"
tell process "Pages"
click menu item "Close" of menu "File" of menu bar item "File" of menu bar 1 of it
end tell
end tell
BUT then you have to come up with the problem of what happens if the window hasn't been saved (has been modified) -- which in a scriptable app uses the construction you were originally trying. When using System Events, you can do:
activate application "Pages"--note that this will probably be NECESSARY (if it's not frontmost, it prob won't work)
tell application "System Events"
tell process "Pages"
click menu item "Close" of menu "File" of menu bar item "File" of menu bar 1 of it
delay .5
keystroke "d" using command down
end tell
end tell
But then again how do you make the script smart enough to know if the window has been modified or not? Or maybe you use System Events to see if the window has been killed after the close command, and if it hasn't, it does the keystroke thing. This kind of thing can be done by doing something like:
activate application "Pages"
tell application "System Events"
tell process "Pages"
set frontMostWinName to name of window 1
click menu item "Close" of menu "File" of menu bar item "File" of menu bar 1 of it
tell me to delay 0.5
if exists window 1 then
if name of window 1 = frontMostWinName then keystroke "d" using command down
end if
end tell
end tell
I don't have Pages, but this works with another non-scriptable app, Bean (although I should mention that Bean uses tabs, and I had to move a tab to a window to get this to work*, and I don't know how Pages works in this regard).
[EDIT: *actually, this is not true; this works in Bean regardless of tabs/windows]

Simple GUI scripting question

I am trying this simple GUI script to open a new window of Safari:
tell application "Safari"
activate
end tell
tell application "System Events"
tell process "Safari"
try
tell menu bar 1
tell menu bar item 3
click menu item 1
end tell
end tell
on error theError
display dialog ("An error occurred while performing requested action" & theError) buttons "OK" default button "OK"
end try
end tell
end tell
but it is giving this error message:
Expected end of line but found """
Can anyone suggest me where I may be wrong?
Thanks,
Miraaj
Wow, that was weird. Your script broke AppleScript Editor. After running your script and it not working... I tried to recompile the script and then the error you posted starting showing up. So somehow your code caused AppleScript editor to break and thus the error. I had to quit and relaunch AppleScript Editor to get it working again.
I used the application UI Browser and found the problem. Your reference to the menu item was wrong. There's an extra menu in there that we can't see... and you didn't reference that extra menu. This is the problem with gui scripting. And even if a gui script works it may break at some future date as an application is updated. As such avoid gui scripting if at all possible.
Anyway, here's what your code should look like...
tell application "Safari"
activate
end tell
tell application "System Events"
tell process "Safari"
try
tell menu bar 1
tell menu bar item 3
click menu item 1 of menu 1
end tell
end tell
on error theError
display dialog ("An error occurred while performing requested action " & theError) buttons "OK" default button "OK"
end try
end tell
end tell
EDIT:
As I mentioned in my comment below, if you can't find a native command from an application's dictionary, the next most reliable method is using keyboard shortcuts. Most menu items have them. For example, if I wanted to open a new tab in a window that menu item has the keyboard shortcut command-t. So we can use that like this. Note there is a native command to open a new tab without using keystrokes, I'm just showing this as an example.
tell application "Safari" to activate
tell application "System Events"
keystroke "t" using command down
end tell
end
Keyboard commands don't usually change between application updates whereas gui commands often do because programmers redesign their interface in updates... and when that happens gui scripting goes haywire. One of the gotcha's with both gui scripting and keystrokes is that sometimes the script goes too fast and these techniques can't keep up with the speed of the program, so they often error. When this happens you need to slow down the script using small delays to allow the interface to keep up with the script.

Resources