Applescript API documentation - macos

I want to make an AppleScript to automate the task of switching resolution on the MacBook Pro Retina.
Searching the internet for "applescript system preferences" I came across a page where some preferences are show. Being the scaled resolution thing new, it is not documented.
This brings to a bigger problem I have with AppleScript (mind that apart from copy-pasting something I never really programmed in it). Where is the documentation that tells me, for instance, tha the System Preferences object is actually called "System Preferences", that it has objects called "pane", that they have an id and that the expose id is "com.apple.preference.expose"?
It seems like there must be some sort of "secret" documentation for every program, and they must be huge, mapping all the object hierarchies and possible actions. In the end, AppleScript core is minimal and all you do is manipulate such programs. But where are they documented?

Ok this is how it works:
Where is the documentation that tells me, for instance, tha the System Preferences object is actually called "System Preferences"
The object is called "System Preferences" because that is the exact name of the application. What you're telling Applescript with this is I want to speak to the application named System Preferences (tell application "System Preferences" ...)
that it has objects called "pane"
Now it's the fun part. If you open your Library window (in Applescript Editor, Window > Library) you will see that there is a collection of scriptable applications available, the thing is that 'System Preferences' is not there. So let's find it: File > Open Dictionary > System Preferences. Now you got a window that both lets you drill down all available classes/commands/properties of the app and also a split window with relevant documentation (if you click on SSystem Preferences you'll see Cpane and by clicking on this you'll see Pid among others). The id of the pane for once more would be the name of the pane (lowercased and concatenated - I'm still looking into documentation for a strict definition on this). I hope that this will get you started.
S:Suite
C:Class
P:Property
(the 'C' inside a circle stands for Command)

You're exactly right. Each program does have its own documentation for applescript. It's called its applescript dictionary. You can see the dictionary of any application by any of the following...
1) in AppleScript Editor, under the File menu, choose "Open Dictionary...". You can select an application from there and it will show its dictionary.
2) drag/drop an application onto the AppleScript Editor's icon.
3) there's a list of frequently-used dictionaries for fast access. Under the Window menu in AppleScript Editor choose "Library". You can double-click an application in that list. You can also modify that list to contain dictionaries that you want in the list.
Good luck.

You can ask AppleScript to tell you the ids for each of the panes.
tell application "System Preferences" to get the id of every pane
This is particuarly handy as it will tell you the ids for any third-party preference panes you have installed. For instance, I was able to work out that the pane for my Microsoft Natural keyboard is called com.microsoft.microsoftkeyboard
I haven't really explored this much yet, but I would expect that similar syntax exists to identify the objects within any scriptable application.

I have another issue but you can have a look to my question as there is some hint in my script about your issue
HOW TO: display a check mark, disable a menu item, refresh a menubar
For instance:
tell application "System Preferences"
reveal anchor "displaysDisplayTab" of pane id "com.apple.preference.displays"
end tell
This code should directly put you in the resolution preferences of the system preference.
Then you can make a code to recuperate all the UI elements of the pane so that you now which action to trigger. Something like this should also work:
tell application "System Events"
tell application process "System Preferences"
set frontmost to true
delay 1
return every UI element of front window
return name of every UI element of front window
end tell
end tell
Hope it helps

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.

Applescript: do a context menu action

I'm sorry I couldn't come up with a better title.
I've made a little applescript service that gets the unix path to a file you selected in the Finder and then stores that path in the clipboard.
The files I use this for are in my Google Drive volume and now I'd like to add an extra feature which is powered by Google Drive File Stream application.
If I right click on a Google Drive file in the finder, I get 3 extra items in the context menu, see attached screenshot.
All I want is my script to run "Copy link to clipboard".
So how do I tell apple script to do so?
I'm sorry for the very trivial question, but I think I lack the right terminology to make a Google search, all I could find was how to add an apple script to a context menu, which I already did.
Use AXShowMenu to open the context menu. Then send the keystroke "Copy link to clipboard" to select the copy action, and send "Enter" to activate the action.
tell application "System Events" to tell application process "Finder"
set selectedFile to value of attribute "AXFocusedUIElement"
tell selectedFile to perform action "AXShowMenu"
delay 0.5
keystroke "Copy link to clipboard"
-- Sends enter
key code 36
end tell
Note that this doesn't work properly when using Finder's icon view. The list view or column view must be used.

`AXFocusedUIElement` <- does not get focused element (folder, file), it points to `Finder` menu

trying to reproduce right-click context menu on my Mac.
I found such an article:
https://beebom.com/how-right-click-using-keyboard-mac/
I did accordingly but when I click my keyboard shortcut I get Finder menu not a currently selected file/folder menu.
This is an apple script used,
on run {input, parameters}
tell application "System Events" to set frontApp to name of first process whose frontmost is true
tell application "System Events"
tell application process frontApp
set _selection to value of attribute "AXFocusedUIElement"
tell _selection to perform action "AXShowMenu"
end tell
end tell
return input
end run
Spent hours trying to get this basic and obvious to every Windows user functionality to work, lost of time and very frustrating!
I think code is correct, maybe there is something specific on my computer that stops it from working as expected?
Please help :-)
Not sure i understood what is actually not working for you, but i had problem to reproduce the same script, once i wrote it in Automator.app i tried to press "play" button to see if the script was working and it was telling me something like "syntax error, can't get attribute AXFocusedUIElement of application process Automator" (from memory, not sure it's exactly what was written)
and struggled for a while as well untill i realised there was a pop window that i didn't see, saying me that "automator wants permission to control this computer using accessibility features (this thing in the system preference, security and privacy, privacy, accessibility), so i opened, there was a list of apps allowed to control my computer, i ticked Automator.app and after that it worked
Then every app that i was trying to do a right click was showing me the same pop up and i had to do the same for each one (safari, finder etc...)
And then it worked
Hope might help you!
Encountered same issue.
Allow 'Finder' to control computer at System Preferences>Security & Privacy>Privacy>Accessibility.
Worked for me

Accessing "hidden" windows in AppleScript

I'm trying to set up an applescript which will handle a slightly-annoying VPN login process for me. I use Cisco AnyConnect, and every time I have to log back on, I have to hit connect, accept a certificate warning, enter my username, password, and select the right group, and accept ANOTHER certificate warning.
It's that second certificate warning I can't seem to get around.
Some digging indicates that the warning dialog is owned by a process named vpndownloader, but the odd thing is that Applescript seems convinced that it has no windows and does not exist!
I've been using Accessibility Inspector to get the window IDs and such to make this script work. For this particular dialog, it looks like this (accessibility inspector behind the actual dialog I'm attempting to control)
The strangeness comes in when I try to get the window's ID so I can do things with it.
tell application "System Events" to windows of process "vpndownloader"
{}
Blank. Okay, maybe there's something useful in the properties of the process?
tell application "System Events" to properties of process "vpndownloader"
{has scripting terminology:false
bundle identifier:"com.yourcompany.vpndownloader"
file:alias "Macintosh HD:opt:cisco:anyconnect:bin:vpndownloader.app:" of application "System Events"
creator type:"????"
subrole:missing value
entire contents:{}
selected:missing value
application file:alias "Macintosh HD:opt:cisco:anyconnect:bin:vpndownloader.app:" of application "System Events"
orientation:missing value
role:"AXApplication"
accepts high level events:true
file type:"APPL"
value:missing value
position:missing value
id:1212712
displayed name:"vpndownloader"
name:"vpndownloader"
class:application process
background only:true
frontmost:false
size:missing value
visible:false
Classic:false
partition space used:0
role description:"application"
maximum value:missing value
architecture:"i386"
short name:"vpndownloader"
focused:missing value
minimum value:missing value
help:missing value
title:"vpndownloader"
accepts remote events:false
total partition size:0
description:"application"
accessibility description:missing value
enabled:missing value
unix id:9053}
(for giggles, note that Cisco didn't set their bundle identifier..)
No contents, no visible windows. Despite the dialog I've got up right in front of me.
So, on one hand it obviously has a window (accessibility inspector can see it), but AppleScript is convinced that it does not.
How do I programmatically locate and access this "phantom" dialog?
Things that didn't work:
tell application "vpndownloader" to windows
error "vpndownloader got an error: Can’t get every window." number -1728 from every window
Again the theme of this application being in a weird state between existence and nonexistence comes up
tell application "vpndownloader" to properties
error "vpndownloader got an error: Can’t get every property." number -1728 from every property
It has a menu bar, but no windows.
tell application "System Events" to get UI elements of process "vpndownloader"
{menu bar 1 of application process "vpndownloader" of application "System Events"}
You can probably just use keystrokes. For example when that window comes up you yourself can probably physically hit the "connect anyway" button by first pressing the "tab" key to change the focussed button and then press the "space bar" to select the focussed button.
NOTE: you may have to enable this functionality by enabling full keyboard access. Do this by going to system preferences->keyboard->shortcuts and checking "all controls" at the bottom of the window.
If you can then you can applescript it. The following will work as long as that window is frontmost when you issue the commands.
tell application "System Events"
keystroke tab
delay 0.2
keystroke space
end tell
Good luck.
It works for me (I use anyconnect 3.1.06073).
https://gist.github.com/lotreal/ce43f4a85d8ae73781fa
So I found an interesting workaround for this problem that doesn't involve scripting. It turns out the vpndownloader is entirely optional, and it apparently only serves the purpose of updating the client when an update is pushed from the upstream server
A local policy XML can be defined to disable the process. This will cause breakage if an update is pushed (the connection will just abort), but it at least allows the login to be scripted.
On Mac/Linux systems, this file is located in /opt/cisco/anyconnect/AnyConnectLocalPolicy.xml - I had to create one based on the schema file, AnyConnectLocalPolicy.xsd in the same folder. If it already exists, just edit the existing one.
The key line is <BypassDownloader>, which is set to false by default. Setting it to true means that the downloader is simply not run, meaning the second dialog I was trying to access simply never appears!

Can I manipulate the location of a dialog displayed through osascript?

I've been playing around with various UNIX commands and came across this one to display a dialog:
osascript -e 'tell app "System Events" to display dialog "Hello World"'
I'd like to change the position of the dialog. For most commands, I can just use man command to figure out how to do something for that command. However, man osascript doesn't tell me how I can change the position of the dialog box. How can I modify the command to put the dialog in a different place?
First, to get help with applescript just open the AppleScript Editor application and look under the help menu. The applescript language guide is in there and other tools. Also under the file menu is "Open Dictionary" which will show you the specific commands for applications.
To see the information about display dialog, open the dictionary of StandardAdditions and use the search field to find the command.
To answer your question, no, you cannot specify the location of a "display dialog" window. There are no parameters in that command for positioning the window, as you'll see in the dictionary. In addition, no other commands will help you either because you can't issue other commands while the dialog window is open because the code pauses while the window is open waiting for a response from the dialog window (like when you press the OK button).
If you need to set the position of a window to display information to a user then you'll need to use some other dialog tool other than "display dialog". You could create your own window in cocoa or google for some alternatives like cocoaDialog, SKProgressBar, and Notification Center.
There is a round-about way to go about this, which may be useful in some scenarios. Try the following:
on displayMessage(msg)
tell application "Finder"
activate
set c to (count windows)
ignoring application responses
display dialog msg with icon note
end ignoring
end tell
tell application "System Events"
tell application process "Finder"
repeat until ((count windows) > c)
delay 0.2
end repeat
set position of window 1 to {0, 22}
end tell
end tell
end displayMessage
displayMessage("I'm over here!")
Credit for this little script goes to a post here.
In implimenting this myself, I found it was limited to whether or not the application that is being called (Finder, in the example) supports the count window command (or whether it has API support at all).
I realise I've dragged up a question from 2013. I am posting this answer here in case it is of use to the OP or, more likely, someone else with a similar question.

Resources