I'm trying to use AppleScript to get the frontmost application, get its application process, and shuffle the window index.
As soon as I write a tell application "System Events"
, then I need to grant the executor Accessibility/assistive permissions in Security & Privacy system events.
But if I know the frontmost app ahead of time, I can move its windows without this permission, e.g. tell application "Finder" to make new window...
How can I make the frontmost application shuffle its windows around without granting the script the control of my computer permission?
As you've observed, System Events is able to retrieve the frontmost process
(and access its properties) without requiring assistive access, e.g.
tell application id ("com.apple.SystemEvents") ¬
to tell (the first application process ¬
where it is frontmost) to set frontApp ¬
to {id:bundle identifier, AppleScript:¬
has scripting terminology, name:name}
(* frontApp = {
id: "com.apple.ScriptEditor2",
AppleScript: true,
name: "Script Editor"
} *)
However, AppleScript provides a built-in method to retrieve the frontmost application
by way of the path to
scripting additions command:
return the path to the frontmost application
--> alias "ck-mac.ssd:System:Applications:Utilities:Script Editor.app:"
Generally speaking, it's better to use built-in methods in the first instance, as they're more efficient, don't require any special privileges or an external application to be running, and will return values using native type classes that will be universally understood by other components of the script.
However, if you know that, after retrieving the front application, your script end up calling out to System Events in order to, say, manipulate its windows, then it makes sense to use System Events to retrieve the frontmost application from the outset.
How can I make the frontmost application shuffle its windows around without granting the script the control of my computer permission?
Any and all applications on your computer can be placed into one of two categories: those that are scriptable, and those that aren't. Here, a scriptable application refers to an application that AppleScript can communicate with using messages called Apple events. This is the technology that allows AppleScript to interface with such applications and control their functionality.
This is distinct to the type of control conferred by System Events, which is a superficial† interaction with the visual elements that make up the graphical user interface of an application. Controlling applications using this so-called UI scripting should only ever be a last resort, and maybe not even then: it's unreliable and scripts often break between minor version app upgrades if parts of the user interface change (which they often do); it's temperamental during execution, because scripting the UI depends on visual elements being, well, visible, and can often become inaccessible when obscured beneath another application or when moved off-screen; and it's inconvenient to execute if the computer is being used, as the simulated interactions of a UI script are disrupted by the actual interactions of a physical user moving the mouse or typing at the keyboard.
However, since most applications are not scriptable, the option to use AppleScript to shuffle the windows of whichever application is at the front is probably going to present itself less frequently than not. Thus, the following will work fine if TextEdit is at the front:
set frontApp to the application named (the ¬
path to the frontmost application)
--> application "TextEdit"
tell the frontApp to set the last window's ¬
index to 1
--> Back window is brought to the front
In fact, that will probably work for the majority of scriptable applications, including Script Editor, Finder, Safari, and so on... However, it will throw an error if the front application is Affinity Photo, ChatGPT, Photo Booth (although this only has one window, I believe), or Amazon Prime Video, etc.
Therefore, if you want to have more universal control over the windows of your applications, regardless of whether or not they are scriptable, you will have to use System Events for those that are not scriptable, which then makes more sense to use System Events even for the ones that are scriptable. Either way, this will require assistive access, and there's no easy way around that.
† Not to be interpreted as benign, since the visual elements include every button and menu item exposed by the user interface, which clearly presents a potential security risk.