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
}
}
]
}
}
]
}
]
}