Mac の Vim でインサートモードを抜けるときに日本語入力を OFF にしたい

追記:swim がビルドできるようになったので続編を書きました。
続・Mac の Vim でインサートモードを抜けるときに日本語入力を OFF にしたい

以前、WSL の Vim でもインサートモードを抜けるときに日本語入力を OFF にしたい という記事を書きました。この記事の中で

私の場合、Mac で Vim を使う時は InsertLeave 時に swim を叩く事で解決していました。

と書いたように、Mac では swim というツールを使って日本語入力を操作していたのですが、先日その swim がビルド出来なくなっているのを発見して困っておりました・・・

Can’t build swim with swift 5.0

ちょっと頑張れば自分で直せそうな気がしないでもないですが・・・swim に頼らず OS 標準の AppleScript を使って日本語入力を OFF にする方法がわかりましたので、そちらの方法に切り替えることにしました。

AppleScript で 日本語入力を OFF にする

以下のページを参考にしました。

AutometorとAppleスクリプトでGUIアプリを自動操作

tell application "System Events"
    key code 102
end tell

キーコード 102 は英数キーです。osascript コマンドは -e オプションでその後に続く文字列を評価してくれるので、以下のワンライナーにしてターミナルから叩いてみます。

osascript -e 'tell application "System Events" to key code {102}'

しっかり日本語入力が OFF になることを確認できました。

Vim へ

あとはこれを vimrc に組み込みます。

if has('mac')
    augroup insertLeave
        autocmd!
        autocmd InsertLeave * :call job_start(
                    \ ['osascript', '-e', 'tell application "System Events" to key code {102}'],
                    \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
    augroup END
endif

やってる事は前回の記事 (冒頭のリンク) と同じで、InsertLeave で 外部コマンド (osascript) を叩いています。

前回は外部コマンドの起動に system() を使いましたが、今回は job_start() を使ってみます。osascript コマンドが少々遅く、インサートモードから抜ける度に遅延を感じるようになってしまったため、非同期にしてプロセスの終了を待たないようにする狙いです。

job_start() の第二引数に指定している {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'} は、起動したプロセスの stdin, stdout, stderr を一切見ないことを示します。Vim のヘルプを参考にしました。

9. Starting a job without a channel

To start another process without creating a channel:
let job = job_start(command,
\ {“in_io”: “null”, “out_io”: “null”, “err_io”: “null”})

This starts {command} in the background, Vim does not wait for it to finish.

When Vim sees that neither stdin, stdout or stderr are connected, no channel
will be created.

https://vimhelp.org/channel.txt.html

job_start() でも遅延が気になる

しかし system() をやめて job_start() にしたものの、インサートモードから抜ける際の遅延がやはり気になります。

私の場合は jj もしくは っjESC にマッピングしてあるのですが、日本語入力 OFF 時にインサートモードで jjj とタイプしても1行下にカーソルが移動してくれません。

で、色々調べた結果以下の記事に行き着きました。

VimでNormalモード切り替え時にIMEをOFFにする、をMacでKarabiner無しで実現する 2

なるほど ttimeoutlen を設定する・・・早速 vimrc に設定を加えます。

set ttimeoutlen=1

するとちょっとマシになったような・・・でも私の環境では快適とは言えない感じでした。

set ttimeoutlen=1 でも遅延が気になる

結局 InsertLeave で日本語入力を OFF にするのは諦めてしまいました。上述のように普段は jj または っj を使っているので、っj の場合だけ osascript が動いてくれれば十分です。

まずは InsertLeave でコマンドを叩くようにしていた部分を関数化します。

function! s:disableIme()
    if has('mac')
        call job_start(['osascript', '-e', 'tell application "System Events" to key code {102}'],
                    \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
    endif
endfunction

s:disableIme() 関数は、実際には前回の記事のように AutoHotKey を叩く処理も書いていますがここでは省略。

続いて っj のマッピングに s:disableIme() 関数を割り込ませます。

" jj → そのまま
inoremap <silent> jj <ESC>

" っj → disableIme() を呼ぶ
inoremap <silent> っj <C-o>:call <SID>disableIme()<CR><ESC>

s:disableIme() 関数はスクリプトローカルで宣言しているため、キーマップから呼ぶときは s:<SID> に置き換えます。(これは今回初めて知ったので、どこかで別の記事にしたいです。)

でどうなったか

っj でインサートモードを抜けるときはあまり快適ではないですが、そもそも頭の中では

  1. っj
  2. (あ、IME オフるの忘れた)
  3. Enter

のように一旦思考が止まるので (^^; あまり遅延が気にならないのでした。

また、jj でインサートモードを抜けるときは外部コマンドを叩かないため、だいぶ快適になりました。プログラミングをする時などは日本語をあまり使わないので私の場合はこれで十分なのでした。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です