追記: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
https://vimhelp.org/channel.txt.html
will be created.
job_start() でも遅延が気になる
しかし system()
をやめて job_start()
にしたものの、インサートモードから抜ける際の遅延がやはり気になります。
私の場合は jj
もしくは っj
を ESC
にマッピングしてあるのですが、日本語入力 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
でインサートモードを抜けるときはあまり快適ではないですが、そもそも頭の中では
- っj
- (あ、IME オフるの忘れた)
- Enter
のように一旦思考が止まるので (^^; あまり遅延が気にならないのでした。
また、jj
でインサートモードを抜けるときは外部コマンドを叩かないため、だいぶ快適になりました。プログラミングをする時などは日本語をあまり使わないので私の場合はこれで十分なのでした。