Why AppleScript doesn't enter Repeat loop - while-loop

My overall goal is to close Avast window during start up. Performing this repeat until loop does not trigger the code within the loop.
tell application "System Events"
set ids to bundle identifier of every application process
repeat until ids contains "com.avast.AAFM"
wait(1)
beep
set ids to bundle identifier of every application process
end repeat
tell application "System Events" to tell process "Avast" to tell the front window to if (exists) then tell attribute "AXCloseButton" to click its value
end tell
Using a clumsy brute force approach to check if com.avast.AAFM is one of the apps open before quitting. If not then wait a second and check again. I'm not understanding why the repeat loop isn't run. When Avast is running the script does close Avast.

Is wait a valid AppleScript command?
In this case I'd prefer a simple repeat loop and exit repeat
repeat
tell application "System Events" to set ids to bundle identifier of every application process
if ids contains "com.avast.AAFM" then exit repeat
delay 1
beep
end repeat
tell application "System Events" to tell process "Avast" to tell the front window to if (exists) then tell attribute "AXCloseButton" to click its value

You can close (on startup) any application windows simpler:
set appID to "com.avast.AAFM"
repeat until window 1 of application id appID exists
delay 1
end repeat
tell application id appID to close windows

Related

Is there any apple script to set the mission control keyboard options to null?

Steps to do:
Open System Preferences
Click on Mission Control
Under the Heading "Keyboard and Mouse Shortcuts" do the following
Select "-" for Mission Control
Select "-" for Application Windows
Select "-" for Show desktop
Note: Required for bigsur OS
[Image][1]
[1]: https://i.stack.imgur.com/syhEF.png
The example AppleScript code, shown below, was tested in Script Editor under macOS Catalina a with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.
1 Assumes necessary and appropriate setting in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.
Example AppleScript code:
-- # Check to see if System Preferences is
-- # running and if yes, then close it.
-- #
-- # This is done so the script will not fail
-- # if it is running and a modal sheet is
-- # showing, hence the use of 'killall'
-- # as 'quit' fails when done so, if it is.
-- #
-- # This is also done to allow default behaviors
-- # to be predictable from a clean occurrence.
if running of application "System Preferences" then
try
tell application "System Preferences" to quit
on error
do shell script "killall 'System Preferences'"
end try
delay 0.1
end if
-- # Make sure System Preferences is not running before
-- # opening it again. Otherwise there can be an issue
-- # when trying to reopen it while it's actually closing.
repeat while running of application "System Preferences" is true
delay 0.1
end repeat
-- # Open System Preferences to Mission Control.
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.expose"
end tell
tell application "System Events"
tell window 1 of application process "System Preferences"
-- Wait until UI ellements are available.
set i to 0
repeat until exists checkboxes of group 2
delay 0.1
set i to i + 1
if i ≥ 30 then return
end repeat
-- # Uncheck any checked ckeckboxes.
tell group 2
repeat with i from 1 to count checkboxes
if value of checkbox i is equal to 1 then click checkbox i
end repeat
end tell
-- # Set all pop up buttons to: -
tell group 1
repeat with i from 1 to count pop up buttons
if value of pop up button i is not "-" then
click pop up button i
pick menu item "-" of menu 1 of pop up button i
end if
end repeat
end tell
end tell
end tell
tell application "System Preferences" to quit
Note: The example AppleScript code is just that and sans any included error handling 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.
Following script disables mission controls and set the shortcut options to null.
tell application "System Preferences"
activate
delay 1
set the current pane to pane id "com.apple.preference.expose"
delay 1
tell application "System Events"
tell checkbox "Group windows by application" of group 2 of window "Mission Control" of application process "System Preferences"
if (get its value) = 1 then click it
tell application "System Events"
tell checkbox "Automatically rearrange Spaces based on most recent use" of group 2 of window "Mission Control" of application process "System Preferences"
if (get its value) = 1 then click it
tell application "System Events"
tell checkbox "When switching to an application, switch to a Space with open windows for the application" of group 2 of window "Mission Control" of application process "System Preferences"
if (get its value) = 1 then click it
tell application "System Events"
tell checkbox "Displays have separate Spaces" of group 2 of window "Mission Control" of application process "System Preferences"
if (get its value) = 1 then click it
end tell
end tell
end tell
end tell
end tell
end tell
end tell
end tell
tell application "System Events" to tell process "System Preferences"
tell window "Mission Control"
tell pop up button 1 of group 1
if value is not "-" then
click
delay
pick menu item "-" of menu 1
end if
end tell
tell pop up button 2 of group 1
if value is not "-" then
click
delay
pick menu item "-" of menu 1
end if
end tell
tell pop up button 3 of group 1
if value is not "-" then
click
delay
pick menu item "-" of menu 1
end if
end tell
end tell
end tell
quit
end tell

Safari - AppleScript does not move to the next section of a bookdown online book

I am writing a script to print a section of a bookdown online book as PDF, then move to the next section, and so on.
The print part works (the key codes are from this page):
tell application "Safari"
activate
tell application "System Events"
key code 35 using command down -- activate print menu item
end tell
delay 0.5
set i to 0
repeat while i < 15
set i to i + 1
delay 0.1
tell application "System Events"
key code 48 -- press tab 15 times
end tell
end repeat
tell application "System Events"
key code 49 -- press space
end tell
set i to 0
repeat while i < 2
set i to i + 1
delay 0.1
tell application "System Events"
key code 125 -- press down key twice
end tell
end repeat
tell application "System Events"
key code 36 -- enter
end tell
set i to 0
repeat while i < 16
set i to i + 1
delay 0.1
tell application "System Events"
key code 125 -- press tab to get to "save"
end tell
end repeat
tell application "System Events"
key code 36 -- enter to cleck on save
end tell
end tell
Problem
Now that I have printed the current section and I am back on Safari, I can click manually on the right arrow and move to the next section, but I can't manage to have the script to do that.
I have tried to add the following to the script above:
tell application "System Events"
key code 124 -- right arrow to enter the next page
end tell
Or even to "reopen" Safari, but nothing happens.
tell application "Safari"
activate
tell application "System Events"
key code 124 -- right arrow to move to the next section
end tell
end tell
How can I have AppleScript "turn the page" and move to the next section?
Also, I welcome suggestions to improve the script! I wonder if it would be easy to avoid repeating "tab" 15 times. I have looked at the Accessibility Inspector and found that "PDF" in the print menu corresponds to NSPopUpButtonCell. I have tried to use select NSPopUpButtonCell of its sheet but it did not work.
I can click manually on the right arrow and move to the next section, but I can't manage to have the script to do that.
How can I have AppleScript "turn the page" and move to the next section?
If you are trying to programmatically click the right-arrow, as shown in the image below, then the following example AppleScript code can do that:
tell application "Safari" to ¬
tell document 1 to ¬
do JavaScript ¬
"document.getElementsByClassName('fa fa-angle-right')[0].click();"
Notes:
This requires Allow JavaScript from Apple Events to be check on the hidden Develop menu.
To unhide the hidden Develop menu:
Safari > Preferences… > Advanced > [√] Show Develop menu in menu bar
Update to address:
Also, I welcome suggestions to improve the script! I wonder if it would be easy to avoid repeating "tab" 15 times.
Here is how I'd use the JavaScript from above and coded to avoid using the key code and or keystroke System Events commands, especially tabbing around the UI.
Example AppleScript code:
tell application "System Events"
tell application process "Safari"
set frontmost to true
set i to 0
repeat until (its frontmost = true)
delay 0.1
set i to i + 1
if i ≥ 20 then return
end repeat
click menu item "Print…" of ¬
menu 1 of ¬
menu bar item "File" of ¬
menu bar 1
tell its front window
set i to 0
repeat until (exists menu button "PDF" of sheet 1)
delay 0.1
set i to i + 1
if i ≥ 20 then return
end repeat
click menu button "PDF" of sheet 1
set i to 0
repeat until (exists menu item "Save as PDF" of ¬
menu 1 of menu button "PDF" of sheet 1)
delay 0.1
set i to i + 1
if i ≥ 20 then return
end repeat
click menu item "Save as PDF" of ¬
menu 1 of ¬
menu button "PDF" of ¬
sheet 1
set i to 0
repeat until (exists button "Save" of sheet 1 of sheet 1)
delay 0.1
set i to i + 1
if i ≥ 20 then return
end repeat
click button "Save" of sheet 1 of sheet 1
set i to 0
repeat while (exists sheet 1)
delay 0.1
set i to i + 1
if i ≥ 100 then return
end repeat
end tell
end tell
end tell
tell application "Safari" to ¬
tell document 1 to ¬
do JavaScript ¬
"document.getElementsByClassName('fa fa-angle-right')[0].click();"
Notes:
Since this type of AppleScript script is using UI Scripting, I have included an error handling in the form of a repeat loop to wait up to two seconds for the target UI element to become available to be acted upon for most of the targets, however the last repeat loop waits longer because it has to wait until the Save as PDF to complete. A simple delay command with an appropriate value could be used instead, but with the include delay of a tenth of a second in the repeat loops it shouldn't have to wait any longer than need be. In other words, I'd only use simple delay command if I want to slow the script down from going through the various events of the UI. It's doubtful that it would need to be adjusted, but obviously do so as/if necessary.
If the timeout is reached, the script aborts at that point without any error message. The single-line if i ≥ 20 then return statements can be turned into a full if block and include an error message via the display dialog, display alert, or display notification command as wanted.

Get NSTextFieldCell value using AppleScript

I am trying to automate a few tasks where I need to get the text displayed on a dialog box (the 6 digit code).
Accessibility Inspector revealed the following hierarchy:
I am a beginner in the field of AppleScript and have read a few examples where something similar could be done like this:
set myText to textField's stringValue() as text
But I'm not sure if this could work in my case, as the Accessibility Inspector does not show any variable names for NSTextFieldCell which contains the 6 digit code.
How can I extract the 6 digit code in the NSTextFieldCell and possibly return this value so that a shell script can use this code?
I have something like this right now -
tell application "FollowUpUI"
activate
# get the 6 digit code
end tell
Update
After some help, i have tried to traverse to the text field
tell application "System Events"
repeat with theProcess in processes
#initialize
tell theProcess
set processName to name
set allWindows to windows
end tell
#check if process exists
if processName is "FollowUpUI" then
activate
say "FollowUpUI found"
set windowsCount to count of the allWindows
#only one window should exist
if windowsCount is 1 then
say "1 window was found"
tell window 1
tell group 1
tell text field 1
set code to value
end tell
end tell
end tell
end if
end if
end repeat
end tell
but i've got stuck because of an error -
System Events got an error: cant get window 1. Invalid index.
I am not sure if this is a syntax error. Any pointers would be helpful. Thanks
The error occurs because you have to reference window 1 of process "FollowUpUI"
Your code is too complicated, you just need to check if the process exists
tell application "System Events"
if exists process "FollowUpUI" then
tell process "FollowUpUI"
tell window 1
tell static text 1 of group 1
set code to its value
end tell
end tell
end tell
end if
end tell
If the code is a part of a workflow you have to wait until the window is open
tell application "System Events"
repeat until exists window 1 of process "FollowUpUI"
delay 0.2
end repeat
tell window 1 of process "FollowUpUI"
tell static text 1 of group 1
set code to its value
end tell
end tell
end tell
I added its before value to make sure that it refers to the current reference (the text field)
As you don't send key or mouse events to the window you don't need to activate anything.
Not an answer but I can't paste code in a comment. Here's a trick to get the UI Element. Hit Command-Shift-4 to get a cursor with coordinates. Aim at the UI Element and remember the coordinates. Click to get the arrow cursor back. Use the coordinates in this script.
activate application "FollowUpUI"
tell application "System Events"
tell application process "FollowUpUI"
click at {290, 150}
end tell
end tell
Script Editor must be allowed to control the computer. You can set this in the System prefs, Security & Privacy, Privacy.

applescript: work "whose" and "exists" into the same line

My problem can best be demonstrated with one line of code:
tell application "System Events" to tell application process "Dock" ¬
to tell list 1 to first UI element whose value of attribute "AXTitle" ¬
is "Trash"
This ends in error because not every UI element in Dock has attribute "AXTitle". dock separator item only has AXRole, AXRoleDescription, etc.
I want to know if there is a way to have the code return the correct UI element despite this.
Here is what I've tried and failed:
1) try block: This simply jump over this line of code and continue to next line
2) ignore application response block: Ditto.
3) exists(attribute "attributeName"): I was able to test each individual UI element with e.g. exists (attribute "AXTitle") of UI element 1, but I cannot works exists into whose statement: It should look something like this:
UI elements whose (exists (attribute "AXTitle") is true)
And that doesn't work. Right now I have to run a repeat with loop, a if statement inside, and an exit repeat so that I can cycle through everything. This is cumbersome.
There has to be a better way.
Clarification: A few people showed me more elegant ways to get to Trash. I used Trash as an example but meant the question to be broarder, namely how to find the first item of a list based on an attribute when a item in the list lacks this atrribute. Another example would be:
delay 5
tell application "System Events" to tell application process "Dock" ¬
to tell list 1 to first UI element whose value of attribute ¬
"AXSelected" is true
And move cursor to any item in the Dock. This example failed because again Dock Separator doesn't have the common field "AXSelected".
Just add another condition like this : whose subrole is not "AXSeparatorDockItem"
tell application "System Events"
tell application process "Dock" to tell list 1 to (first UI element whose subrole is not "AXSeparatorDockItem" and its selected is true)
end tell
--
Update : You can use the title property instead of value of attribute "AXTitle", this will not give error.
tell application "System Events"
tell application process "Dock" to tell list 1 to UI elements whose title is "Trash"
end tell
This worked for me, and is also better, since the title of the "Trash" is localized, here it is "Papirkurv". :)
tell application "System Events" to tell process "Dock"
tell list 1
get first UI element whose value of attribute "AXSubrole" is "AXTrashDockItem"
end tell
end tell
If you got Xcode installed, then you should have an app named UIElementInspector, which lets you read off the different values of the UI Elements.

How to close all, or only some, tabs in Safari using AppleScript?

I have made a very simple AppleScript to close tabs in Safari. The problem is, it works, but not completely. Only a couple of tabs are closed. Here's the code:
tell application "Safari"
repeat with aWindow in windows
repeat with aTab in tabs of aWindow
if [some condition is encountered] then
aTab close
end if
end repeat
end repeat
end tell
I've also tried this script:
tell application "Safari"
repeat with i from 0 to the number of items in windows
set aWindow to item i of windows
repeat with j from 0 to the number of tabs in aWindow
set aTab to item j of tabs of aWindow
if [some condition is encountered] then
aTab close
end if
end repeat
end repeat
end tell
... but it does not work either (same behavior).
I tried that on my system (MacBook Pro jan 2008), as well as on a Mac Pro G5 under Tiger and the script fails on both, albeit with a much less descriptive error on Tiger.
Running the script a few times closes a few tab each time until none is left, but always fails with the same error after closing a few tabs. Under Leopard I get an out of bounds error. Since I am using fast enumeration (not using "repeat from 0 to number of items in windows") I don't see how I can get an out of bounds error with this...
My goal is to use the Cocoa Scripting Bridge to close tabs in Safari from my Objective-C Cocoa application but the Scripting Bridge fails in the same manner. The non-deletable tabs show as NULL in the Xcode debugger, while the other tabs are valid objects from which I can get values back (such as their title). In fact I tried with the Scripting Bridge first then told myself why not try this directly in AppleScript and I was surprised to see the same results.
I must have a glaring omission or something in there... (seems like a bug in Safari AppleScript support to me... :S) I've used repeat loops and Obj-C 2.0 fast enumeration to iterate through collections before with zero problems, so I really don't see what's wrong here.
Anyone can help?
Thanks in advance!
I have a script that closes all of the tabs but does not need a repeat loop.
set closeTab to "Stack Overflow" as string
tell application "Safari"
close (every tab of window 1 whose name is not equal to closeTab)
end tell
See if that works for you.
Note: change "Stack Overflow" to whatever the title name is of
the tab you want to stay open.
this works for me nice and simple
tell application "Safari"
close every window
end tell
ok you have to go from the count to 1 otherwise the count will be off when you close the window
tell application "Safari"
repeat with i from (count of windows) to 1 by -1
repeat with j from (count of tabs of window i) to 1 by -1
set thistab to tab j of window i
set foo to name of thistab
if foo is not equal to "bar" then close thistab
end repeat
end repeat
end tell
Both provided answers are fine, but I think it is better to combine both. This way you will be closing all tabs of all chrome windows, and it is less verbose than the first answer:
set closeTab to "Post Attendee" as string
tell application "Google Chrome"
repeat with i from (count of windows) to 1 by -1
close (every tab of window i whose name is not equal to closeTab)
end repeat
end tell