Getting several apps in fullscreen in a row via Applescript - bash

So I am writing a script that would set up my working environment by opening and then getting several apps in fullscreen via a single command line. I am having trouble with the "getting the apps in fullscreen" part, and the script execution is very confusing to me.
My hardware is a MacBook Pro (15-inch, 2017) running on macOS Catalina 10.15.7.
Here is the part of the script that behaves erraticaly when executed:
script1.scpt:
tell application "Sublime Text"
activate
tell application "System Events"
tell front window of (first process whose frontmost is true)
set value of attribute "AXFullScreen" to true
end tell
key code 123 using {control down}
end tell
end tell
When executed while the app (here, Sublime Text) is not in fullscreen via the command osascript script1.scpt, the app is activated and goes fullscreen, but key code 123 using {control down} does not work, without producing any error message or sound.
When executed while the app is already in fullscreen via the command osascript script1.scpt, the app is activated, stays in fullscreen as intended but I get this error message:
execution error: System Events got an error: Can't get window 1 of process 1 whose frontmost = true. Invalid index. (-1719)
Also, key code 123 using {control down} does not work either.
When executed via a shell script calling script1.scpt while the app is not in fullscreen, the app behaves exactly as in case 1.
When executed via a shell script calling script1.scpt while the app is already in fullscreen, the app behaves exactly as it should and everything seems fine. But if I lengthen the script to get 2 apps in fullscreen in a row as in script2.scpt (see below), the 2nd app does stricly nothing, and I get the error message of case 2 again.
script2.scpt:
tell application "Sublime Text"
activate
tell application "System Events"
tell front window of (first process whose frontmost is true)
set value of attribute "AXFullScreen" to true
end tell
key code 123 using {control down}
end tell
end tell
tell application "Skim"
activate
tell application "System Events"
tell front window of (first process whose frontmost is true)
set value of attribute "AXFullScreen" to true
end tell
key code 123 using {control down}
end tell
end tell
I have been spending hours trying to understand what is going on without success, so any help or clue would be very welcome.
The only way I found to get things working is to separate the code in separate steps with 0.5sec pauses in-between them, like in the following shell script code block. But I would like to find a faster and "cleaner" solution to my problem.
osascript -e "tell application \"Sublime Text\" to activate" ;
sleep 0.5 ;
osascript -e "tell application \"System Events\"" -e "tell front window of (first process whose frontmost is true)" -e "set value of attribute \"AXFullScreen\" to true" -e "end tell" -e "end tell" ;
sleep 0.5 ;
osascript -e "tell application \"Skim\" to activate" ;
sleep 0.5 ;
osascript -e "tell application \"System Events\"" -e "tell front window of (first process whose frontmost is true)" -e "set value of attribute \"AXFullScreen\" to true" -e "end tell" -e "end tell" ;
sleep 0.5 ;
osascript -e "tell application \"Finder\" to activate" ;
sleep 0.5 ;
osascript -e "tell application \"System Events\"" -e "tell front window of (first process whose frontmost is true)" -e "set value of attribute \"AXFullScreen\" to true" -e "end tell" -e "end tell" ;
sleep 0.5 ;
osascript -e "tell application \"Terminal\" to activate" ;
sleep 0.5 ;
osascript -e "tell application \"System Events\"" -e "tell front window of (first process whose frontmost is true)" -e "set value of attribute \"AXFullScreen\" to true" -e "end tell" -e "end tell"'
EDIT: For the moment being, I managed to get my script doing what I wanted it to do pretty reliably. Not completely satisfied though, because I still have to rely on fixed delays and this makes the execution a bit slow. This is what the code looks like:
in .bash_profile:
cd ~/<path>/ ;
osascript workspace_on.scpt
workspace_on.scpt:
tell app "System Events" to tell process "Terminal" to set the value of attribute "AXFullScreen" of window 1 to true
delay 0.6
tell app "Sublime Text" to activate
delay 0.6
tell app "System Events" to tell process "Sublime Text" to set the value of attribute "AXFullScreen" of window 1 to true
delay 0.6
do shell script "open -a skim ~/<path>/main.pdf"
delay 1
tell app "Skim" to set interaction mode of document 1 to full screen mode
delay 0.6
do shell script "open ~/<path>"
delay 1
tell app "System Events" to tell process "Finder" to set the value of attribute "AXFullScreen" of window "latex-template" to true

Just to copy-and-paste my most recent comment from above:
“Like you, I've spent a bit too much time figuring out this problem. It's quite a frustrating situation because I had a few light bulb moments of inspiration that, in theory, ought to have worked, and worked well, but ultimately didn't work at all. ¯_(ツ)_/¯ But in the process, I've at least written out a naive implementation that incorporates conditional checks and operates on each app one-by-one. It's not what I had aimed for in my head, but it works. See below.”
set Apps to {"TextEdit", "ManOpen", "Usenapp", "QuickTime Player"}
tell application id "com.apple.SystemEvents"
set dock to list 1 in the process named "Dock"
repeat with A in the Apps
tell my application named A to activate
set _P to (a reference to the process named A)
set _W to (a reference to _P's front window)
set _B to (a reference to the value of _W's ¬
attribute "AXFullScreenButton")
set _M to (a reference to (_P's menu bar 1's ¬
menu bar items's menu 1's menu items ¬
whose name = "Enter Full Screen"))
tell (a reference to (the dock's ¬
first UI element whose ¬
name = A)) to if ¬
exists then click
tell _W to repeat 60 times -- 60 x 0.5 = 30 seconds
delay 0.5
if it exists then
click _B
if (the value of attribute ¬
"AXFullScreen") ¬
then exit repeat
end if
end repeat
end repeat
end tell
System information:
AppleScript version: 2.8 system version: 12.6 ("Monterey")

Related

How to open multiple panes on iTerm?

I have created aliases of applescripts to open multiple panes on iTerm. However, ever since the latest update the scripts stopped working. I keep getting this error:
syntax error: Expected end of line but found identifier. (-2741)
Here's the script:
newPaneDown() {
osascript -e "
tell application \"iTerm\"
make new terminal
tell the current terminal
activate current session
tell the last session
tell i term application \"System Events\" to key code 2 using {shift down, command down}
end tell
end tell
end tell"
}
newPaneLeft() {
osascript -e "
tell application \"iTerm\"
make new terminal
tell the current terminal
activate current session
tell the last session
tell i term application \"System Events\" to key code 2 using command down
end tell
end tell
end tell"
}
newPanes4x4() {
/usr/bin/env osascript <<-EOF
tell application "iTerm"
activate
launch session "Panes"
tell i term application "System Events" to keystroke "d" using command down
tell i term application "System Events" to keystroke "D" using command down
tell i term application "System Events" to keystroke "[" using command down
tell i term application "System Events" to keystroke "[" using command down
tell i term application "System Events" to keystroke "D" using command down
end tell
EOF
}
alias p2='newPaneLeft'
alias p3='newPaneDown && newPaneLeft'
alias p4='newPanes4x4'
Applescript is not backwards compatible since iTerm2 Version 3.
The new Applescript syntax is described here.
You should replace:
make new terminal
with
create window with default profile

How to close a Terminal tab using AppleScript?

I'm using AppleScript to open PostgreSQL in a Terminal tab like this:
#!/bin/bash
function new_tab() {
TAB_NAME=$1
COMMAND=$2
osascript \
-e "tell application \"Terminal\"" \
-e "tell application \"System Events\" to keystroke \"t\" using {command down}" \
-e "do script \"printf '\\\e]1;$TAB_NAME\\\a'; $COMMAND\" in front window" \
-e "end tell" > /dev/null
}
new_tab "PostgreSQL" "postgres -D /usr/local/var/postgres"
Running this script from the Terminal will open a new tab with PostgreSQL server inside. So at the end of the execution I'll have 2 tabs: the first one which was used to run the script, and the second one containing the server.
How can I close the first one?
This is my try:
osascript -e "tell application \"Terminal\" to close tab 1 of window 1"
But I get this error message:
execution error: Terminal got an error: tab 1 of window 1 doesn’t
understand the “close” message. (-1708)
You can try something like this:
tell application "Terminal"
activate
tell window 1
set selected tab to tab 1
my closeTabOne()
end tell
end tell
on closeTabOne()
activate application "Terminal"
delay 0.5
tell application "System Events"
tell process "Terminal"
keystroke "w" using {command down}
end tell
end tell
end closeTabOne
One way to do it is like this:
osascript \
-e "tell application \"Terminal\"" \
-e "do script \"exit\" in tab 1 of front window" \
-e "end tell" > /dev/null
But Terminal must be configured to close the window when the shell exits.
Anyone has a solution which does not need to do this?
This will close the active tab only:
tell application "Terminal" to close (get window 1)
To determine the tab’s window, you can parse the error message you get when trying to access the still non-existing window property of the tab. The error message usually contains the window's id with which you can reference the window.
As your question is 5 years old, I’ll finish my answer with example code that can be run in the Script Editor instead of a bash script which makes it hard to read.
tell application "Terminal"
-- Perform command
set theTab to do script "echo 'Hello World'"
try
-- Try to get the tab's window (this should fail)
set theWindow to window of theTab
on error eMsg number eNum
if eNum = -1728 then
(*
The error message should look like this:
Terminal got an error: Can’t get window of tab 1 of window id 6270.
*)
-- Specify the expected text that comes before the window id
set windowIdPrefix to "window id "
-- Find the position of the window id
set windowIdPosition to (offset of windowIdPrefix in eMsg) + (length of windowIdPrefix)
-- Get the window id (omitting the period and everything else after)
set windowId to (first word of (text windowIdPosition thru -1 of eMsg)) as integer
-- Store the window object in a variable
set theWindow to window id windowId
else
-- Some other error occurred; raise it
error eMsg number eNum
end if
end try
close theWindow
end tell
I think the key is to get the id of front window.
tell application "Terminal"
do script "pwd"
set myID to id of front window
close window id myID
end tell

Have a script wait until the last script is complete

I have a script that has two apple scripts that open a new tab and do a command. I want the second apple script to wait until the first apple script's command line action is completed. I would rather not have to only to a sleep for x long, before it continues.
Is there a way that I can do this?
Here is what I have:
osascript -e 'tell application "Terminal" to activate' \
-e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
-e 'tell application "Terminal" to do script "cd '$current_dir'" in selected tab of the front window' \
-e 'tell application "Terminal" to do script "./my_script arg1" in selected tab of the front window'
------ Wait until this process is finished -------
osascript -e 'tell application "Terminal" to activate' \
-e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
-e 'tell application "Terminal" to do script "cd '$current_dir'" in selected tab of the front window' \
-e 'tell application "Terminal" to do script "./my_script different_arg1" in selected tab of the front window'
You can check the busy property of a window or tab:
tell application "Terminal"
set w to do script "sleep 1"
repeat
delay 0.1
if not busy of w then exit repeat
end repeat
end tell
osascript -e 'on run {a}
tell application "Terminal"
activate
tell application "System Events" to keystroke "t" using command down
do script "cd " & quoted form of a & "; sleep 1" in window 1
repeat
delay 0.1
if not busy of window 1 then exit repeat
end repeat
tell application "System Events" to keystroke "t" using command down
do script "cd " & quoted form of a & "; sleep 1" in window 1
end tell
end run' /tmp

applescript to osascript conversion?

I am using max msp to run shell commands, I have been prototyping code in applescript and need them to run in osascript for example -
tell application "Google Chrome" to close tab 1 of window 1
converts to
osascript -e 'tell application \"Google Chrome\" to close tab 1 of window 1'
I have converted around 10 commands, but am stuck on the very last one which is
tell application "Google Chrome" to activate
tell application "System Events"
tell process "Google Chrome"
do shell script "/usr/local/bin/cliclick/ c:360,550"
end tell
end tell
which I think goes to
osascript -e 'tell application \"Google Chrome\" to activate' -e 'tell application \"System Events\" to tell process \"Google Chrome\" to do shell script \"/usr/local/bin/cliclick c:360, 550\"'
cliclick lets you use the mouse through shell. http://www.bluem.net/en/mac/cliclick/. The c is the command identifier for clicking, so at x360 y550
is my syntax correct? it works when I dont include the c identifier.
Thanks
I tried this and it gave me this error message:
99:151: execution error: System Events got an error: Invalid argument “360,” to command “c”: Expected two coordinates, separated by a comma. Example: “c:123,456” (1)
Solution: you have an extra space before the number 550 (c:360, 550) and the second value gets lost. Remove the space character and it should work (c:360,550)…
Here is a version where I also changed the quoting:
osascript -e "tell application \"Safari\" to activate" -e "tell application \"System Events\" to tell process \"Safari\" to do shell script \"/usr/local/bin/cliclick c:360,550\""

How to distinct multiple java processes in AppleScript

I encounter a problem when writting osascript. I need to "tell" one java process (GUI) to do something but there are other java process with the same process name "java" (also GUI),
so my below sample code will not work for me:
osascript \
-e "tell application \"System Events\"" \
-e "tell process \"java\"" \
-e "click button \"MyButton\" of tab group 1 of window \"MyWindow\"" \
-e "end tell" \
-e "end tell"
So my question is how to distinct different java process in such scenario?
Based on your response to my comment, I would do something like the following. Note that I did not test this so you'll probably have to tweak it but it shows how you can check for those specific names. Good luck.
tell application "System Events"
set javaProcesses to processes whose name is "java"
repeat with aJavaProcess in javaProcesses
tell aJavaProcess
try
set windowName to name of window 1
set buttonNames to title of buttons of tab group 1 of window 1
if windowName is "Java Control Panel" and "Update Now" is in buttonNames then
click (first button of tab group 1 of window 1 whose title is "Update Now")
exit repeat
end if
end try
end tell
end repeat
end tell
EDIT: maybe you can get at the proper process like this...
tell application "System Events"
set javaIDs to unix id of processes whose name is "java"
repeat with i from 1 to count of javaIDs
set aJavaProcess to (first process whose unix id is (item i of javaIDs))
tell aJavaProcess
-- do the stuff in the tell block from the code above
end tell
end repeat
end tell

Resources