#!/bin/sh # Installs JOKey for this user account: curl -sS https://afixer.app/jokey/install.sh | sh # A given version: curl -sS https://afixer.app/jokey/install.sh | V=1.0.0 sh # # Every earlier JOKey goes first (the 1.x input method, 2.x, their settings). # JOKey 2 is the "JOKey" keyboard layout plus ~/Applications/JOKey.app, which # starts at login and types the Vietnamese while the layout is selected. It is # not notarized (ad-hoc signed, no Apple Developer ID), so this script clears # the download quarantine itself instead of going through Gatekeeper. # # Top-level `echo` lines are shown on the website as the install transcript: # keep them plain, and indent the ones on error and optional paths. MAC_VERSION=$(sw_vers -productVersion) MAC_VERSION_MAJOR=$(echo "$MAC_VERSION" | cut -d. -f1) MAC_REQUIRED=11 if [ "$MAC_VERSION_MAJOR" -lt $MAC_REQUIRED ]; then echo Can not install JOKey on your Mac! echo Your macOS version is $MAC_VERSION, minimum required is macOS version $MAC_REQUIRED exit 1 fi if [ -n "$V" ]; then JOKEY_VERSION=$V else JOKEY_VERSION=$(curl -fsS https://afixer.app/jokey/version.txt) fi echo JOKey v$JOKEY_VERSION ID=afixer.inputmethod.JOKey USER_ID=$(id -u) ZIP_FILE=JOKey-$JOKEY_VERSION.zip TMP_DIR=$(mktemp -d) trap 'rm -rf "$TMP_DIR"' EXIT APP="$HOME/Applications/JOKey.app" BIN="$APP/Contents/MacOS/JOKey" # JOKey 1.x: an input method OLD_APP="$HOME/Library/Input Methods/JOKey.app" LAYOUTS="$HOME/Library/Keyboard Layouts" LSREGISTER=/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister echo Download $ZIP_FILE if ! curl -fsS "https://afixer.app/jokey/$ZIP_FILE" -o "$TMP_DIR/$ZIP_FILE"; then echo Download failed, visit https://afixer.app/jokey/install#versions to get the available versions exit 1 fi NEW="$TMP_DIR/new/JOKey.app" if ! ditto -xk "$TMP_DIR/$ZIP_FILE" "$TMP_DIR/new" || ! codesign --verify "$NEW" 2>/dev/null; then echo The downloaded JOKey.app is damaged, please run the installer again exit 1 fi # macOS ties the Accessibility approval to the app's signature: a different # build needs a fresh approval, and a stale entry would look on but not work. cdhash() { codesign -dvvv "$1" 2>&1 | sed -n 's/^CDHash=//p'; } bundle_id() { defaults read "$1/Contents/Info" CFBundleIdentifier 2>/dev/null; } if [ "$(bundle_id "$APP")" = "$ID" ]; then OLD_HASH=$(cdhash "$APP"); else OLD_HASH=$(cdhash "$OLD_APP"); fi NEW_HASH=$(cdhash "$NEW") echo Remove the old JOKey # the login agent first (it would restart JOKey), then every JOKey process launchctl bootout "gui/$USER_ID/$ID.agent" 2>/dev/null rm -f "$HOME/Library/LaunchAgents/$ID.agent.plist" pkill -x -u "$USER_ID" JOKey for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do pgrep -x -u "$USER_ID" JOKey >/dev/null || break sleep 0.1 done # with its app gone, the old input method leaves the input menu rm -rf "$OLD_APP" "$HOME/Library/Caches/$ID" case $(bundle_id "$APP") in "$ID"*) rm -rf "$APP" ;; esac # 1.x was sandboxed: its data is in a container (recent macOS may keep it; harmless) rm -rf "$HOME/Library/Containers/$ID" 2>/dev/null # the 2.0 previews' layout; "JOKey" itself only when the new one differs, since # macOS can drop a re-created layout from the input menu until the next login rm -rf "$LAYOUTS/JOKey Direct.bundle" rm -f "$LAYOUTS/JOKey Direct.keylayout" "$LAYOUTS/JOKey Direct.icns" if ! diff -rq "$NEW/Contents/Resources/JOKey.bundle" "$LAYOUTS/JOKey.bundle" >/dev/null 2>&1; then rm -rf "$LAYOUTS/JOKey.bundle" fi # settings start from the defaults defaults delete $ID >/dev/null 2>&1 rm -f "$HOME/Library/Preferences/$ID.plist" if [ "$OLD_HASH" != "$NEW_HASH" ]; then tccutil reset Accessibility $ID >/dev/null 2>&1 tccutil reset AppleEvents $ID >/dev/null 2>&1 fi # other copies (downloads, builds) are forgotten by LaunchServices mdfind "kMDItemCFBundleIdentifier == '$ID'" 2>/dev/null | while IFS= read -r copy; do "$LSREGISTER" -u "$copy" 2>/dev/null done if [ -e "/Library/Input Methods/JOKey.app" ]; then echo " An old JOKey is installed for all users; remove it with:" echo " sudo rm -rf '/Library/Input Methods/JOKey.app'" fi case $JOKEY_VERSION in 0.* | 1.*) # JOKey 1.x is an input method; macOS may ask to add it in System Settings echo " Install JOKey.app into Input Methods" mkdir -p "$HOME/Library/Input Methods" ditto "$NEW" "$OLD_APP" "$OLD_APP/Contents/MacOS/JOKey" enable "$OLD_APP/Contents/MacOS/JOKey" select >/dev/null echo " Done" exit 0 ;; esac echo Install JOKey.app into Applications mkdir -p "$HOME/Applications" ditto "$NEW" "$APP" xattr -dr com.apple.quarantine "$APP" 2>/dev/null "$LSREGISTER" -f "$APP" 2>/dev/null echo Install the JOKey keyboard and start JOKey # macOS lists a layout installed after login only once the user logs in again [ -e "$LAYOUTS/JOKey.bundle" ] || NEEDS_LOGIN=1 # a Mac may not have this folder yet, and JOKey 2.0.0 does not create it mkdir -p "$LAYOUTS" if ! OUT=$("$BIN" install 2>&1); then echo " Installing the JOKey keyboard failed:" echo "$OUT" | sed 's/^/ /' exit 1 fi "$BIN" select >/dev/null echo Disable spelling autocorrect defaults write -g ApplePressAndHoldEnabled -bool false defaults write -g NSAllowContinuousSpellChecking -bool false defaults write -g NSAutomaticSpellingCorrectionEnabled -bool false defaults write -g NSAutomaticTextCompletionEnabled -bool false defaults write -g WebAutomaticSpellingCorrectionEnabled -bool false defaults write -g NSAutomaticCapitalizationEnabled -bool false defaults write -g NSAutomaticQuoteSubstitutionEnabled -bool false echo Done STATUS=$("$BIN" status) # also installed earlier since this login (JOKey 2.0.0 does not say) case $STATUS in *needsLogin:true*) NEEDS_LOGIN=1 ;; esac if ! echo "$STATUS" | grep -q "isEnabled:true"; then if [ -n "$NEEDS_LOGIN" ]; then echo " Next: log out and log in again (macOS lists a new keyboard only after that)," echo " then add JOKey in System Settings > Keyboard > Input Sources > Edit > + > Vietnamese" else echo " Next: add JOKey in System Settings > Keyboard > Input Sources > Edit > + > Vietnamese" echo " (not listed? log out and in once, then add it)" fi fi if [ "$OLD_HASH" != "$NEW_HASH" ]; then echo " Then allow JOKey in System Settings > Privacy & Security > Accessibility" fi