Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automate darwin install #43

Merged
merged 14 commits into from
May 16, 2024
99 changes: 95 additions & 4 deletions lib/install/macos.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,100 @@
'use strict';

exports.install = async function() {
throw new Error('macos install not implemented');
const { exec: _exec } = require('child_process');
const { resolve } = require('path');
const { promisify } = require('util');

const LSREGISTER_EXECUTABLE_PATH =
'/System/Library/Frameworks/CoreServices.framework/Versions/Current/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister';
const APPLICATION_NAME = 'ATDriverGenericMacOS.app';
const EXTENSION_IDENTIFIER = 'com.bocoup.ATDriverGenericMacOS.ATDriverGenericMacOSExtension';
const VOICE_IDENTIFIER =
'com.bocoup.ATDriverGenericMacOS.ATDriverGenericMacOSExtension.ATDriverGenericMacOSExtension';
const SYSTEM_VOICE_IDENTIFIER = 'com.apple.Fred';
const PLUGIN_TRIPLET_IDENTIFIER = 'ausp atdg BOCU';

const exec = promisify(_exec);

/** @typedef {import('child_process').ExecOptions} ExecOptions */

/**
* @returns {Promise<void>}
*/
exports.install = async function () {
const options = await getExecOptions();

if (await isInstalled()) {
throw new Error('Already installed');
}

await removeQuarantine(options);
await registerExtensions(options);
await enableExtension();
await setSystemVoice(VOICE_IDENTIFIER);
};

exports.uninstall = async function() {
throw new Error('macos uninstall not implemented');
/**
* @returns {Promise<void>}
*/
exports.uninstall = async function () {
const options = await getExecOptions();

if (!(await isInstalled())) {
throw new Error('Not installed');
}

await setSystemVoice(SYSTEM_VOICE_IDENTIFIER);
await unregisterExtensions(options);
};

const isInstalled = async function () {
const { stdout } = await exec(`auval -v ${PLUGIN_TRIPLET_IDENTIFIER}`);
return /ATDriverGenericMacOSExtension/.test(stdout);
};

/**
* @returns {Promise<ExecOptions>}
*/
const getExecOptions = async function () {
return {
cwd: resolve(__dirname, '../../Release/macos'),
};
};

/**
* @param {ExecOptions} options
* @returns {Promise<void>}
*/
async function removeQuarantine(options) {
await exec(`xattr -r -d com.apple.quarantine ${APPLICATION_NAME}`, options);
}

/**
* @param {ExecOptions} options
* @returns {Promise<void>}
*/
async function registerExtensions(options) {
await exec(`${LSREGISTER_EXECUTABLE_PATH} -f -R -trusted ${APPLICATION_NAME}`, options);
}

/**
* @param {ExecOptions} options
* @returns {Promise<void>}
*/
async function unregisterExtensions(options) {
await exec(`${LSREGISTER_EXECUTABLE_PATH} -f -R -trusted -u ${APPLICATION_NAME}`, options);
}

async function enableExtension() {
await exec(`pluginkit -e use -i ${EXTENSION_IDENTIFIER}`);
}

/**
* @param {string} voice
* @returns {Promise<void>}
*/
async function setSystemVoice(voice) {
await exec(
`defaults write com.apple.Accessibility SpeechVoiceIdentifierForLanguage '{2 = {en = "${voice}";};}`,
);
}