rcmdnk's blog
Last update

20170831_escime_200_200

Karabinerが使えなくなってからVimを使っている時に IMEをOFFにしつつノーマルモードに戻る方法が無くて困ってましたが Karabiner-Elementsを使い始めたのをきっかけとして もう一度挑戦してなんとなく上手く行く方法を見つけました。

El Capitan以前の方法

El Capitan以前はKarabinerを使ってIMEをチェックし、IMEの変更まで全て管理していました。

ちなみにWindowsではAutoHotkeyを使って同じ様なことをしています。

macOS Sierraになってからの苦闘

で、macOS SierraになってKarabinerが使えなくなって色々となんとか出来ないかやってきました。

まずはAppleScriptでIMEの状態をチェックしてIMEの変更を行えるものを用意し、 そのスクリプトをBetterTouchToolでESCとかに割り当てるというもの。

ショートカットキーの割り当てのアプリはなんでもいいんですがトラックパッドの設定で必ず使うのでついでにBetterTouchToolの中で設定しました。

出てきた問題はAppleScriptを使う方法だとちょっと時間がかかってしまって 勢い良くキーを打ち込むとIMEの変更前に打ち込まれてしまうことがあるということ。

他にも色々細かい問題が出てきて結局使わない事にしました。

次が同様にAppleScriptを使いますが今度はAppleScriptでは単にEISUを送るだけのものにします。 (USキーボードのみ使っていてEISUがどこにも無い場合でも送る事は出来ます。)

これを使えばコマンドラインからEISUを送ることができIMEをオフにできます。

これを使って今度は.vimrcの中でInsertLeave時に このコマンドを送る設定をします。

最初の方法ではGNU screenのコピーモード時の問題があるので常にEISUESCを余計に送る様な設定にしてしまうことができませんでした。 (GNU screenを使ってなかったらそられのキーを連続して常に送れば良い。)

この場合にはVimの中での設定なのでインサートモードからノーマルに戻る時に 常にEISUを送ることは特に問題ありません。 (既に英数状態でも何もしないだけなので。)

この方法は結構上手く行ったのですが、 カーソルキーが使えなくなる問題があったり、 色々工夫してもそれでもまだ遅延があったり して完璧とは言えないものでした。

その次に見つけたのがGoogle日本語入力を使ってその中で キー設定を行うというもの。

ESCキャンセル後IMEを無効化を割り当てると IMEを無効化した上でさらにESCも送れる、というもの。

この方法見つけた時は非常に上手くいって完全に思い通りのことが出来ました。

が、しばらく経った後に違和感を感じて調べてみたらこの方法が効かなくなってました。 (IMEがオンの状態だとESCを押してもIMEがオフになるだけで追加でESCが送られない。)

色々設定を見直しましたが以前と変更したところは無いと思うのでGoogle日本語入力か macOSのアップデートによってだめになってしまったようです。

恐らくGoogle日本語入力の所でキャンセル後IMEを無効化 をしながら更にESCが送られる、という動作が元々予期されないもの(バグ)で、 それが正しく指定の動作だけを行う様になったのかな、と。

ということで残念ながらこの方法は今は使えません。

Karabiner-Elementsを使って実現する

Karabiner-Elementsが進化して大分色々出来る様になったので これまで予備的にBetterTouchToolでしのいで居たキーバインド設定をKarabiner-Elementsに全面的に移す事にしました。

やってみた結果、BetterTouchToolだとどうしても出来なかったいくつかの事もまた出来る様になってて素晴らしい限りです。

ただ、まだKarabinerの時にやっていたことで出来ない事がいくつかあって、 そのうちの1つがこのIME問題です。

KarabinerではIMEの情報やIMEを操作する方法がありましたが Karabiner-Elementsにはありません。

追記: 2017/10/30

Karabiner-ElementsでもIMEの情報を得たり直接操作することが出来るようになりました。

上の記事では新しいinput_source_ifを使った以前と同じ様な VimでNormalモード切り替え時にIMEをOFFにする を作っています。

追記ここまで

ただ、IMEをオフにするだけであればEISUを送れば良いだけなのでKarabiner-Elementsでも出来ます。

そこで次の様な設定をしてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"from": {
    "key_code": "escape"
},
"to": [
    {
        "key_code": "escape"
    },
    {
        "key_code": "japanese_eisuu"
    },
    {
        "key_code": "escape"
    }
]

ESCを押した時に一回ESCを押した後、EISUを送り 再びEISUを送ります。

最初のESCは変換中などにそれを中断させるため、 次のEISUでIMEをオフにし、 もう一度ESCを押すことでVimでインサートモードだった場合にノーマルモードに戻ります。

変換中でなければ最初のESCでノーマルモードに戻りますが 後のESCは無視されるだけです。

これをしてしまうと、本来の変換中にESCを押した時に書き込みをキャンセルしてまたIMEがオンのまま書き続ける、 という動作が出来なくなりますが、 IMEの状態を取れない環境では中途半端にEISUESCだけすると 変換中からだとIMEをオフにした状態でインサートな状態、になり これも中途半端です。

なのでESCを押す時は全部キャンセルしてノーマルに必ず戻る様に。 変換中のキャンセルとかはBackspaceなり-H で一文字づつでも消していけば良いかと。

同様の設定を

1
2
3
4
5
6
7
8
"from": {
    "key_code": "open_bracket",
    "modifiers": {
        "mandatory": [
            "control"
        ]
    }
},

にも。

ちょっと副作用が大きいので ターミナルやVim上でのみ有効にしてあります。 (Karabiner-Elementsにあるerb2json.rb中の emacs_key_bindings_exceptionの定義にあたるもの。)

ただ上にも書いたとおりこれをターミナル上で常に有効にしてしまうとGNU screenのコピーモードに入れなくなります。

そこで、~/.screenrcに次の一行を加えます。

bindkey -m ^[ eval ''

bindkey -mはコピーモード時でのキーバインド。

^[は設定するキー(ctrl-[)ですがESCもこの設定で同時に行われます。(GNU screenではこれらは区別されない。)

eval ''で実際に行う設定を入れていますが、通常はeval 'writebuf'とか コマンドを入れますがここではコマンドを空にして何もしないようにしています。 ('<command>'は複数書く事が出来ますが、省略してevalだけにしたりevalも書かなかったりするとエラーが出ました。 何もしたくない場合は空の''evalに指定すれば良いようです。)

これによって ESCを使ってGNU screenでコピーモードに入っても その後ESCが送られてもコピーモードを保つことが出来ます。

コピーモードを中止したい時は適当に割り当ての無いキーを押せば良いわけですが(ESCも単に割り当ての無いキーだった)、 入る時に使うエスケープキー(自分設定ではQ)の近くに指が残るので、 丁度そのキーコピーモードではは使われてないのそれを押せば良いかな、と。 (自然といままでもQでキャンセルしてることもあったので。)

ちょっと癖が残ってる間はESCで終了させようとして しまいますが全てQにするのはそれほど大変じゃなさそうな感覚。

このGNU screenの設定をすればAppleScriptの最初の試みの所でIMEをチェックせずに ESCとIMEをオフにするコマンドを送ることで遅延時間を減らして行う事も出来るかもしれません。 ただそれでもAppleScriptを呼ぶこと自体が結構負荷あるみたいなので Karabiner-Elementsでやったほうが問題なく出来ます。

ただこのGNU screenの設定をしておけば 今後もMacで何らかの理由でKarabiner-Elementsが使えなくなったときや Windowsでも上手く行かないとき、 またLinuxなんかを使うときでも色々応用して設定が出来そうです。

まとめ

とりあえず今回の設定で再びターミナル内でのVimでも 問題なくVimのインサートモードから Normalモード切り替え時にIMEをOFFにする を1つのキーで行える様になりました。

未だに逆にクセでESC(正確には-[を常に使ってるのでそっち) を2回押してしまう事が多いですが 気をつけて1回で使ってると大分楽に感じます。

今回の設定をまとめると以下の様になります。

Karabiner-Elements complex_modifications rules by rcmdnk へ行ってPersonal rules (@rcmdnk)をImportすると ESC (or Control-[) sends ESC EISU ESCが設定できる様になるので それをEnableすることでも使えます。 (Karabiner-Elementsの新しい設定配布方法とても便利。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
{
  "title": "ESC mapping to disable IME and change to Normal mode at Vim at once",
  "rules": [
    {
      "description": "ESC (or Control-[) sends ESC EISU ESC",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "escape"
          },
          "to": [
            {
              "key_code": "escape"
            },
            {
              "key_code": "escape"
            },
            {
              "key_code": "escape"
            }
          ],
          "conditions": [
            {
              "type": "frontmost_application_if",
              "bundle_identifiers": [
                "^org\\.gnu\\.Emacs$",
                "^org\\.gnu\\.AquamacsEmacs$",
                "^org\\.gnu\\.Aquamacs$",
                "^org\\.pqrs\\.unknownapp.conkeror$",
                "^com\\.microsoft\\.rdc$",
                "^com\\.microsoft\\.rdc\\.mac$",
                "^com\\.microsoft\\.rdc\\.osx\\.beta$",
                "^net\\.sf\\.cord$",
                "^com\\.thinomenon\\.RemoteDesktopConnection$",
                "^com\\.itap-mobile\\.qmote$",
                "^com\\.nulana\\.remotixmac$",
                "^com\\.p5sys\\.jump\\.mac\\.viewer$",
                "^com\\.p5sys\\.jump\\.mac\\.viewer\\.web$",
                "^com\\.vmware\\.horizon$",
                "^com\\.2X\\.Client\\.Mac$",
                "^com\\.googlecode\\.iterm2$",
                "^com\\.apple\\.Terminal$",
                "^co\\.zeit\\.hyperterm$",
                "^co\\.zeit\\.hyper$",
                "^org\\.vim\\.",
                "^com\\.vmware\\.fusion$",
                "^com\\.vmware\\.horizon$",
                "^com\\.vmware\\.view$",
                "^com\\.parallels\\.desktop$",
                "^com\\.parallels\\.vm$",
                "^com\\.parallels\\.desktop\\.console$",
                "^org\\.virtualbox\\.app\\.VirtualBoxVM$",
                "^com\\.vmware\\.proxyApp\\.",
                "^com\\.parallels\\.winapp\\.",
                "^org\\.x\\.X11$",
                "^com\\.apple\\.x11$",
                "^org\\.macosforge\\.xquartz\\.X11$",
                "^org\\.macports\\.X11$"
              ]
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "open_bracket",
            "modifiers": {
              "mandatory": [
                "control"
              ]
            }
          },
          "to": [
            {
              "key_code": "escape"
            },
            {
              "key_code": "escape"
            },
            {
              "key_code": "escape"
            }
          ],
          "conditions": [
            {
              "type": "frontmost_application_if",
              "bundle_identifiers": [
                "^org\\.gnu\\.Emacs$",
                "^org\\.gnu\\.AquamacsEmacs$",
                "^org\\.gnu\\.Aquamacs$",
                "^org\\.pqrs\\.unknownapp.conkeror$",
                "^com\\.microsoft\\.rdc$",
                "^com\\.microsoft\\.rdc\\.mac$",
                "^com\\.microsoft\\.rdc\\.osx\\.beta$",
                "^net\\.sf\\.cord$",
                "^com\\.thinomenon\\.RemoteDesktopConnection$",
                "^com\\.itap-mobile\\.qmote$",
                "^com\\.nulana\\.remotixmac$",
                "^com\\.p5sys\\.jump\\.mac\\.viewer$",
                "^com\\.p5sys\\.jump\\.mac\\.viewer\\.web$",
                "^com\\.vmware\\.horizon$",
                "^com\\.2X\\.Client\\.Mac$",
                "^com\\.googlecode\\.iterm2$",
                "^com\\.apple\\.Terminal$",
                "^co\\.zeit\\.hyperterm$",
                "^co\\.zeit\\.hyper$",
                "^org\\.vim\\.",
                "^com\\.vmware\\.fusion$",
                "^com\\.vmware\\.horizon$",
                "^com\\.vmware\\.view$",
                "^com\\.parallels\\.desktop$",
                "^com\\.parallels\\.vm$",
                "^com\\.parallels\\.desktop\\.console$",
                "^org\\.virtualbox\\.app\\.VirtualBoxVM$",
                "^com\\.vmware\\.proxyApp\\.",
                "^com\\.parallels\\.winapp\\.",
                "^org\\.x\\.X11$",
                "^com\\.apple\\.x11$",
                "^org\\.macosforge\\.xquartz\\.X11$",
                "^org\\.macports\\.X11$"
              ]
            }
          ]
        }
      ]
    }
  ]
}
Sponsored Links
Sponsored Links

« KE-complex_modificationsを使ってKarabiner-Elementsの定義を色々作って公開する Karabiner-Elements用のKE-complex_modificationsのextra_descriptionsを自動で生成する »

}