長年Linux/Windows使いだった私がmacOSで開発環境を整えるためにやったこと

長年業務でWindows,プライベートでLinuxを使い続けていた私が、macOSを使ったWeb開発業務を行うことになりました。環境周りを色々調整していたのですが、ようやく安定してきたのでやったことをまとめておきます。
2020.06.25

はじめに

プライベートでは Ubuntu を中心とした Linux デスクトップ環境、業務では Windows を長年利用していたのですが、色々あって MacBook Pro で開発業務を行うことになりました。

macOS 自体初めてで、独特のショートカットキーを使いこなせる気がしなかったので、Ubuntu に近い操作感にならないかと試行錯誤した結果、ある程度満足の行くところまで調整出来たので、その内容をまとめました。

環境は以下の通りです。内蔵キーボードやトラックパッドは全く使用しない環境となります。

  • MacBook Pro (13-inch, 2019, Four Thunderbolt 3 ports) (US配列)
  • HHKB Lite2 (US配列)
  • MX Ergo
  • macOS Catalina 10.15.5

普段の開発で使用している以下アプリケーションが想定通りに動くことが、今回のゴールとなります。

  • Chrome
  • iTerm2
  • Visual Studio Code
  • IntelliJ IDEA

OS全体の設定

IME設定

IME 起動ショートカットに Alt + Grave (`) を使っているので、 システム環境設定 - キーボード - ショートカット - 入力ソース - 前の入力ソースを選択Option + ` に設定しました。

アプリケーション切り替え

macOS だとアプリケーションの切り替えは Command + Tab となっているようです。

Alt + Tab でアプリケーションの切り替えがしたかったので、Option + Tab に変更出来ないか設定を探したのですが、どうやらそのような項目は無さそうです。

途方に暮れていたところ、以下のような情報(入れ替えたいキーは少し違う)が見つかり、Karabiner-Elements というアプリケーションを入れることで設定変更が可能でした。

Karabiner-Elements インストール後、以下のような JSON ファイルを ~/.config/karabiner/assets/complex_modifications/remap_cmd_tab.json として作成し、Karabiner-Elements の Complex modifications タブの Add rule で JSON ファイルを読み込ませることで、Option + Tab のショートカットが Command + Tab として解釈されるようになり、アプリケーションの切り替えが動作するようになりました。 (Shift + Command + Tab による逆向きの切り替えも可能)

{
  "title": "Option+tab maps to Cmd+tab",
  "rules": [
    {
      "description": "Make Option+tab activate Cmd+tab",
      "manipulators": [
     {
        "type": "basic",
        "from": {
            "key_code": "tab",
            "modifiers": {
                "mandatory": [
                    "option"
                ],
                "optional": [
                    "shift"
                ]
            }
        },
        "to": [
               {
                "key_code": "tab",
                "modifiers": ["command"]
               }
        ]
      }
      ]
    }
  ]
}

同一アプリケーション内の別ウィンドウ切り替え

ただ、macOSのアプリケーション切り替えは、同一アプリケーション内の別ウィンドウ切り替えを行ってくれないので、妥協策として別途 ショートカット - キーボード - 次のウィンドウを操作対象にするOption + Command + Tab に変更しました。

コピー、ペーストなどの基本操作を Control との組み合わせにする(不完全)

macOS を使い始めて、いわゆるコピペの操作は Control + C, Control + V ではなく Command キーとの組み合わせだということを知り、衝撃を覚えました。基本操作なので何とか慣れることは出来ないか頑張ってみましたが、長年染み付いた操作を変えることは無理だと悟りました。

そこで、思い切ってキーボードの修飾キー設定で Control を押したら Command が発行されるようにしたところ、いい具合になりました。

これで解決、と思ったのですが、開発に必須のターミナルソフトウェアである iTerm2 上で何気なく Control + C を発行させたところ…効かない。 そう、ControlCommand となるよう変更したため、iTerm2 では Command + C と解釈され、期待通りに動作していなかったのです。

iTerm2

上で述べた Control キー問題の解決なしではとても開発作業が出来ないので、祈るように検索したところ、以下の情報が見つかりました。まさに、同じ問題にぶち当たっていました。

上記情報を参考に、Karabiner-Elements 用 JSON ファイルを ~/.config/karabiner/assets/complex_modifications/iterm.json として作成し読み込ませることで、iTerm2 以外を使っている時に ControlCommand として動作するようになり、iTerm2 を使っている時は Control がそのまま解釈されるようになりました。

{
    "title": "iTerm settings",
    "rules": [
        {
            "description": "left_control to left_command(without iTerm/IntelliJ)",
            "manipulators": [
                {
                    "type": "basic",
                    "from": {
                        "key_code": "left_control",
                        "modifiers": {
                            "optional": [
                                "any"
                            ]
                        }
                    },
                    "to": [
                        {
                            "key_code": "left_command"
                        }
                    ],
                    "conditions": [
                        {
                            "type": "frontmost_application_unless",
                            "bundle_identifiers": [
                                "^com\\.googlecode\\.iterm2",
                                "^com\\.jetbrains\\.intellij"
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

なおこの設定は、iTerm2 の他 IntelliJ IDEA を使用している時も同様の挙動となるようにしています(後述)。

IntelliJ IDEA

IntelliJ IDEA 以前は Windows/Linux 環境で Eclipse を使ってきたため、IntelliJ IDEA の KeymapEclipse に設定しています。

このキーマップだと、コピペが Control + C Control + V に割りあたっているので、上記で説明したとおり ControlCommand を入れ替えないよう Karabiner-Elements で対応しています。

また、Control + 矢印キー が Mission Control に奪われるので、Mission Control 設定の キーボードとマウスのショートカット をすべて未設定としました。

Visual Studio Code

候補選択ショートカット変更

まず候補選択ショートカットとして以前から使ってきた Control + スペース が Karabiner-Elements で Command + スペース と解釈された結果 Spotlight 検索が起動するので、キーボードショートカット設定の Spotlight検索を表示 を別のショートカット(私は Shift + Option + スペース) に割り当てました。

その上で、Visual Studio Code の 基本設定 - キーボード ショートカット から editor.action.triggerSuggest を検索し、Command + Space に割り当てました。

ターミナルのシーケンス送信ショートカット変更

Visual Studio Code 上のターミナルにおいて、iTerm2 と同様 ControlCommand として解釈されるため、Control + C のようなシーケンス送信ショートカットが動作しません。

iTerm2 ではコピペ動作のショートカットを重要視しておらず(基本的にマウス操作で対応)、また IntelliJ IDEA ではコピペショートカットが Control との組み合わせに変更出来ていたので問題なかったのですが、Visual Studio Code のショートカットを IntelliJ IDEA と同様に豪快に変える方法について知見が無かったので、以下の情報を参考に、ターミナル側のショートカットを置き換えるようにしました。

この設定で動作はすることを確認しました。ただし、シーケンスを個別に登録する必要があります。

登録方法は 表示 - コマンドパレット - 基本設定: キーボード ショートカットを開く (JSON)keybindings.json が開きますので、そこに適宜入力します。

なお、シーケンス送信("command": "workbench.action.terminal.sendSequence")以外のショートカットも含まれているので、必要に応じて取捨選択してください。

// 既定値を上書きするには、このファイル内にキー バインドを挿入しますauto[]
[
    {
        "key": "cmd+a",
        // "command": "-workbench.action.terminal.selectAll",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0001" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+b",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0002" },
        "when": "terminalFocus"
    },    
    {
        "key": "cmd+c",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0003" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+d",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0004" },
        "when": "terminalFocus"
    },    
    {
        "key": "cmd+e",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0005" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+f",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0006" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+g",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0007" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+h",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0008" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+k",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u000b" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+l",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u000c" },
        "when": "terminalFocus"
    }, 
    {
        "key": "cmd+n",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u000e" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+p",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0010" },
        "when": "terminalFocus"
    },       
    {
        "key": "cmd+r",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0012" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+t",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0014" },
        "when": "terminalFocus"
    },    
    {
        "key": "cmd+u",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0015" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+w",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0017" },
        "when": "terminalFocus"
    },    
    {
        "key": "cmd+y",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u0019" },
        "when": "terminalFocus"
    },    
    {
        "key": "cmd+z",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u001a" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+\\",
        "command": "workbench.action.terminal.sendSequence",
        "args": { "text": "\u001c" },
        "when": "terminalFocus"
    },
    {
        "key": "cmd+space",
        "command": "editor.action.triggerSuggest",
        "when": "editorHasCompletionItemProvider && textInputFocus && !editorReadonly"
    },
    {
        "key": "ctrl+space",
        "command": "-editor.action.triggerSuggest",
        "when": "editorHasCompletionItemProvider && textInputFocus && !editorReadonly"
    },
    {
        "key": "shift+alt+cmd+[",
        "command": "workbench.action.navigateBack"
    },
    {
        "key": "ctrl+-",
        "command": "-workbench.action.navigateBack"
    },
    {
        "key": "shift+alt+cmd+]",
        "command": "workbench.action.navigateForward"
    },
    {
        "key": "ctrl+shift+-",
        "command": "-workbench.action.navigateForward"
    },
    {
        "key": "alt+escape",
        "command": "-editor.action.triggerSuggest",
        "when": "editorHasCompletionItemProvider && textInputFocus && !editorReadonly"
    }
]

最後に

転職してからリモートワークが続いているため、外付けキーボード+トラックボール前提の設定となっています。そのため内蔵キーボード+トラックパッド向けにはさらに調整が必要なのですが、当分はこれで困らないものと思われます。 いざという時は Karabiner-Elements だと設定を分けられるようなので、その辺りは安心しています。

ただ Karabiner-Elements と OnVUE の相性が悪いらしい、という話も出てきているため、いざこれで受験することになった場合はどうしようかという悩みもあります(ちなみに、先日は試験会場で受験しました)。

ブログネタはボチボチメモしていたのですが、WWDC20 で Big Sur が発表されたので、手遅れになる前に頑張って仕上げました。

同じような状況で困っている人の助けになれば幸いです。