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.

1 Like

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.

3 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.

const app = Application.currentApplication()
app.includeStandardAdditions = true

function getJSON(path) {
	const fullPath = path.replace(/^~/, app.pathTo('home folder'))
	const contents = app.read(fullPath)
	return JSON.parse(contents)
}

function run() {

	let focus = "No focus" // default
	const assert = getJSON("~/Library/DoNotDisturb/DB/Assertions.json").data[0].storeAssertionRecords
	const config = getJSON("~/Library/DoNotDisturb/DB/ModeConfigurations.json").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
}
7 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.

4 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.

1 Like

Any chance to set the focus mode via script?

Welcome! Probably easiest by creating a Shortcut with the Set Focus action and running with shortcuts.

Thank you akerr! This is greatā€¦

1 Like

Hi! First post hereā€¦just made an account to thank @akerr and all the others pitching in. Hereā€™s the icloud link to the Shortcut I made with your help:

iCloud Shortcut: Toggle Focus Mode

It checks whether thereā€™s a Focus Mode running. If there is, it turns focus off. If itā€™s off, it prompts you to select which Mode you want to turn on.

I finally used this in BetterTouchTool on a button for the TouchBar.

2 Likes

OH THIS IS PERFECT TIMING!

I just made a Stream Deck / Keyboard Maestro button for showing what is the current active Focus Mode, if any.

The next step was going to be how to do exactly what this Shortcut does.

Once I have a chance to test it a bit more, I will release it for the community to use.