Accessing an Applescript from 2 different menus produces different results. Why? - user-interface

I've got an application that has an embedded Script menu for running Applescripts. However, if you try to run scripts with certain functions (mostly UI related) they won't work unless you run them from the System script menu (in menu bar).
For example, if in theApplication you say :
tell application "System Events" to tell application process "theApp" to get all windows
it will return an empty list if run from the program's script menu, but 2 if run from the system script menu. I've also tried:
tell application "System Events"
tell application process "theApp"
set allElements to UI elements
display dialog (count of allElements)
end tell
end tell
-- returns 2 when run from System script menu but 0 when run from within theApp.
Also if you run from the Script Editor it will work fine. GUI scripting is enabled for the application in System Preferences, so I'm curious as to why this is happening, and any workarounds for it (other than run the script from the System Script menu)? The Dictionary shows Standard Suite so it should have access to windows...
Any ideas?

I believe you haven't provisioned the app in question to use assistive devices.
You should really open System Preferences, then click the button for "Security", then unlock, and click the button for Assitive Devices, (the blue icon with a white man), then drag your app onto it (reveal your app from its Dock menu), and permit it to control your machine, remember to lock the pane afterwards.
I can not guaranttee this to work, but it is certainly worth a try.

Related

Automator permissions error when running AppleScript in Safari – Alternatives and security risks?

I want to use Automator and AppleScript to fill out a form in Safari. I have a functioning script that looks something like this toy example:
on run {}
tell application "System Events" to keystroke "Hello"
tell application "System Events" to keystroke tab
tell application "System Events" to keystroke "World"
end run
I wish to execute it with a keyboard shortcut when I'm at a specific point in my browser. However, when I do this, I run into permission issues:
The action "Run AppleSCript" encountered an error:
"System Events got an error: Automator Workflow Runner
(WorkflowServiceRunner, my_script_name) is not allowed to send keystrokes"
In System Prefrences -> Security & Privacy -> Privacy -> Accessibility I have allowed both Automator and AppleScript Utility, and under the Automation tab, I have allowed System Events for Safari.
I can get it to work, at least temporary, if I allow Safari in Accessibility too, but that seems to be too drastic and a security risk to have Safari to always have full control just to run a script from time to time.
How should I approach this? I want the script to be easy to use, and wouldn't want to go into the settings each time to temporary allow Safari. Or can this be automated too? Is there a completely different approach than Automator and AppleScript that would allow me to do this in a more user friendly and safe way? Basically, I want to do something similar to what AutoHotKey would be able to do in Windows.
I’m guessing that what you’ve done is set up a Quick Action and then given that Quick Action a shortcut under “Services” in “Keyboard:Shortcuts” in System Preferences. I was able to duplicate the problem by doing that: attempting to run the script requires that Safari itself have access to “control your computer”. If that is not what you’ve done, this solution should still work, but you may also want to update your question, in case a better solution is available.
What you can do is use redirection. Create an application that can be given permission to control your computer, and then create a Service that will launch the application.
Use Automator (or Script Editor) to create an Application with the above steps, adding as the first step tell application "Safari" to activate. You need that step because opening the app will take the focus away from Safari.
Save this Application. (If using Automator, you tell Automator that it’s an application when you start creating the script; if using Script Editor, you tell Script Editor that it’s an application when you save the script.)
Use Automator to create a Quick Action. Give it the action “Launch Application” and tell it to launch the application you just created.
Drag the application you created in step 2 into the “Accessibility” list in System Preferences’s “Security & Privacy” settings. (You may have to unlock those settings to allow changes.) It should be checked automatically when you drag it in, but if not you can check it.
In the “Services” list in the “Keyboard:Shortcuts” settings of System Preferences, the Quick Action you created in step 3 should be listed. Give it a keyboard shortcut.
At this point, you should be able to use the keyboard shortcut to run the application, and only that application needs to have permission to control your computer.

Sending keystrokes in Applescript via Automator in any application

I setup an Applescript quick action in Automator to leave a zoom meeting. No matter what application is in the forefront, I would like to check if zoom is running and if so, leave the meeting.
set appName to "Zoom.us"
if application appName is running then
tell application id (id of application appName)
activate
end tell
tell application "System Events"
keystroke "w" using command down
keystroke tab
keystroke return
end tell
end if
It works! The problem is, if I'm in a zoom meeting and another app is in the forefront, I have to get permission from system preferences for that app to access system preferences. Like if I'm in Chrome, I have to allow Chrome to send keystrokes. Then, Chrome will always work.
I have to do this for every single possible app. Is there a way to get keystrokes in there without going thru this security stuff in Big Sur? I don't mind bringing up zoom to the forefront.
There are issues at play here with using global keyboard shortcuts with Automator workflows saved as a Service/Quick Action.
The keyboard shortcut assigned to the Service/Quick Action needs to not conflict with a default keyboard shortcut for whichever application is frontmost at the time it's pressed, otherwise there may be unwanted behavior.
Every application that is frontmost when the keyboard shortcut is pressed on a Service/Quick Action using UI Scripting in the Run AppleScript action will need to have accessibility privileges granted for it (as you've already found this out and hence the question).
To workaround the accessibility privileges issue, here are three methods to achieve the goal that come to mind.
The first, my preferred method for running AppleScript scripts with a keyboard shortcut, is to use a third-party application named FastScripts, as it would not need to have every application that's frontmost, that hasn't yet been granted privileges, to be granted accessibility privileges to run the AppleScript code shown in your question. I'd imagine other similar type third-party applications that allowed assigning keyboard shortcuts and running a script would bypass the issue too, but have only tested the aforementioned.
The second method, can be done with Automator as a Service/Quick Action using a Run Shell Script action, then assigned a keyboard shortcut and will work without having to give accessibility privileges to the application that is frontmost when the keyboard shortcut is pressed.
The third method, can be done with Automator as a Service/Quick Action using a Run AppleScript action if changing a zoom.us default preference under zoom.us > Preferences… > General by unchecking [] Ask me to confirm when I leave a meeting, then when assigned a keyboard shortcut and will work without having to give accessibility privileges to the application that is frontmost when the keyboard shortcut is pressed.
All testing was done under macOS Big Sur using zoom.us, (Version: 5.4.7 (59780.1220)) with my Language & Region setting in System Preferences set to US English using the various methods presented.
Method 1
The first method using the following example AppleScript code, show further below, and FastScripts with the keyboard shortcut ⌃⌥⌘W assigned and works for me as coded.
In System Preferences > Security & Privacy > Privacy > Accessibility I had the following added and checked:
FastScripts
System Events
Then with zoom.us running and several other applications which were frontmost when the keyboard shortcut was pressed I did not have to grant accessibility privileges to those other applications, zoom.us was brought to the front and closed.
Example AppleScript code:
if application "zoom.us" is running then
tell application "zoom.us" to activate
delay 0.5
tell application "System Events" to ¬
tell application process "zoom.us"
keystroke "w" using command down
delay 0.5
key code 36
end tell
end if
Note for testing purposes, after testing Method 1, I quit FastScripts as it would have been triggered by the same keyboard shortcut which was assigned when testing the next two methods.
FastScripts can be run as a free app, up to 10 keyboard shortcuts, or upgraded for $24.95 USD to unlock unlimited keyboard shortcuts. I have no affiliation with Red Sweater Software, LLC, other then as a user of FastScripts.
Method 2
The second method was tested using Automator and a Service/Quick Action with setting Workflow receives [no input] in [any application] using a Run Shell Script action with its default settings, and the following example shell script code is all that was used:
[[ -z $(pgrep -x 'zoom.us') ]] || pkill −x 'zoom.us'
In System Preferences > Keyboard > Shortcuts > Services I assigned it the keyboard shortcut: ⌃⌥⌘W
Then with zoom.us running and several other applications which were frontmost when the keyboard shortcut was pressed I did not have to grant accessibility privileges to those other applications, zoom.us was closed.
Method 3
The third method was tested using Automator and a Service/Quick Action with setting Workflow receives [no input] in [any application] using a Run AppleScript action replacing its default code with just the following example AppleScript code:
tell application "zoom.us" to quit
In System Preferences > Keyboard > Shortcuts > Services I assigned it the keyboard shortcut ⌃⌥⌘W after removing it from the Service/Quick Action created in Method 2.
Then with zoom.us running and several other applications which were frontmost when the keyboard shortcut was pressed I did not have to grant give accessibility privileges to those other applications, zoom.us was closed.
This of course works because the [] Ask me to confirm when I leave a meeting preference was unchecked in the preferences for zoom.us.
To recap, if you do not mind changing the mentioned default preference in zoom.us, then Method 3 is probably the easiest and best way to resolve your issue as it allows for a graceful quit over Method 2, does not require any third-party application, and does not require any accessibility privileges be granted or zoom.us being frontmost, it just works.
I mentioned the other methods first as method one addresses the UI Scripting issue with Automator and a Service/Quick Action, and method two works with the default settings in zoom.us.

Perform actions on a certain window of the application with AppleScript

I'm building a macOS app for managing locations sent to an iOS device via GPX file in Debug mode, so I need to have to Xcode windows opened for each project. I got an AppleScript which presses Debug -> Simulate Location -> "my gpx file name" for continuous location updates. However, it works only if the window with an iOS project (through which I simulate the location) is frontmost.
I want the script to be able to perform said actions just on a window with a certain name (or rather whose name contains ...), no matter of the hierarchy. I don't want it to be brought to the front or activated, as I might be coding something in a second one while the script runs.
I tried many ways, but with my limited understanding of AppleScript I either get an error (like "Can't locate menu item 1 in bla-bla-bla of the process Xcode) or the window activates and doesn't work in the "background".
repeat while true
tell application "System Events" to tell process "Xcode"
click menu item "MyLocation" of menu 1 of menu item "Simulate Location" of menu 1 of menu bar item "Debug" of menu bar 1
end tell
delay 0.2
end repeat
Is it even possible to perform any action on inactive window? I thought it is since the system lets you scroll without focusing the window.

AppleScript to block Safari pop-up windows

I am trying to automate the blocking of pop-up windows in Safari.
I have tried the following defaults write operation
defaults write com.apple.Safari WebKit2JavaScriptCanOpenWindowsAutomatically -boolean false
But this fails to do it. I have also tried setting it as true but even that didn't help. I am currently trying to find a way to do it using AppleScript.
This is what I have written so far -
CMD_ACTIVATE='tell application "Safari" to activate'
CMD_NEWTAB='tell application "System Events" to keystroke "," using {command down}'
osascript -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB"
This opens up the preferences but then I draw a blank. Anyone with any suggestions on how to proceed? Also I don't really need a solution to this only in AppleScript any other way to do it would also be helpful.
Note: I have been using Mac OS only for a week now, and am not that well versed in the nuances of this OS, so please be a bit descriptive when answering.
Thanks.
Blocking pop-up window is done via Safari / preferences / tab Security where you need to set the correct checkbox.
This preference seems to be stored in your library / preferences file com.safari.plist which contains the flag com.apple.Safari.ContentPageGroupIdentifier.WebKit2JavaScriptCanOpenWindowsAutomatically with value Yes when pop-up are blocked.
However, it may not be the only place to be changed and in any cases, it is not officially documented, so that place can be changed by Apple any time. This is not recommended to use it.
Going back to Applescript, because Safari is quite poor in terms of applescript handling events, you are forced to go via GUI scripting. That’s what you’ve started, but keep in mind that if Apple changes the layout of Safari preference window, your script must be reviewed.
When going through GUI scripting (which, again, should only be when no other solution found) you must understand structure of GUI objects. Window contains button, check box, tool bar... in a hierarchy model. For instance the preference window in Safari contains bellow the tool bar, an object "group 1" with itself contains many objects depending of the tool bar current selection. Once you understand that concept, the script below, which does what you're looking for, will be easy to understand with many comments:
tell application "Safari" to activate
tell application "System Events"
keystroke "," using {command down}
delay 0.2 -- leave sometime to open window
tell window 1 of process "Safari"
click button 6 of toolbar 1 -- Security button is number 6
delay 0.2
-- check if check box not yet set and set it.
if (value of checkbox 5 of group 1 of group 1) = 0 then click checkbox 5 of group 1 of group 1
end tell
delay 0.2
click button 1 of window 1 of process "Safari" -- click on red / close button
end tell
I am running on Safari 10.0.3. If your version is different, the preference window may be different. Then the script must be adjusted: the Security tab button may not longer be the number 6 in your version,...

Access context menu items by name using AppleScript

I'm trying to use AppleScript to click on context menu items in Logic Pro, preferably by simply providing the name of the menu item. It seems like this should be possible because I'm able to set up keyboard shortcuts for these context menu items using system preferences and providing the name of the command.
For instance, if you right click on the main editing window in Logic, a menu pops up with an option called "Add Audio File..." If I create a system preferences keyboard shortcut for Logic and give it this menu item name, it's able to execute just fine. I'd like to recreate this with a script. I'm familiar with accessing normal menu items using the hierarchy like so:
tell process "Logic Pro"
tell menu bar 1
tell menu bar item "File"
tell menu "File"
click menu item "Save"
but as far as I know, there's no way to access the context menu (right click menu) that I want like this. It seems there should be a way to simply access a non-menu-bar menu item by name since system preferences is obviously able to do so.
Logic pro is not scriptable so my suggestion would be that you set a keyboard shortcut in the system preferences then use system events to use said shortcuts.
for example to enter find mode (assuming there is a find mode since i don't own Logic Pro)
tell application "Logic Pro" to activate
tell application "System Events"
tell application process "Logic Pro"
keystroke "f" using command down
end tell
end tell
I don’t think you need to use the context menus. “Add Audio File…” is available in other parts of the Logic Pro X user interface. If you open the Project Audio window, there is an “Audio File” menu button with an “Add Audio File…” button in it. So this AppleScript will activate the “Add Audio File…” command:
tell application "System Events"
tell application "Logic Pro X" to activate
tell process "Logic Pro X"
tell menu bar 1
click menu item "Open Project Audio" of menu "Window"
end tell
delay 1
tell window 1
click menu button "Audio File" of group 1 of group 1
click menu item "Add Audio File..." of menu 1 of menu button "Audio File" of group 1 of group 1
end tell
end tell
end tell
One thing to keep in mind if distributing a GUI script is that the above script will only work in Logic Pro X running on a Mac set to US English (and maybe other kinds of English) because the names of the menus change if the system is set to another language. What you can do is replace the names in the above script with numbers, which is a totally experimental process, as far as I know. You have to try different numbers and see which continues to work.
So you may be able to replace:
menu button "Audio File" of group 1 of group 1
… in the above script with:
menu button 1 of group 1 of group 1
… and get the same functionality, and the script would work on any Mac. Or you may need to use “menu button 2.” Same goes for the other named items in the above script.
Also keep in mind that the user you distribute this script to has to give System Events permission to control their Mac in the Security pane of System Preferences or this script won’t work. That can be a giant obstacle to distributing GUI scripts. And if you save your script as an Application, you have to digitally sign it or it won’t run on other people’s computers, and that can be complicated.

Resources