Forked from stephancasas/toggle-do-not-disturb-ventura.jxa.js
Created
January 19, 2025 16:29
-
-
Save Lego2012/8442cbb783ca98b5ab6b379bdde400ba to your computer and use it in GitHub Desktop.
Toggle Do Not Disturb Ventura AppleScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env osascript -l JavaScript | |
/** | |
* ----------------------------------------------------------------------------- | |
* Toggle Do Not Disturb Mode from Control Center | |
* ----------------------------------------------------------------------------- | |
* | |
* Created on May 18, 2023 by Stephan Casas | |
* | |
* Options: | |
* - TARGET_DND_MODE | |
* The name of the Do Not Disturb mode to toggle. | |
* | |
* | |
* Notes: | |
* This script was tested on macOS 13 Ventura and may break with future OS | |
* updates. | |
*/ | |
const TARGET_DND_MODE = 'Do Not Disturb'; | |
const $attr = Ref(); | |
const $windows = Ref(); | |
const $children = Ref(); | |
function run(_) { | |
// Get the current Control Center PID. | |
const pid = $.NSRunningApplication.runningApplicationsWithBundleIdentifier( | |
'com.apple.controlcenter', | |
).firstObject.processIdentifier; | |
// Get the Control Center application. | |
const app = $.AXUIElementCreateApplication(pid); | |
// Get the Control Center menubar extra children. | |
$.AXUIElementCopyAttributeValue(app, 'AXChildren', $children); | |
$.AXUIElementCopyAttributeValue($children[0].js[0], 'AXChildren', $children); | |
// Locate the Control Center menubar extra (also has Clock, Users, etc.). | |
const ccExtra = $children[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXIdentifier', $attr); | |
return $attr[0].js == 'com.apple.menuextra.controlcenter'; | |
}); | |
// Open Control Center window and await draw. | |
$.AXUIElementPerformAction(ccExtra, 'AXPress'); | |
if ( | |
!(() => { | |
const timeout = new Date().getTime() + 2000; | |
while (true) { | |
$.AXUIElementCopyAttributeValue(app, 'AXWindows', $windows); | |
if ( | |
typeof $windows[0] == 'function' && | |
($windows[0].js.length ?? 0) > 0 | |
) { | |
return true; | |
} | |
if (new Date().getTime() > timeout) { | |
return false; | |
} | |
delay(0.1); | |
} | |
})() | |
) { | |
return; | |
} | |
// Get Control Center window children. | |
$.AXUIElementCopyAttributeValue($windows[0].js[0], 'AXChildren', $children); | |
// Locate the Control Center modules group. | |
const modulesGroup = $children[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXRole', $attr); | |
return $attr[0].js == 'AXGroup'; | |
}); | |
// Get the individual modules within the modules group. | |
$.AXUIElementCopyAttributeValue(modulesGroup, 'AXChildren', $children); | |
// Locate the focus modes module. | |
const focusModes = $children[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXIdentifier', $attr); | |
return $attr[0].js == 'controlcenter-focus-modes'; | |
}); | |
// Activate the Do Not Disturb module and await draw. | |
$.AXUIElementPerformAction( | |
focusModes, | |
// Wtf is this action name, Apple?? | |
'Name:show details\nTarget:0x0\nSelector:(null)', | |
); | |
if ( | |
!(() => { | |
const timeout = new Date().getTime() + 2000; | |
while (true) { | |
$.AXUIElementCopyAttributeValue(modulesGroup, 'AXChildren', $children); | |
if ( | |
typeof $children[0] == 'function' && | |
($children[0].js.length ?? 0) > 0 | |
) { | |
return true; | |
} | |
if (new Date().getTime() > timeout) { | |
return false; | |
} | |
delay(0.1); | |
} | |
})() | |
) { | |
return; | |
} | |
// Get the scroll area containing the DND options. | |
const dndOptions = $children[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXRole', $attr); | |
return $attr[0].js == 'AXScrollArea'; | |
}); | |
// Get all DND options. | |
$.AXUIElementCopyAttributeValue(dndOptions, 'AXChildren', $children); | |
// Locate the toggle element for the target DND mode. | |
const toggle = $children[0].js | |
.filter((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXRole', $attr); | |
return $attr[0].js == `AXCheckBox`; | |
}) | |
.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXAttributedDescription', $attr); | |
return `${$attr[0].string.js}`.toLowerCase() == TARGET_DND_MODE.toLowerCase(); | |
}); | |
if (!toggle) { | |
console.log('Error: Could not get toggle for target Do Not Disturb mode.'); | |
return 1; | |
} | |
// Press the toggle for the target DND mode. | |
$.AXUIElementPerformAction(toggle, 'AXPress'); | |
// Send ⎋ to dismiss Control Center. | |
$.CGEventPost($.kCGHIDEventTap, $.CGEventCreateKeyboardEvent(null, 53, true)); | |
return 0; | |
} | |
// prettier-ignore | |
(() => { | |
ObjC.import('Cocoa'); // yes, it's necessary -- stop telling me it isn't | |
ObjC.bindFunction('AXUIElementPerformAction', ['int', ['id', 'id']]); | |
ObjC.bindFunction('AXUIElementCreateApplication', ['id', ['unsigned int']]); | |
ObjC.bindFunction('AXUIElementCopyAttributeValue',['int', ['id', 'id', 'id*']]); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment