Toggle Calendar visibility via a script

I’m trying to set up my stock Calendar to hide/show specific calendars when I change focus modes (and various other times). As far as I can tell, there is no way to do this via AppleScript (at least, not in the Calendar AppleScript dictionary in Script Editor) or through UI scripting (no menu items for it).

Does anyone know of an AppleScript, terminal command, shell script, etc that will programmatically “check” or “uncheck” a calendar’s visibility?

You can use the click at command in System Events to simulate clicks on the calendar checkboxes. My calendar looks like this:

By figuring out the distances from the upper left corner of the window to the centers of the checkboxes and combining that with the upper left coordinates of the window, I can get AppleScript to click a box this way:

-- Coordinates of calendar checkboxes relative to the window
set xAny to 25
set yWork to 71
set yHome to yWork + 28
set yFamily to yHome + 28
set ySpecial to yFamily + 28
set yFed to ySpecial + 28

tell application "Calendar"
  activate
  delay 1
  set calWindow to bounds of front window
end tell

set xClick to (item 1 of calWindow) + xAny
set yClick to (item 2 of calWindow) + ySpecial

tell application "System Events"
  tell application process "Calendar"
    click at {xClick, yClick}
  end tell
end tell

This is hardly ideal, as it doesn’t check to see if the box is checked or not before clicking. Also, you have to activate Calendar.

If you have Keyboard Maestro, you can use its Click at Image action.

Thanks, @drdrang. I may try the AppleScript version. I started doing the click-at-image stuff in KM, but it got real messy real fast. (I have like 30 calendars). Especially when trying to deal with whether it was already checked or not. Seems like x/yClick or Click at Image are the only options for now. (Ideally, I would just use Fantastical’s calendar sets, but my work’s Exchange server blocks 3rd party calendar apps. :frowning:)

You can select and click by row – row 3 in this example, which is the second calendar under the group “On My Mac”:

tell application "System Events"
	tell application process "Calendar"
		set t to checkbox 1 of UI element 1 of row 3 of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
		set v to value of t
		if v = 1 then
			click t
		end if
	end tell
end tell

Allowing you to test if the checkbox is already ticked or not – making this calendar invisible if it is already visible.

Checking each row to see if “text field 1” = your calendar name would allow a script to work even if you added and deleted calendars.

This is the best way to go about it, but I gave up trying to work my way through the hierarchy of UI elements. How did you do it?

I still use a 2011 AppleScript from Nigel Garvey:

https://macscripter.net/viewtopic.php?pid=146903#p146903

Which dumps the information into TextEdit so that it is easier to work through the levels.

Exciting days back then for applescripters. When Bill Cheeseman launched his UI Browser it seemed that nothing was out of our reach :slight_smile:

1 Like

Oh, where has this script been all my life? I never bought UI Browser because I thought it would fail before I got my money’s worth from it.

UI Browser was free when I used it.

It was so long ago that I can’t remember exactly when this was… I can see lots of old scripts of mine from 2004 that targeted the UI, so think that it must have been around that time?

Followed quickly after by a number of Obj-C scripts that date from 2005.

So I was mistaken. The “exciting days” were in the previous decade!

1 Like

Here, long after the fact, is a simple solution that takes a numeric keyboard shortcut from some other program (e.g., Keyboard Maestro, BetterTouchTool, Shorcuts), toggling the visibility of the nth calendar. For example, ⌘1 to toggle the first calendar.

set triggerKey to 1 --pass input from some keyboard shortcut app 

tell application "System Events"
	tell process "Calendar"
		set calCheckboxes to checkboxes of UI elements of ¬
			rows of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window "Calendar"
		set calCheckboxes to my Flatten_List(calCheckboxes)
		click item triggerKey of calCheckboxes
	end tell
end tell

on Flatten_List(aList)
	if class of aList is not list then
		return {aList}
	else if length of aList is 0 then
		return aList
	else
		return Flatten_List(first item of aList) & (Flatten_List(rest of aList))
	end if
end Flatten_List

This is now built-in with Focus Filters on iOS and macOS, no script required.

This handler isnt neceesary.

Instead:

tell application "System Events" to tell (process "Calendar") ¬
        to tell UI elements of rows of outline 1 of scroll area 1 ¬
        of splitter group 1 of splitter group 1 of window 1 ¬
        to click checkbox triggerKey