Can anyone help me to get the active list on display in the Reminders app on OS X?
According to the applescript dictionary for reminders, the application has a "default list" property which is "the list currently active in the Reminders application."
However, this property always seems to return the first list in order in the lists sidebar, not the list which is actually being displayed and is active. I have found that if I rearrange the order of the lists in the sidebar, I will always get whichever I have made the first list, regardless of which is actually being viewed and worked with.
My application is to create a Keyboard Maestro trigger to run an AppleScript to print the list I am currently working on, but it does not appear that the Reminders app functions as is documented in its dictionary. (I have temporarily used a workaround of having the script pop up a chooser listing all the lists so I can select the one i want to print, but that's inefficient and inelegant).
Thanks!
Yes, you can, but you will have to use the bad GUI scripting. And in a bad way. Look:
--Do some GUI scripting to get the decription of a specific group
tell application "Reminders" to activate
tell application "System Events"
tell process "Reminders"
tell window "Reminders"
tell splitter group 1
tell group 1
set des to get description
end tell
end tell
end tell
end tell
end tell
--This description is in the format "Viewing MyList, 1 reminder" so get the part to the "," from des.
set text item delimiters to ","
set texitems to text items of des
set firstPart to get text item 1 of texitems
--Setting the delimiters back
set text item delimiters to ""
--Jump to charcter 9 of firstPart then converting to text
set listname to characters 9 thru end of firstPart as text
--Now we know the name of the current list, so do whatever you want:
tell application "Reminders" to get list listname
This works. But only if Reminders is open. And if Apple changes Reminders structure...
Related
I need to get a count of all windows per application. Every way I've tried to do this, I only get a count of windows that are assigned to the current (Mission Control) Desktop. (I'm currently running Mac OS X 10.7, so post-Spaces.) Is there any way to get a per-application count of all windows across all Desktops?
The crux of what I've tried:
tell application "System Events"
repeat with _app in (every process whose visible is true)
tell _app
log (name as string) & ": " & (count of every window)
end tell
end repeat
end tell
Note that the whose visible is true clause isn't the problem. It finds all of the appropriate processes, but once I ask the processes for windows, they only count the ones in the active Desktop.
I've tried pulling the log line out of the tell and using name of _app and count of every window of _app, but there's no difference. I've tried grabbing things other than processes from System Events, but anything useful ends up effectively being just a different way to get the same object. I've tried iterating over UI elements, but no windows show up that aren't on the current Desktop, though I do get a menubar for each application.
I'm fine with iterating across all Desktops (though not actually switching to all of them), but I can't even find a way to get a list of Desktops. This answer claims to describe how to do that, but I only ever get a single element inside every desktop. Not that there's an obvious way to get windows once you have that Desktop object anyway.
It's also worth pointing out that desktops are controlled by the Dock, and not by Mission Control. I'm not aware of any way for AppleScript to talk to the Dock, so if you know of something, then an answer or comment about that might help point me in the right direction.
Am I trying to do something impossible?
I ran your code, setting up the Applescript version to 2.4 (do that as a habit); on the first run, your code presented me with the appropriate count of all the windows per application.
This code is what I tried, and the results seem to be satisfactory. Is there something I'm not seeing?
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application "System Events"
set my_list to {}
repeat with _app in (every process whose visible is true)
tell _app
log (name as string) & ": " & (count of every window)
set my_list to my_list & {name as string, count of every window}
end tell
end repeat
log my_list
end tell
As the OP is over six years old and I am unable to test under OS X 10.7, which is what was being used at that time, nonetheless, the following example AppleScript code works for me under macOS Catalina and returned the correct window count across all Desktops/Spaces, with the exception of any application that does understand the given AppleScript command and why the try and on error statements are being used.
Example AppleScript code:
tell application "System Events" to ¬
set appBundleIdentifierList to ¬
the bundle identifier of ¬
(every process whose visible is true)
repeat with appBundleIdentifier in appBundleIdentifierList
try
tell application id appBundleIdentifier to ¬
set {appName, winCount} to {name, (count windows)}
log appName & ": " & winCount
on error errorMessage
log errorMessage
end try
end repeat
Sample output on my system that has multiple Desktops/Spaces with windows of the application on all or some of the Desktops/Spaces and the window count for each is correct across all Desktops/Spaces, not just the active Desktop/Space the script was run from.
(*Safari: 6*)
(*Terminal: 2*)
(*TextEdit: 4*)
(*Script Editor: 7*)
(*Finder: 3*)
(*BBEdit: 1*)
(*Norton Secure VPN got an error: every window doesn’t understand the “count” message.*)
(*Music: 2*)
Notes:
Not all applications are AppleScript scriptable, in that some do not contain an AppleScript dictionary within their application bundle.
Since the application process cannot return the correct number of windows across all Desktops/Spaces, this method relies on the application to return the number of windows across all Desktops/Spaces.
Update:
The following example AppleScript code does the following:
Gets the bundle identifier of every process whose visible is true.
For each bundle identifier, get its name and the window count by querying the application directly. If the application understands the AppleScript command, then if goes to the next item in the appBundleIdentifierList list. If it does not understand, then the window count is calculated by the following:
Attempts to get an invisible window count as they would not show up on the Window menu of an application.
Calculates the window count by the number of windows shown on the Window menu of the application.
Failing these methods it get the window count by querying the application process, with is only accurate fo the active Desktop/Space and is included only for completeness of trying to ascertain the window count just using basic vanilla AppleScript.
Goes to the the application in the appBundleIdentifierList list.
Example AppleScript code:
set menuName to "Window"
tell application id "com.apple.systemevents" to ¬
set appBundleIdentifierList to ¬
the bundle identifier of ¬
(every process whose visible is true)
repeat with appBundleIdentifier in appBundleIdentifierList
try
tell application id appBundleIdentifier to ¬
set {appName, winCount} to {name, (count windows)}
log appName & ": " & winCount & ¬
" -- By querying the application directly."
on error
set winCount to 0
set notVisibleWindowList to {}
set errAppName to ¬
name of application id appBundleIdentifier
tell application id "com.apple.systemevents"
try
tell application process errAppName
set notVisibleWindowList to ¬
(windows whose visible is false)
if notVisibleWindowList is {} then ¬
set winCount to ¬
length of notVisibleWindowList
end tell
end try
try
set theTargetMenuItemsList to ¬
the reverse of ¬
(get name of ¬
menu items of ¬
menu menuName of ¬
menu bar item menuName of ¬
menu bar 1 of ¬
application process errAppName)
on error
set theTargetMenuItemsList to {}
end try
end tell
if theTargetMenuItemsList is not {} then
repeat with anItem in theTargetMenuItemsList
if contents of anItem is ¬
missing value then exit repeat
set winCount to winCount + 1
end repeat
log errAppName & ": " & winCount & ¬
" -- By querying the Window menu of the application process."
else
try
tell application id "com.apple.systemevents" to ¬
set winCount to ¬
(count windows of ¬
application process errAppName)
log errAppName & ": " & winCount & ¬
" -- By querying the application process. " & ¬
"May not be accurate, verify as necessary."
end try
end if
end try
end repeat
Running both versions of the example AppleScript code to show the difference in output:
First version of example AppleScript code:
(*Safari: 6*)
(*TextEdit: 4*)
(*Finder: 3*)
(*BBEdit: 1*)
(*Norton Secure VPN got an error: every window doesn’t understand the “count” message.*)
(*Music: 2*)
(*Sublime Text 2 got an error: every window doesn’t understand the “count” message.*)
(*DiskCatalogMaker got an error: every window doesn’t understand the “count” message.*)
(*Script Editor: 7*)
(*System Preferences: 2*)
(*VMware Fusion got an error: every window doesn’t understand the “count” message.*)
(*Activity Monitor got an error: every window doesn’t understand the “count” message.*)
(*Terminal: 2*)
Second version of example AppleScript code:
(*Safari: 6 -- By querying the application directly.*)
(*TextEdit: 4 -- By querying the application directly.*)
(*Finder: 3 -- By querying the application directly.*)
(*BBEdit: 1 -- By querying the application directly.*)
(*Norton Secure VPN: 0 -- By querying the application process. May not be accurate, verify as necessary.*)
(*Music: 2 -- By querying the application directly.*)
(*Sublime Text 2: 4 -- By querying the Window menu of the application process.*)
(*DiskCatalogMaker: 2 -- By querying the Window menu of the application process.*)
(*Script Editor: 7 -- By querying the application directly.*)
(*System Preferences: 2 -- By querying the application directly.*)
(*VMware Fusion: 1 -- By querying the Window menu of the application process.*)
(*Activity Monitor: 0 -- By querying the Window menu of the application process.*)
(*Terminal: 2 -- By querying the application directly.*)
As you can see even Activity Monitor, a native default macOS application, the Window menu had to be queried as the application directly didn't understand the basic count windows AppleScript command.
Although the output of the second version of the code was accurate across all Desktops/Spaces at the time it was executed, any application that has "By querying the application process. May not be accurate, verify as necessary." as part of its output only includes the window count of the active Desktop/Space it was executed form. The bottom line is using basic vanilla AppleScript there is no guarantee to get a complete accurate window count of every visible application unless all the applications at that time cen be queried directly. Querying the Window menu by its application process should also be accurate.
With that said, I think other methods may need to be used to get an accurate count.
I'm trying to different events depending on what application is currently the "open" application - The one which is foremost of the screen. I have managed to save the name of the application using a variable. Using this code.
tell application "System Events"
item 1 of (get name of processes whose frontmost is true)
set openWindow to (get name of processes whose frontmost is true)
do shell script "echo " & openWindow & " > /Users/name/temp/currentWindow.txt"
end tell
I then tried to use this code do different events for each open application
tell application "System Events"
if openWindow = "AppleScript Editor" then
display dialog "my variable: " & openWindow
end if
end tell
However this code does not apper to do anything, I don't have any error messages or anything however the code doesn't display the dialog box. If I place the code for the dialog box in the first section of code it will display the name of the open application.
Any ideas on how to get this to work, it would be very helpful
To explain your problem, it's because of this code...
set openWindow to (get name of processes whose frontmost is true)
That code returns a list of items. Notice you asked for processes (plural), so you can get more than one so applescript gives it to you as a list whether there's one or more items found. What's strange is that in the line above this you do ask for "item 1" of the list but for some reason you don't do anything with that line of code. Normally I would write that line of code like this so I only get item 1...
set openWindow to name of first process whose frontmost is true
Anyway, you can't compare the string "AppleScript Editor" to a list {"AppleScript Editor"}. They are not equal so your if statement is never true.
Display dialog displays a string. So when you move that code outside the if statement, applescript is smart enough to convert your list into a string so it can be displayed.
So bottom line is you are getting a list and you must access the items of the list. The items are strings so get one (in your case you want item 1) and use that in the if statement.
Hopefully you can learn from this explanation. Good luck.
In the first script cast the openWindow variable to a string:
set openWindow to (get name of processes whose frontmost is true) as string
I just purchased Alfred App for my Mac and I want to use this script I found online:
---------------------------------------------------
--Modified by: Pontus Sundén, http://psu.se
--Icon from: http://findicons.com/pack/1362/private_eye_act_1
---------------------------------------------------
on alfred_script(strQuery)
--Get the parameters passed to the script - this is the search query
set strSearchCriteria to SpaceList(strQuery)
--Try to populated an existing window with the search query
tell application "Evernote"
try
set query string of window 1 to strSearchCriteria
on error
--No existing window, open an new one
open collection window with query string strSearchCriteria
end try
end tell
tell application "System Events" to set frontmost of process "Evernote" to true
end alfred_script
--Take a list of text items and retrun them as a string with a space between each item
on SpaceList(astrItems)
--Store what the current list delimiter is
set tmpDelimiters to AppleScript's text item delimiters
--Set the list delimiter to a space and build the string we want to pass back
set AppleScript's text item delimiters to " "
set strReturn to astrItems as string
--Set the list delimiter back to what it was previously
set AppleScript's text item delimiters to tmpDelimiters
--Return the string we built
return strReturn
end SpaceList
which should open up evernote and search for something. It works fine, but instead of searching for, say the word boat, it will search for "boat" with the double quotes and obviously this yields no matches.
Your script is perfectly correct – the spurious quoting of search terms passed via AppleScript is a known Evernote bug in version 3 of the client (well, “known” as in “I opened a support ticket for it a while ago, and Evernote acknowledged it”; I’d add a link to the ticket, but these are private to the user who opened it … will update on progress, though).
Until they get around to fix it, you will have to either use the suggested GUI Scripting solution as a workaround, or correct the search strings manually.
You can use UI scripting to populate the search field like this:
set xxx to "boat"
activate application "Evernote"
tell application "System Events" to tell process "Evernote"
set value of text field 1 of group 4 of tool bar 1 of window 1 to xxx
end tell
I am trying to make a script that will get the contents of an email message that I'm composing in Mail, do something with the data, and then send the message. I know how to make and send a new message from scratch with AppleScript, but I can't find a way to get a message that I'm already writing. I don't care what language is used, and I would be open to trying a different email client. Thanks for your help!
Mail has huge limitations with regards to Applescript and dealing with its content area is a major one. The best bet is to use GUI scripting to tab to the content area, type cmd-C, and then work off the data in the clipboard.
Sadly from what I can see Applescript has not been improved at all in Lion.
It's actually pretty easy to do what you need.
If you want to run some kind of an inline processing (assigned to, say, a hotkey (in Mail, e.g. Cmd+D is not occupied), or "just" listed in the Services menu, accessible after selecting something), you can simply use Automator. A demo Automator script reading the current selection, making some changes (here, converting some ASCII char+number combinations to some accented characters) and, finally, returning the modified text is as follows:
on run {input, parameters}
set myText to replaceText("a1", "á", (input as text))
set myText to replaceText("e1", "é", myText)
set myText to replaceText("i1", "í", myText)
return myText
end run
on replaceText(find, replace, someText)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set someText to text items of someText
set text item delimiters of AppleScript to replace
set someText to "" & someText
set text item delimiters of AppleScript to prevTIDs
return someText
end replaceText
Make sure you enable the "Replaces selected text", should you want to overwrite the original content with the returned one.
if you want to write an external script not invoked from the local Services menu (or via a hotkey), you'll also need to add clipboard handling. A solution similar to the above with additional clipboard copy/paste:
on replaceText(find, replace, someText)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set someText to text items of someText
set text item delimiters of AppleScript to replace
set someText to "" & someText
set text item delimiters of AppleScript to prevTIDs
return someText
end replaceText
tell application "Mail"
activate
tell application "System Events"
tell process "Mail"
click menu item "Select All" of menu "Edit" of menu bar 1
click menu item "Copy" of menu "Edit" of menu bar 1
end tell
end tell
end tell
tell application "Mail"
set textclip to (the clipboard)
end tell
set myText to replaceText("a1", "á", textclip)
set myText to replaceText("e1", "é", myText)
set myText to replaceText("i1", "í", myText)
set the clipboard to myText
tell application "Mail"
activate
tell application "System Events"
tell process "Mail"
click menu item "Paste" of menu "Edit" of menu bar 1
end tell
end tell
end tell
Note that the latter script selects (and, then, overwrites) the entire window contents. It should be easy to work on the current selection only.
It's possible, but painful. Painful enough that I'm still trying to work out exactly how to do something similar but in Safari. I've gotten to the point where I can find the textarea, but the documentation I've found for getting the content isn't working. (Unfortunately, that's pretty much par for the course for AppleScript; every program does stuff just a little bit differently from the next program.)
EDIT: ok, have some horrible evil which hopefully can be adapted to work with Mail: http://www.ece.cmu.edu/~allbery/edit_textarea.script
This is striaghtforward if we make two reasonably weak assumptions: that the message you're working on is frontmost, and that the subject of all draft messages is unique. Then, before running the script, save the message you're working on; this will place it in the drafts mailbox. Then, since the subject of the message is the name of the window, we can easily access it; and since we can easily access the drafts mailbox, we can combine the two. This gives us:
tell application "Mail"
set msgs to messages of drafts mailbox ¬
whose subject is (name of window 1 as string)
if (count of msgs) = 1 then
-- Do whatever
else
-- Error, disambiguate, whatever
end if
end tell
It's probably possible to make the script save the frontmost window, and it wouldn't surprise me if a freshly-saved message is always the first item of the drafts mailbox, but these are left as an exercise for the reader :-)
So I came across this in 2020 and with this Apple Script it is (now?) possible (whenever its still a bit hacky since I have to use the clipboard for this):
activate application "Mail"
tell application "System Events"
tell process "Mail"
set initialClipboardContent to (the clipboard as text)
set composeWindow to (first window whose title does not contain "Inbox")
set value of attribute "AXFocused" of UI element 1 of scroll area 1 of composeWindow to true
delay 0.05
# CMD + A
key code 0 using command down
delay 0.1
# CMD + C
key code 8 using command down
delay 0.1
set message to (the clipboard as text) as string
log message
set the clipboard to initialClipboardContent
end tell
end tell
Here a proof of concept:
This is an application specific problem. I am trying to find and select a tab in Terminal.app depending on contents within. Here is what I'm doing:
tell application "Terminal"
set foundTabs to (every tab of every window) whose contents contains "selectme"
repeat with possibleTab in foundTabs
try
set selected of possibleTab to true
end try
end repeat
end tell
This isn't acting as expected and is pretty foolproof. I wonder if someone can suggest a way to do this with much less code (for instance, the looping shouldn't really be necessary, but applescript is an elusive language).
Thanks
Thing is, the following Applescript will do what you want, but unless your "selectme" string is very unique, you will find it in many tabs.
But anyway, here you go:
tell application "Terminal"
set allWindows to number of windows
repeat with i from 1 to allWindows
set allTabs to number of tabs of window i
repeat with j from 1 to allTabs
if contents of tab j of window i contains "selectme" then
set frontmost of window i to true
set selected of tab j of window i to true
end if
end repeat
end repeat
end tell