TL;DR
Vim や GUI エディタの Vim 拡張機能 (e.g. vscodevim) を普段使うとき、 jj
を esc
にマップして insert mode を抜けるのに使っているのですが、日本語入力中に jj
(つまり っj
) を入力したときも機能するよう、 Karabiner-Elements の complex modifications を設定する方法をまとめました。
Requirements
これを実現するためには日本語入力で っj
が入力されたら、
- 現在までに入力中の日本語文章の変換を確定させ、
- 入力を日本語から半角英数に変更し、
- Vim insert mode から何らかの方法で抜ける
ことが必要になります。1. と 2. は return
および 英数
キーを入力するよう設定すれば OK です。一方、3. については以下の2つの方針が考えられます。
-
っj
→esc
にマップする (jj
の入力はなかったことにする) -
っj
→jj
にマップする (jj
→esc
のマッピングは Vim や Vim 拡張機能の設定に任せる)
Karabiner-Elements を使うと macOS のグローバルなキーボード設定が変えることができるので (もちろん特定のアプリケーションに限定した設定も可能ですが)、ターミナルの Vim だろうが VS Code だろうが jj
が使えるようになるのが大きな魅力です。そこで、様々な場面で意図しない esc
が実行されないように、ここでは後者を選択することにします。
Installation
ここでは @s-show さんの Karabiner-Elementsを使ってキーの2連打に処理を割り当てる方法 を参考に、以下の vim-in-japanese.json
を作成しました (Gist にも置いておきました)。これを、 ~/.config/karabiner/assets/complex_modifications
に置いておけば、 Karabiner-Elements Preferences → Complex Modifications → Add rule から選択できるようになるはずです。
仕組みとしては、
- 1つ目の
j
が入力されたら、変数j_pressed
を1
にする。もし一定時間何も入力されなかった場合 (to_if_invoked
) やj
以外の文字が入力された場合 (to_if_canceled
) は、j_pressed
を0
に戻す。 -
j_pressed
が1
の状態で立て続けに2つ目のj
が入力されたらreturn
+英数
+j
に置換し、j_pressed
を0
に戻す。
となっています。あとは Vim の場合は .vimrc
で、
inoremap <silent> jj <ESC>
としておけば OK です。上で前者の方針を選択した場合も、これを参考に簡単に設定できると思います。macOS 限定のハックですが、 Vim-like な環境で快適に日本語入力ができるようになるので便利ですね!
Rule file
{
"title": "For Vim in Japanese",
"rules": [
{
"description": "日本語入力の っj を jj にマッピングする",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "j"
},
"to": [
{
"key_code": "return_or_enter"
},
{
"key_code": "japanese_eisuu"
},
{
"key_code": "j"
}
],
"conditions": [
{
"type": "variable_if",
"name": "j_pressed",
"value": 1
},
{
"type": "input_source_if",
"input_sources": [
{
"language": "^ja$"
}
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "j"
},
"to": [
{
"set_variable": {
"name": "j_pressed",
"value": 1
}
},
{
"key_code": "j"
}
],
"to_delayed_action": {
"to_if_invoked": [
{
"set_variable": {
"name": "j_pressed",
"value": 0
}
}
],
"to_if_canceled": [
{
"set_variable": {
"name": "j_pressed",
"value": 0
}
}
]
}
}
]
}
]
}