how to make the element selection to return null instead of throw error in applescript - macos

I am debugging a legacy desktop automation tool which use AppleScript for UI control on MacOS. One of the script keeps failing with error "System Events got an error: Can’t get static text \"2\" of window \"UISoup – mac_utils.py\" of application process \"pycharm\"." number -1728 from static text "2" of window "UISoup – mac_utils.py" of application process "pycharm", and here is the script
tell application "System Events" to tell process "PyCharm"
set visible to true
set uiElement to static text "2" of window "UISoup – mac_utils.py" of application process "pycharm" of application "System Events"
set layer to 1
if uiElement = null then
set layer to 0
set collectedElements to {UI elements of front window, layer}
else
set layer to layer + 1
set collectedElements to {null, layer}
if name of attributes of uiElement contains "AXChildren" then
set collectedElements to {value of attribute "AXChildren" of uiElement, layer}
end if
end if
end tell
It seems like this line set uiElement to static text "2" of window "UISoup – mac_utils.py" of application process "pycharm" of application "System Events" should set the uiElement to null if the element is not found. But in fact it will throw error instead. How to let it return null instead of throw error to make it works? Thank you.

In the AppleScript equivalent of null is missing value. When GUI scripting, the process should be frontmost. You can check existing of UI elements using command exists (you can use try block as well).
tell application "System Events" to tell process "PyCharm"
set frontmost to true
-- set visible to true
set uiElementExists to exists static text "2" of window "UISoup – mac_utils.py"
set layer to 1
if not uiElementExists then
set layer to 0
set collectedElements to {UI elements of front window, layer}
else
set layer to layer + 1
set collectedElements to {missing value, layer}
set uiElement to static text "2" of window "UISoup – mac_utils.py"
if name of attributes of uiElement contains "AXChildren" then
set collectedElements to {value of attribute "AXChildren" of uiElement, layer}
end if
end if
end tell

Related

Pressing cancel in choose from list will cause a error

When I execute this script, everything works fine, but then when I press the cancel button, the script just give me a error, "Can’t get item 1 of false"
set mailList to {"Hide Applications", "Quit Applications", "Full Volume"}
set mailType to choose from list mailList
if item 1 of mailType is "Hide Applications" then
tell application "Finder"
set visible of every process whose visible is true and name is not "Finder" to false
set the collapsed of windows to true
end tell
else if item 1 of mailType is "Full Volume" then
set volume output volume 100
else if item 1 of mailType is "Quit Applications" then
tell application "System Events" to set the visible of every process to true
set white_list to {"Finder"}
try
tell application "Finder"
set process_list to the name of every process whose visible is true
end tell
repeat with i from 1 to (number of items in process_list)
set this_process to item i of the process_list
if this_process is not in white_list then
tell application this_process
quit
end tell
end if
end repeat
on error
tell the current application to display dialog "An error has occurred!" & return & "This script will now quit" buttons {"Quit"} default button 1 with icon 0
end try
end if
You add a check if mailType is a boolean which would happen if you press cancel. The check would be inserted between line 2 and 3 and would look something like this:
...
if class of mailType = boolean then return
...
choose from list returns boolean false when the Cancel button is pressed.
Just abort the script immediately in this case
set mailType to choose from list mailList
if mailType is false then return

Getting Active Window via Applescript throws error, "Can’t get window 1 of process"

Script:
global frontApp, frontAppName, windowTitle
set windowTitle to ""
tell application "System Events"
set frontApp to first application process whose frontmost is true
set frontAppName to name of frontApp
tell process frontAppName
tell (1st window whose value of attribute "AXMain" is true)
set windowTitle to value of attribute "AXTitle"
end tell
end tell
end tell
return {frontAppName, windowTitle}
It works some times, but other times I get things like: [2021-03-15 19:43:53.947] [error] Error: 339:344: execution error: System Events got an error: Can’t get window 1 of process "Adobe Premiere Pro 2020" whose value of attribute "AXMain" = true. Invalid index. (-1719)
Any ideas?
Thanks!
This following repeat loop added to your AppleScript code should do the trick
global frontApp, frontAppName, windowTitle
set windowTitle to ""
tell application "System Events"
set frontApp to first application process whose frontmost is true
set frontAppName to name of frontApp
tell process frontAppName
repeat until exists of ¬
(1st window whose value of attribute "AXMain" is true)
delay 0.1
end repeat
tell (1st window whose value of attribute "AXMain" is true)
set windowTitle to value of attribute "AXTitle"
end tell
end tell
end tell
return {frontAppName, windowTitle}

Why is it reporting "Can't get value" when I ask for the title, not the value?

This is the same code as the application from my last few questions but this version is rewritten to run under "Script Editor" for debugging help.
The error is generated by this code's last line. Checking with Accessibility Inspector, ALL of the menu items have NIL values that is why I specifically reference the title instead.
-- `menu_click`, by Jacob Rus, September 2006
--
-- Accepts a list of form: `{"Finder", "View", "Arrange By", "Date"}`
-- Execute the specified menu item. In this case, assuming the Finder
-- is the active application, arranging the frontmost folder by date.
on menuClick(mList)
local appName, topMenu, r
-- Validate our input
if mList's length < 3 then error "Menu list is not long enough"
-- Set these variables for clarity and brevity later on
set {appName, topMenu} to (items 1 through 2 of mList)
set r to (items 3 through (mList's length) of mList)
-- This overly-long line calls the menu_recurse function with
-- two arguments: r, and a reference to the top-level menu
tell application "System Events" to my menuClickRecurse(r, ((process appName)'s ¬
(menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))
end menuClick
on menuClickRecurse(mList, parentObject)
local f, r
-- `f` = first item, `r` = rest of items
set f to item 1 of mList
if mList's length > 1 then set r to (items 2 through (mList's length) of mList)
-- either actually click the menu item, or recurse again
tell application "System Events"
if mList's length is 1 then
click parentObject's menu item f
else
my menuClickRecurse(r, (parentObject's (menu item f)'s (menu f)))
end if
end tell
end menuClickRecurse
local destination, libraryName, choices
set destination to "/Users/bryandunphy/music"
set libraryName to "Testing.xml"
tell application "iTunes" to activate
menuClick({"iTunes", "File", "Library", "Export Library…"})
tell application "System Events" to set the value of the text field "Save As:" of window "iTunes" of process "iTunes" to libraryName
tell application "System Events" to tell process "iTunes" to tell its front window's group 1's pop up button 1 to click
tell application "System Events" to tell process "iTunes" to set choices to the title of every menu item of menu 1 of pop up button 1 of group 1 of its front window
repeat with ndx from 1 to count of choices
if the value of choices's item ndx is "" then
tell application "System Events" to tell process "iTunes" to select (the menu item of menu 1 of pop up button 1 of group 1 of its front window whose title is equal to item (ndx - 1) of choices)
end if
end repeat
Because the 'choices' variable contains a list of strings, not a list of menu items, so remove the value of.
You can use the index of the menu instead of the whose clause --> whose title is equal to (....).
repeat with ndx from 1 to count of choices
if choices's item ndx is "" then
tell application "System Events" to tell process "iTunes" to select (menu item (ndx - 1) of menu 1 of pop up button 1 of group 1 of its front window)
exit repeat
end if
end repeat

Why does this Applescript cause "Export Library.scpt: execution error: System Events got an error: Can’t get process "i". (-1728)"?

ƒIt's caused when run through osascript from terminal using the command line "osascript Export\ Library.scpt /Users/bryandunphy/Development/iTunesLibraryConsolidator testing.xml".
same script as my last (solved) question but posting it's entirety this time.
-- `menu_click`, by Jacob Rus, September 2006
--
-- Accepts a list of form: `{"Finder", "View", "Arrange By", "Date"}`
-- Execute the specified menu item. In this case, assuming the Finder
-- is the active application, arranging the frontmost folder by date.
on menuClick(mList)
local appName, topMenu, r
-- Validate our input
if mList's length < 3 then error "Menu list is not long enough"
-- Set these variables for clarity and brevity later on
set {appName, topMenu} to (items 1 through 2 of mList)
set r to (items 3 through (mList's length) of mList)
-- This overly-long line calls the menu_recurse function with
-- two arguments: r, and a reference to the top-level menu
tell application "System Events" to my menuClickRecurse(r, ((process appName)'s ¬
(menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))
end menuClick
on menuClickRecurse(mList, parentObject)
local f, r
-- `f` = first item, `r` = rest of items
set f to item 1 of mList
if mList's length > 1 then set r to (items 2 through (mList's length) of mList)
-- either actually click the menu item, or recurse again
tell application "System Events"
if mList's length is 1 then
click parentObject's menu item f
else
my menuClickRecurse(r, (parentObject's (menu item f)'s (menu f)))
end if
end tell
end menuClickRecurse
-- Created by Bryan Dunphy during January of 2017
--
-- select the folder "directory" in Window "WinName" of Application "appName" and then clicks the default button if requested
-- if WinName is "" then it uses the frontmost window (to allow for unnamed windows)
-- REQUIRES "on handleDir" and "on findRoot" to work!
-- ONLY call switchDir
-- "createIt" is a boolean that will create any missing directories if it is set to "true".
-- "selectDefault" is a boolean indicating whether or not to click the window's default button after selecting the specified directory
-- returns "true" or "false" to indicate success.
-- clicks "Cancel" button on failure
-- Always returns "true" if "createIt" is set to "true"
on switchDir(directory, winName, appName, createIt, selectDefault)
local dirs, delim
set delim to AppleScript's text item delimiters
set AppleScript's text item delimiters to "/"
set dirs to every text item of directory
tell application "System Events" to tell process appName to set frontmost to true
my findRoot(appName, winName)
repeat with dir in dirs
if not handleDir(dir, winName, createIt) then
tell application "System Events" to tell process appName to tell button "Cancel" to click
return false
end if
end repeat
if selectDefault then keystroke return
return true
end switchDir
on handleDir(dir, winName, appName, createIt)
local foundIt
foundIt = false
local ndx
if winName is not "" then
repeat with ndx from 1 to (count of window winName's list 1)
if window winName's list 1's item ndx's value is equal to dir then
select window winName's list 1's item ndx
foundIt = true
exit repeat
end if
end repeat
else
repeat with ndx from 1 to (count of front window's list 1)
if front window's list 1's item ndx's value is equal to dir then
select front window's list 1's item ndx
foundIt = true
exit repeat
end if
end repeat
end if
if not foundIt then
if createIt then
if winName is not "" then
tell application "System Events" to tell process appName to tell window winName
tell button "New Folder"
click
repeat until window "New Folder" exists
delay 0.5
end repeat
set value of text field 1 of window "New Folder" to dir
tell button "Create" to click
return my handleDir(dir)
end tell
end tell
else
tell application "System Events" to tell process appName to tell its front window
tell button "New Folder"
click
repeat until window "New Folder" exists
delay 0.5
end repeat
set value of text field 1 of window "New Folder" to dir
tell button "Create" to click
return my handleDir(dir)
end tell
end tell
end if
end if
else
return foundIt
end if
end handleDir
on findRoot(appName, winName)
local rootName
if winName is not "" then
tell application "System Events" to tell process appName to tell window winName
tell pop up button 1
click
repeat until menu 1 exists
delay 0.5
end repeat
local ndx
repeat with ndx from 1 to (count of menu 1)
if the title of menu 1's menu item ndx is "" then
set rootName to the title of menu 1's menu item (ndx - 1)
select (menu 1's menu item (ndx - 1))
exit repeat
end if
end repeat
end tell
end tell
else
tell application "System Events" to tell process appName's front window
tell pop up button 1
click
repeat until menu 1 exists
delay 0.5
end repeat
local ndx
repeat with ndx from 1 to (count of menu 1)
if the title of menu 1's menu item ndx is "" then
set rootName to the title of menu 1's menu item (ndx - 1)
select (menu 1's menu item (ndx - 1))
exit repeat
end if
end repeat
end tell
end tell
end if
return rootName
end findRoot
on run (clp)
if clp's length is not 2 then error "Incorrect Parameters"
local destination, libraryName
set destination to clp's item 1
set libraryName to clp's item 2
menuClick("iTunes", "File", "Library", "Export Library…")
set value of parentObject's text field "Save As:" to (libraryName and ".xml")
tell pop up button 1 of group 1 of window "New iTunes Library" of process iTunes of application "System Events" to click
repeat with ndx from 1 to (count of parentObject's menu 1)
if title of menu item ndx is "" then
select menu item (ndx - 1)
exit repeat
end if
end repeat
my switchDir(destination, "iTunes", "iTunes", true, false)
set the value of text field "Save As:" of window "iTunes" to (libraryName + ".xml")
tell button "Save" of window "iTunes" to click
return (destination and "/" and libraryName and ".xml")
end run
Change:
menuClick("iTunes", "File", "Library", "Export Library…")
to:
menuClick({"iTunes", "File", "Library", "Export Library…"})
AppleScript's error reporting is truly awful (no tracebacks, for starters), and osascript is even worse than Script Editor for debugging. If you run the script in SE, it will at least highlight the line in your script where the error occurred. If that doesn't give you a clue, add log commands to report the script's progress. osascript will write logged messages to stderr. In SE, click the awful 'document' (show/hide log) icon at the bottom of the window, then select 'Messages'. If your time is worth more than $100, get yourself a copy of Script Debugger which also lets you add breakpoints and step through and inspect variables as the script runs.

Set value of an AXDateTimeArea

I want to set the value of an AXDateTimeArea GUI element via Applescript. Attached is a screenshot of the Accessibility Inspector showing the element.
This is the code that I tried. No errors are thrown, but the value of the element doesn't change.
set value of attribute "AXValue" of tElement to "2012-06-21 13:45:18 +0000"
Additionally I tried the following lines but no success nor an error thrown.
set value of tElement to "2012-06-21 13:45:18 +0000"
set value of tElement to (current date)
set value of attribute "AXValue" of tElement to (current date)
This is always within a loop over the content of the sheet/window:
tell application "System Events"
tell process "myprocess"
set tElements to entire contents of (get sheet 1 of window 1)
repeat with tElement in tElements
end repeat
end tell
end tell
This is a screenshot:

Resources