Get current focus mode via script

Has anyone found a way to ascertain the current Focus Mode status via any method short of using Keyboard Maestro to read the pixels of Control Center?

3 Likes

@RosemaryOrchard was using a change in focus to set a variable in Data Jar via a Shortcut automation. That data can then be referenced. You could write to an alternate location if required by your script of choice.

Hmm, unfortunately that solution seems to be “if you always set your focus mode with a shortcut you can also write that status somewhere and read it later,” which is not really what I mean. I’m looking for a standalone way to detect the current focus mode on macOS Monterey…

(I should also note that on macOS, you can’t set an automation to run when Focus mode changes.)

On i*OS you can trigger a shortcut when a focus mode is enabled/disabled.

I believe focus modes sync across devices, so setting the focus mode on the Mac can set it on another device, which can trigger the shortcut automation. This can then be used to set your own indicator, which can be synced across devices and then queried on the Mac.

1 Like

This is the case I use. I actually set these automations up on my Pushcut automation server, because that will never bother me by running extra automations.

1 Like

Wow! That’s very clever but also awful.

2 Likes

Agreed. It should be a built in action.

1 Like

I was looking for this too and, after some digging, ended up writing the following in Javascript for Automation (JXA). It works with the JXA action in Shortcuts and should work in Keyboard Maestro, Alfred, Script Editor, Automator, osascript etc. The output is the name of the current focus mode, if any.

function getJSON(path) {
	const fm = $.NSFileManager.defaultManager
	const data = fm.contentsAtPath($(path).stringByExpandingTildeInPath)
	const str = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding)
	return JSON.parse(ObjC.unwrap(str))
}

function run() {

	let focus = "No focus" // default
	const assert = getJSON("~/Library/DoNotDisturb/DB/Assertions.json").data[0].storeAssertionRecords
	const modecf = getJSON("~/Library/DoNotDisturb/DB/ModeConfigurations.json")
	const config = modecf.data[0].modeConfigurations

	if (assert) { // focus set manually

		const modeid = assert[0].assertionDetails.assertionDetailsModeIdentifier
		focus = config[modeid].mode.name

	} else { // focus set by trigger

		const date = new Date
		const now = date.getHours() * 60 + date.getMinutes()

		for (const modeid in config) {

			const triggers = config[modeid].triggers.triggers[0]
			if (triggers && triggers.enabledSetting == 2) {

				const start = triggers.timePeriodStartTimeHour * 60 + triggers.timePeriodStartTimeMinute
				const end = triggers.timePeriodEndTimeHour * 60 + triggers.timePeriodEndTimeMinute
				if (start < end) {
					if (now >= start && now < end) {
						focus = config[modeid].mode.name
					}
				} else if (start > end) { // includes midnight
					if (now >= start || now < end) {
						focus = config[modeid].mode.name
					}
				}
			}
		}
	}
	return focus
}
4 Likes

THANK YOU! This is awesome, and just what I was hoping was built-in to macOS.

Edited to Add

For those new to jxa, you can save this in Script Editor, just be sure to change the language to “JavaScript” at the top of the window. It can then be saved as a .scpt file.

If you want to use it with osascript without making a .scpt file, then you have to use the -l (That’s a lowercase -L) flag and specify the language, as osascript assumes plain-text is AppleScript. For example, I put the code into a plain-text file named whichfocus.jxa and ran it like this:

osascript -l JavaScript ./whichfocus.jxa

and it worked great.

Andrew - you might consider posting this as a Github gist so others can discover it.

2 Likes

Thanks and you’re welcome.

3 Likes

Hey @akerr - you’re on Six Colors!

1 Like

Cool! Thanks to @jsnell too - I’m glad it’s helpful. It was a fun little puzzle for me to learn a bit more JXA as well.

What’s especially nice about @akerr’s script is that it teaches us how to get the focus mode using any language. The code is very clear.

2 Likes

@akerr 's script is super useful. If it is helpful to anyone, the solution I’ve been using is to just have a value in data jar that I update using shortcuts automation any time the focus mode changes. Then I can do automation with that.

1 Like

Here’s another handy tip that I just learned today:

defaults read com.apple.controlcenter "NSStatusItem Visible FocusModes"

If that returns 0 then there is no focus mode on.

If that returns 1 then there is some focus mode on.

Still need @akerr’s solution if you want to know which Focus Mode is on, but if you are just looking to turn something on or off, knowing the current ‘general’ state might be sufficient.

This is also useful for telling of your attempt at turning a focus mode on was successful or not. Check the defaults read after, and make sure that it says 1 and you know that something turned on at least.

I’d still love to find a simple shell-script friendly way to get the name of the Focus Mode, but for the time being I just made a wrapper script around the JXA solution.