Help us understand the problem. What is going on with this article?

システム環境設定にあるキーボードショートカットを設定するJXA

More than 1 year has passed since last update.

2年ぐらい前にポストした「システム環境設定にあるキーボードショートカットを設定するAppleScript」のJXA版です。

OS標準のショートカット設定では、設定をインポート/エクスポートができないため、それを補完する感じでJSONファイルで設定を書いて無理やり取り込むスクリプトです。インポートができれば設定ファイルが残るため、エクスポートは「ええやろ」という考えなのでエクスポートのスクリプトはありません。

High Sierra(10.13.6)で動作確認しています。

使い方

  1. 環境設定 → セキュリティとプライバシー → プライバシー の「アクセシビリティ」で、スクリプトエディタ.appにコンピュータの操作を許可する
  2. JSONファイルをこしらえる(:point_right_tone2: JSONの書き方
  3. :point_right_tone2: 下記のスクリプトを「スクリプトエディタ」にコピペする(言語はJavaScriptを選択してください)
  4. スクリプトエディタのツールバーにある右向きの三角で実行(ショートカット:Cmd + R)すると、ダイアログが表示されるので、こしらえたJSONファイルを選択する
  5. あとは無事終わるまで眺める(スクリプトでGUIを操作しているので、文字通り眺めてください)

「アプリケーション」フォルダ直下にないアプリをJSONのappNameで指定している場合、4でダイアログが表示されるので、appNameと同じアプリを選択してください。

  • スクリプトエディタ.appは、「アプリケーション/ユーティリティ」の中にあります。
  • 「アプリケーション」フォルダは、FinderでCmd + Shift + Aで表示されるフォルダです。

JSONの書き方

次のように記述します。

[
    {
        "appName": "Sketch.app",
        "shortcut": [
            {
                "menu": "Flatten Selection to Bitmap",
                "key": "e",
                "modifier": [ "command", "control", "shift" ]
            }
        ]
    }
]
appName:
アプリケーション名です。アプリケーションフォルダ内の名前を正確に入力してください。
shortcut:
menu:
アプリのメニュー項目を正確に入力してください。同じ項目名が複数ある場合は、親のメニュー項目を「->」でつなぎます。
例:Use Defaultという項目がかぶる場合、Kern->Use DefaultLigature->Use Defaultと入力する。
key:
キーボードで文字が入力できるキーを1文字を小文字で指定してください。例外的に矢印キーは「up」「right」「down」「left」と指定できます。Fキーは要望があれば対応します。
modifier:
Command・Control・Shift・Optionキーを指定します。CommandまたはControlのどちらかは必ず含めてください。

サンプル

スクリプト

"use strict";

var app = Application.currentApplication();
app.includeStandardAdditions = true;

// ローカライズ
var langList = app.doShellScript("defaults read NSGlobalDomain AppleLanguages | awk '{gsub(/[^a-zA-Z-]/,\"\");print}' | grep -v '^$'");
var langs = langList.split('\r');

var chooseJSONLabel = 'Please select a JSON file:';
var shortcutLabel = 'App Shortcuts';
var menuItemLabel = 'Menu Title:';
var addButtonLabel = 'Add';
switch (langs[0].substr(0, 2)) {
    case 'ja':
        chooseJSONLabel = 'JSONファイルを選択してください。';
        shortcutLabel = 'アプリケーション';
        menuItemLabel = 'メニュータイトル:';
        addButtonLabel = '追加';
        break;
}

var appList = app.doShellScript('ls /Applications').split('\r');

// 設定ファイルを読み込んでJSONへパース
var chooseFile = app.chooseFile({
        withPrompt: chooseJSONLabel
    })
var json = JSON.parse(readFile(chooseFile));

// 環境設定を起動してキーボードを選択し、ショートカットタブを表示する
var pref = Application('com.apple.systempreferences');
pref.panes['com.apple.preference.keyboard'].anchors['shortcutsTab'].reveal();
pref.activate();
delay(2);

// 左のリストから「アプリケーション」を選択
var sysEvent = Application('System Events');
var prefKeyboard = sysEvent.processes['System Preferences'].windows[0];
var rows = prefKeyboard.tabGroups[0].splitterGroups[0].scrollAreas[0].tables[0].rows();
var shortcutPosition = 0;
for (let i = 0; i < rows.length; i++) {
    console.log(rows[i].staticTexts[0].name());
    if (shortcutLabel === rows[i].staticTexts[0].name()) {
        shortcutPosition = i;
        break;
    }
}
rows[shortcutPosition].select();

// ショートカットを設定
for (let i = 0; i < json.length; i++) {
    let appName = json[i].appName;
    let appExist = false;
    appList.some(function (obj) {
        if (appName === obj) {
            appExist = true;
            return true;
        }
    });

    let appSelected = false;

    for (let j = 0; j < json[i].shortcut.length; j++) {
        // [+]ボタンをクリックしてダイアログシートを表示
        prefKeyboard.tabGroups[0].groups[0].buttons[0].click();
        let settingSheet = prefKeyboard.sheets[0];

        // アプリケーションを設定
        if (!appSelected) {
            if (appExist) {
                settingSheet.popUpButtons[0].click().menus[0].menuItems[appName].click();
            } else {
                // ポップアップの中にアプリがない場合
                let appListItems = settingSheet.popUpButtons[0].click().menus[0].menuItems.length;
                settingSheet.popUpButtons[0].menus[0].menuItems[appListItems - 1].click();

                // アプリが選択されるまで待つ
                while (!appExist) {
                    if(appName == settingSheet.popUpButtons[0].value()) {
                        appExist = true;
                    } else {
                        delay(2);
                    }
                }
            }
            appSelected = true;
        }

        // メニュー項目を設定
        settingSheet.textFields[menuItemLabel].value = json[i].shortcut[j].menu;

        // タブキーでフォーカスを移動
        sysEvent.keyCode(48);

        // ショートカットキーを設定
        let pressKey;
        switch (json[i].shortcut[j].key) {
            case 'left':
                pressKey = 123;
                break;
            case 'right':
                pressKey = 124;
                break;
            case 'up':
                pressKey = 125;
                break;
            case 'down':
                pressKey = 125;
                break;
            default:
                pressKey = json[i].shortcut[j].key
                break;
        }
        setShortcut(pressKey, json[i].shortcut[j].modifier);

        // 追加ボタンをクリック
        settingSheet.buttons[addButtonLabel].click();
    }
    appSelected = false;
}


// Helpers
function readFile(file) {
    var fileString = file.toString();
    return app.read(Path(fileString));
}

function setShortcut(key, mod) {
    for (var i = 0; i < mod.length; i++) {
        mod[i] = mod[i] + ' down';
    }
    if (isNaN(key)) {
        sysEvent.keystroke(key, {using: mod});
    } else {
        sysEvent.keyCode(key, {using: mod});
    }
}

トラブルシューティング

エラー処理はあまり考えてないので、そこは大目にみてください :bow_tone2:

1回実行した後にエラーが出て再実行できない

スクリプトエディタでハンマーのアイコンをクリックしてみてください。ショートカットはCmd + Kです。

アプリを選択したが進まない

JSONのappNameで指定した名前が間違っている可能性がありますので、確認してください。

littlebusters
デザインの人。とりあえずなんでも放り込みます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした