とぴやまのブログ(アーカイブ)

元はてなダイアリー

IMEの前後参照変換機能に対応するには

連続して入力しない場合でも、カーソル位置の前後にある既に入力済みの文字(単語)を参考にして文脈に合った漢字変換を提供する機能が Windows にはあります。この場では「前後参照変換機能」と呼ぶことにします。

例えば、

  • 【花が】「さいた」 →[花が咲いた]
  • 【布を】「さいた」 →[布を裂いた]
  • 【時間を】「さいた」 →[時間を割いた]

【】の中の文字(花が、布を、時間を)を予め入力して(IMEを使わないコピー&ペーストが良い)おいてから、「さいた」とキーボードから入力して変換します。この「前後参照変換機能」が有効になっていれば、[]の中のように、それぞれ異なった変換が行われます。

秀丸エディタの ver7βで対応したようで、今話題(?)の機能ですが、Google検索ではヒットしなかったので、実装方法について調べてみました。次の通りです。

  1. ウインドウプロシージャで、(uMsg, wParam) = (WM_IME_REQUEST, IMR_DOCUMENTFEED) のメッセージが来た時に、構造体 RECONVERTSTRING と 文字列の長さ分のバイト数を返す
  2. その後にIMEは反応して、返したバイト数分のデータを格納できるバッファポインタを lParam に入れて再度 (WM_IME_REQUEST,IMR_DOCUMENTFEED) のメッセージを投げてくるので、そのバッファに対して必要なデータを格納して返す

文字列は、いわゆる段落1つ分(つまり改行から改行までの)文字列で良いようです。

#include <imm.h>

LRESULT wndsubproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  if (uMsg == WM_IME_REQUEST) {
    if (wParam == IMR_DOCUMENTFEED) {
      if (lParam != 0) {
        //lParam != 0 の時(2回目の呼び出し)は
        //lParam を RECONVERTSTRING と 文字列格納バッファに使用する
        RECONVERTSTRING *pReconv   = (RECONVERTSTRING*)lParam;
        char*  pszParagraph        = (char*)pReconv + sizeof(RECONVERTSTRING);
        
        pReconv->dwSize            = sizeof(RECONVERTSTRING);
        pReconv->dwVersion         = 0;
        pReconv->dwStrLen          = <文字列の長さ> ;
        pReconv->dwStrOffset       = sizeof(RECONVERTSTRING);
        pReconv->dwCompStrLen      = 0;
        pReconv->dwCompStrOffset   = 0;
        pReconv->dwTargetStrLen    = 0;
        pReconv->dwTargetStrOffset = <文字列の先頭からのカーソル位置> ;
        
        strcpy(pszParagraph, <文字列の元のバッファ>, <文字列の長さ>);
      }
      //lParam == 0 の時(1回目の呼び出し)は、バッファのサイズを返すだけ。
      //lParam が、0でも!0でも指定する返値は同じ
      return sizeof(RECONVERTSTRING) + <文字列の長さ> ;
    }
  }
  //それ以外のメッセージは、本来のウインドウプロシージャを実行する
  return  CallWindowProc((WNDPROC)Org_WndProc, hwnd, uMsg, wParam, lParam);
}