見出し画像

mac で、とことん(emacs)キーカスタマイズ

以前、Obsidian でも Kill & Yank したいって事で、プラグインに Contribution するほどのショートカット魔です。

そんな中、もちろん "Karabiner" も使っているんですが、気がついたことにこちらで提供されている Emacs キーバインディングも Kill&Yank ないんですよね。

Obsidian や VScode 等、エディタ側で対応していればそちらの方が挙動が安定していてよいのですが、例えば note.com だったり、一般的な Webフォームだったりでも使いたいわけです。mac 標準で kill-line と yank は地味に対応してるんですが、これクリップボード未対応な上、全ての状況で利用できるとは限らないんですね。

そして、こんなものを見つけてしまって、また大興奮です。mark-set もできます。ありがたい。

というわけで、地味めに  "Karabiner" でも kill , yank, mark-set あたりを自分用に作ってみました。ついでに C-x U で undo とかも追加です。

全部を表現するとやばい長さになるので、抜粋するとこんな感じになります。

C-x U で undo

{
  "title": "Emacs key bindings (rev 12+2)",
  "rules": [
    {
      "description": "Emacs key bindings [C-x key strokes] (rev 2+2)",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "u",
            "modifiers": {
              "optional": [
                "control",
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "key_code": "z",
              "modifiers": [
                "left_command"
              ]
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "C-x",
              "value": true
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "x",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "set_variable": {
                "name": "C-x",
                "value": true
              }
            }
          ],
          "to_delayed_action": {
            "to_if_invoked": [
              {
                "set_variable": {
                  "name": "C-x",
                  "value": false
                }
              }
            ],
            "to_if_canceled": [
              {
                "set_variable": {
                  "name": "C-x",
                  "value": false
                }
              }
            }
          ]
        }
      ]
    }

mark-set と mark-reset

C-Space は漢字変換に割り当てているので、私は C-@ で mark-setです。

    {
      "description": "Emacs key bindings [control+keys] (rev 10+10)",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "2",
            "modifiers": {
              "mandatory": [
                "control",
                "shift"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "set_variable": {
                "name": "mark_mode",
                "value": true
              }
            },
            {
              "set_notification_message": {
                "id": "emacs.mark.mode",
                "text": "marking"
              }
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            },
            {
              "name": "mark_mode",
              "type": "variable_unless",
              "value": true
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "2",
            "modifiers": {
              "mandatory": [
                "control",
                "shift"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "set_variable": {
                "name": "mark_mode",
                "value": false
              }
            },
            {
              "set_notification_message": {
                "id": "emacs.mark.mode",
                "text": ""
              }
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            },
            {
              "name": "mark_mode",
              "type": "variable_if",
              "value": true
            }
          ]
        }
      ]
    },

mark-set 判定済みのカーソル動作

この "conditions" 部分で、mark_mode かどうかを判定しています。
set-mark されている最中であれば、挙動に "shift" が追加されています。

              "name": "mark_mode",
              "type": "variable_if",
              "value": true

ということで、この挙動を "b" 以外の npfae などなどにも割り当てます。大変。

        {
          "type": "basic",
          "from": {
            "key_code": "b",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock",
                "shift",
                "option"
              ]
            }
          },
          "to": [
            {
              "key_code": "left_arrow",
              "modifiers": [
                "shift"
              ]
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            },
            {
              "name": "mark_mode",
              "type": "variable_if",
              "value": true
            }
          ]
        }
      ]
    },

mark-set されていない時の挙動

mark されていない判定はここです。"variable_unless" になっているだけです。

              "name": "mark_mode",
              "type": "variable_unless",
              "value": true

その場合は、素直にカーソル動作を行うということです。

        {
          "type": "basic",
          "from": {
            "key_code": "b",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock",
                "shift",
                "option"
              ]
            }
          },
          "to": [
            {
              "key_code": "left_arrow"
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            },
            {
              "name": "mark_mode",
              "type": "variable_unless",
              "value": true
            }
          ]
        }
      ]
    },

kill-line する

行末、パラグラフの終わりまでをしているする挙動が C-e が一番妥当すぎたので、⇧+C-e で行末まで指定してカットするというちょっとかっこ悪い仕様です。なんか他にないかな…。

        {
          "type": "basic",
          "from": {
            "key_code": "k",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock",
                "shift"
              ]
            }
          },
          "to": [
            {
              "key_code": "e",
              "modifiers": [
                "control",
                "shift"
              ]              
            },
            {
              "key_code": "x",
              "modifiers": [
                "left_command"
              ]
            },
            {
              "set_variable": {
                "name": "mark_mode",
                "value": false
              }
            },
            {
              "set_notification_message": {
                "id": "emacs.mark.mode",
                "text": ""
              }
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            }
          ]
        }
      ]
    },

yank する

これはもう素直にペーストするだけです。楽。

        {
          "type": "basic",
          "from": {
            "key_code": "y",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock",
                "shift"
              ]
            }
          },
          "to": [
            {
              "key_code": "v",
              "modifiers": [
                "left_command"
              ]
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            }
          ]
        }
      ]
    },

おまけ - 漢字変換とのバッティングを避ける

漢字変換中にはこういった機能を抑制しています。漢字変換中のキーカスタマイズとバッティングしてしまうので。ここも "conditions" で状態を拾って制御しています。

          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "^en$"
                }
              ]
            }
          ]

ホントまじで "karabiner" さん神です。キーボードだけでほとんどのコトできてしまう。助かる。ありがとう。

貴方がサポートしてくれると、私が幸せ。 私が幸せになると、貴方も幸せ。 新しいガジェット・ソフトウェアのレビューに、貴方の力が必要です。