Skip to content

Instantly share code, notes, and snippets.

@RobTrew
Last active May 11, 2024 07:04
Show Gist options
  • Save RobTrew/2a57cd45fae7162ddf40 to your computer and use it in GitHub Desktop.
Save RobTrew/2a57cd45fae7162ddf40 to your computer and use it in GitHub Desktop.
Toggling OS X Sound Output Devices with JXA Javascript for Automation (OS X 10.10)
// Rob Trew @complexpoint 2015
function run() {
"use strict";
var blnUseKeyboardMaestro = false;
// EDIT TO NAMES OF TWO ALTERNATIVE SOUND OUTPUT DEVICES
var dctSources = { // A unique substring for each is enough
primary: "Internal",
secondary: "Elgato"
}
if (blnUseKeyboardMaestro) {
// NB if you are using KeyBoard Maestro, the values of the KM variables,
var strVarNameONE = "soundDeviceONE"
var strVarNameTWO = "soundDeviceTWO"
// take precedence (as long as they are both set,
// and different from the strings above)
// Otherwise, [blnUseKeyboardMaestro = false]
// the dctSources setting above will be used
var oPrimary = findOrMakeKMVar(strVarNameONE),
oSecondary = findOrMakeKMVar(strVarNameTWO),
kmvarPrimary = oPrimary.value(),
kmvarSecondary = oSecondary.value();
if (kmvarPrimary) dctSources.primary = kmvarPrimary;
else oPrimary.value = dctSources.primary;
if (kmvarSecondary) dctSources.secondary = kmvarSecondary;
else oSecondary.value = dctSources.secondary;
}
// ASSUMING / CREATING TWO KEYBOARD MAESTRO VARIABLES
// Get a reference to a Keyboard Maestro variable
function findOrMakeKMVar(strName) {
var appKM = Application("Keyboard Maestro Engine"),
oVars = appKM.variables;
try {
oVars[strName].name();
} catch (e) {
oVars.push(appKM.Variable({
'name': strName
}));
}
return oVars[strName];
}
var appPrefs = Application("System Preferences"),
blnFound = false,
strLegend, strMsg;
// FIND SOUND TAB OF SYS PREFS
appPrefs.panes[
"com.apple.preference.sound"
].anchors["output"].reveal();
// FIND CURRENT DEVICE SELECTION
var rows = Application("System Events").processes[
"System Preferences"
].windows[0].tabGroups[0].scrollAreas[0].tables[0].rows,
strSeln = rows.where({
"selected": true
})[0].textFields[0].value();
// CHOOSE NEW TARGET BY TOGGLING
var strTarget = (strSeln.indexOf(dctSources.primary) !== -1) ?
dctSources.secondary :
dctSources.primary;
// FIND AND AND SELECT THE FIRST MATCHING LINE
rows().forEach(function (oRow) {
if (!blnFound) {
strLegend = oRow.textFields[0].value();
if (strLegend.indexOf(strTarget) !== -1) {
oRow.select();
blnFound = true;
}
}
});
// NOTIFY FAILURE OR NEW SETTING
var app = Application.currentApplication();
app.includeStandardAdditions = true;
app.activate();
app.displayNotification(
blnFound ?
"→ " + strLegend :
"Couldn't find a sound device containing this string: \"" + strTarget +
'\"', {
withTitle: "Sound Output Device " +
(blnFound ? '' : 'NOT ') + "Changed"
}
);
// AND TIDY UP
appPrefs.quit();
return blnFound;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment