ari23の研究ノート

メーカ勤務エンジニアの技術ブログです

Vimmer必見!TeraTerm+Vimで日本語入力問題を解決する方法

Vimmerのみなさま、こんにちは!
今回は、かの有名な日本語入力問題を解決することができたので、情報共有したいと思います🐜

これで長年の問題から開放されますよ!

Vimの日本語入力問題とは?

前提として、WindowsからSSH(TeraTermなど)でvimする方を想定しています。

Vimで日本語を入力してノーマルモードに戻るときは、以下の手順となりますよね。

  1. ノーマルモード→インサートモードに移行|「i」キーを押下
  2. IMEを有効化|「半角/英数」キーを押下(私の環境では「Ctrl + Space」です)
  3. 日本語を書く
  4. IMEを無効化|「半角/英数」キーを押下(私の環境では「Ctrl + Space」です)
  5. インサートモード→ノーマルモードに移行|「ESC」キーを押下(私の環境では「Ctrl + [」です)

英語を入力していた場合は、4番目の操作が不要となるので、この手間を入れるか入れないかで混乱します。4番目の手順を忘れてノーマルモードに移行した世のVimmerは、「っっっっっj」などをしょっちゅう打っていて、非常にイライラしています。

これがVimの日本語入力問題です。

解決方法

解決策として、たとえば以下が考えられます。

解決策 短所
日本語入力しない 英語の学習コストがつらいorz
KaoriyaさんのGVimを使う Windows以外の環境では構築が大変
TeraTermの制御シーケンスを応用する TeraTerm専用の.vimrcが必要となり、管理が面倒
AutoHotKey 独自のスクリプト言語ですこし学習が必要

私はすべて試した結果、AutoHotKeyを使うのが一番簡単だという結論に達しました。
短所として学習コストを挙げていますが、以降で公開しているソースコードをコピペすれば動きますので、この記事を読んでいただける方は大丈夫です!(ただし、Windowsに限ります)

AutoHotKeyとAPI

AutoHotKeyとAPIを準備します。

インストール

まず下記サイトで、「Download」→「Download Current Version」と進み、AutoHotKeyの.exeファイルをダウンロードします。
https://www.autohotkey.com/

AutoHotKeyダウンロードページ
AutoHotKeyダウンロードページ

ダウンロードした.exeファイルをダブルクリックすると、以下のウィンドウが出るので、「Express Installation」を左クリックします。

AutoHotKeyインストール Express Installation
AutoHotKeyインストール Express Installation

インストールが完了すると、以下のウィンドウが出るので、「Exit」を左クリックする。なお、ここで「Run AutoHotKey」をクリックするとヘルプ画面が出ます。

AutoHotKeyインストール Exit
AutoHotKeyインストール Exit

以上でインストール作業は終了です。

なお、後で使用するAPIは、下記サイトから入手します(私のソースコードをコピペする場合は不要です)。
https://w.atwiki.jp/eamat/pages/17.html

IME制御用関数群にある.zipファイルを左クリックしてダウンロードすればOKです。

IME制御用関数群
IME制御用関数群

設定

インストールすると、右クリック→新規作成から「AutoHotKey Script」が選択できるようになっています。
まず、この手順で空の.ahkファイルをデスクトップなどに用意します。

.ahkファイルを新規作成
.ahkファイルを新規作成

用意した.ahkファイルをテキストエディタで開きます。

.ahkファイル
.ahkファイル

以下のソースコードを.ahkファイルにコピペし、vim.ahkなど適宜名前を変更します。
なお、IME_GET()とIME_SET()はダウンロードした関数群(eamat.さん作成)のAPI.ahkから拝借いたしました。
API.ahkはANSI版とUTF8版ありますが、異なるのは文字コードだけなのでどちらでも構いません1

#UseHook  ; 無限ループ防ぐ

GroupAdd Terminal, ahk_class VTWin32  ; Tera Term
GroupAdd Terminal, ahk_class VirtualConsoleClass  ; Cmder

; includeする場合は、デバッグコードをコメントアウトする
;#include IME.ahk  ; IME制御関数群

; Tera TermとCmderがアクティブのとき以下のスクリプトが走る
#IfWinActive, ahk_group Terminal
    ; ESCキーが押下されたとき
    Esc::
        if(IME_GET()){
            ; IME有効時 ESC→スリープ→IME無効
            Send, {ESC}
            Sleep 1
            IME_SET(0)
        } else {
            ; IME無効時 ESC
            Send, {Esc}
        }
        return

    ; Ctrl + [ が押下されたとき
    ^[::
        if(IME_GET()){
            ; IME有効時 ESC→スリープ→IME無効
            Send, {ESC}
            Sleep 1
            IME_SET(0)
        } else {
            ; IME無効時 ESC
            Send, {Esc}
        }
        return

#IfWinActive

; https://w.atwiki.jp/eamat/pages/17.html からIME.ahkをダウンロード
; IME_GET()とIME_SET()を以下にコピペする

;-----------------------------------------------------------
; IMEの状態の取得
;   WinTitle="A"    対象Window
;   戻り値          1:ON / 0:OFF
;-----------------------------------------------------------
IME_GET(WinTitle="A")  {
    ControlGet,hwnd,HWND,,,%WinTitle%
    if  (WinActive(WinTitle))   {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
        NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
                 ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
    }

    return DllCall("SendMessage"
          , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hwnd)
          , UInt, 0x0283  ;Message : WM_IME_CONTROL
          ,  Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
          ,  Int, 0)      ;lParam  : 0
}

;-----------------------------------------------------------
; IMEの状態をセット
;   SetSts          1:ON / 0:OFF
;   WinTitle="A"    対象Window
;   戻り値          0:成功 / 0以外:失敗
;-----------------------------------------------------------
IME_SET(SetSts, WinTitle="A")    {
    ControlGet,hwnd,HWND,,,%WinTitle%
    if  (WinActive(WinTitle))   {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0)
        NumPut(cbSize, stGTI,  0, "UInt")   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", Uint,0, Uint,&stGTI)
                 ? NumGet(stGTI,8+PtrSize,"UInt") : hwnd
    }

    return DllCall("SendMessage"
          , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hwnd)
          , UInt, 0x0283  ;Message : WM_IME_CONTROL
          ,  Int, 0x006   ;wParam  : IMC_SETOPENSTATUS
          ,  Int, SetSts) ;lParam  : 0 or 1
}

最後に作成した.ahkファイルを右クリックし、「Run Script」を左クリックすると起動します。

.ahk起動
.ahk起動

これで、長年の日本語入力問題が解決された夢の世界を手に入れることできます!

なお、私の最新版の.ahkファイルは以下に置きました。
- https://github.com/ari23ant/autohotkey

アプリを追加したいとき

上記のソースコードでは、TeraTermとCmderでvimを使うときを想定しています。

GroupAdd Terminal, ahk_class VTWin32  ; Tera Term
GroupAdd Terminal, ahk_class VirtualConsoleClass  ; Cmder

アプリを追加したい場合は、ソースコードにアプリごとのahk_classを追加しなければいけません。
このahk_classを調べるには、まずAutoHotKeyを起動した状態で、インジケータから「AutoHotKey」を右クリックします。

ahkインジケータ
ahkインジケータ

出てきたウィンドウから「Window Spy」を右クリックします。

ahk Window Spy
ahk Window Spy

「Window Spy」を起動した状態で、追加したいアプリを選択(アクティブ状態に)すると、下の赤枠にアプリのahk_classを確認できます(下記はTera Termの例)。

ahk ahk_class確認
ahk ahk_class確認

記載したソースコードにahk_classを追記し、再度「Run Script」すれば使えるようになります。

おわりに

vimを本格的に使うようになって5年ほどですが、やっと素晴らしい世界を手に入れることができました。
今まではほんとにつらかった。。。

ぜひ世界のVimmerにもこの世界を体感してもらいたいです!笑

参考になれば幸いです(^^)

参考

この記事を書くにあたって、参考にさせていただいた文献は次の通りです。英語学習は各自で努力しましょう!

Tera Term

AutoHotKey


  1. 私はUTF-8が好きなので、UTF8を選びました。