Get NSTextFieldCell value using AppleScript - objective-c

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.

Related

Why AppleScript doesn't enter Repeat 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

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.

Possible to script the "Export" command in Microsoft Outlook 2019 on Apple OS?

I'm trying to automate export of my calendar on Outlook 2019 on Apple OS 10.13; I don't see the Export command in the scripting dictionary of the application. Am I missing it? Is there a better way to automate this?
What is Apple OS? Is it MacOS???
My Microsoft Outlook version is "version 16.29 (19090802)", the code below works on my MacOS 10.12.6. You can try if it works on your machine.
tell application "Microsoft Outlook"
activate
delay 0.3
end tell
tell application "System Events"
tell process "Microsoft Outlook"
set theExportAsName to "Outlook for Mac Archive.olm"
set theExportToFolder to "/Users/admin/Desktop"
--input the file name and the destination folder path you want to export as
tell menu item "Export..." of menu "File" of menu bar item "File" of menu bar 1
click
delay 0.5
end tell
--show the Export dialog (1/3), we need to deal with three dialogs totally.
--knowledge point 1: how to click menu item in APP menu bar
tell group 1 of group "What do you want to export?" of front window
if value of radio button "Items of these types:" is not 1 then
click radio button "Items of these types:"
end if
end tell
--1st we choose export items
tell group 1 of group 1 of group "What do you want to export?" of front window
if value of checkbox "Mail" is not 0 then
click checkbox "Mail"
end if
if value of checkbox "Calendar" is not 1 then
click checkbox "Calendar"
end if
if value of checkbox "Contacts " is not 0 then
click checkbox "Contacts "
end if
end tell
tell group 2 of group 1 of group "What do you want to export?" of front window
if value of checkbox "Notes" is not 0 then
click checkbox "Notes"
end if
if value of checkbox "Tasks" is not 0 then
click checkbox "Tasks"
end if
end tell
--2nd we check Calendar, uncheck all the others
click button "Continue" of front window
delay 0.5
--3rd click Continue button to go to next dialog window (2/3)
tell text field 1 of sheet 1 of front window
set value to theExportAsName
end tell
--1st we set the file name we want to use
set the clipboard to theExportToFolder
keystroke "G" using {command down, shift down}
delay 0.5
keystroke "v" using {command down}
delay 0.5
keystroke return
delay 0.5
--2nd we set the destination folder path we want to use
tell sheet 1 of front window
click button "Save"
delay 0.5
end tell
--3rd click Save button to go to the last dialog window (3/3)
tell front window
click button "Finish"
end tell
--1st click Finish button to finish this task
end tell
end tell
Note 1: the delay duration is longer than needed, I set it to big number to make the code run slowly, to make you see what happened. You can test then set smaller delay value to speed up the running.
Note 2: to these three dialog window, I all use the code below to get information about the UI elements - to see how to reference them.
tell application "Microsoft Outlook"
activate
delay 0.3
end tell
tell application "System Events"
tell process "Microsoft Outlook"
tell front window
set uiElems to entire contents
end tell
end tell
end tell
Note 3: I write some comments to explain each step of the code. You can test it on your machine. Please let me know if it helps.

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