こちらにあるようにWindows APIの一つであるIMM APIを直に叩いてパッチを作成しました。
IMM APIは具体的な使用例などが載ったドキュメントなどは少なく、ctyepesを使った事もなかったのでそこそこ苦労しました。
ですので本記事がグラフィックライブラリのIME関連の実装をやってみようという方の一助となれば幸いです。
IMM API
さて、基本的な使い方ですが
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
ImmReleaseContext(hWnd, hImc);
とすることでhImcを取得し、各IMM関数に引数として渡す、という感じです。
最後のImmReleaseContextは忘れないでくださいね。IMMを利用するときのお約束みたいなものです。
本記事ではKivyのIME対応に必要としたIMMの機能について解説します。
まずは未確定文字列(コンポジション文字列)を取得する方法について。
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
char compStr[1028];
int size = ImmGetCompositionStringA(hImc, GCS_COMPSTR,NULL,0);
ImmGetCompositionStringA(hImc, GCS_COMPSTR, compStr, size);
compStr[size] = '\0';
ImmReleaseContext(hWnd, hImc);
//return compStr;
こんな感じにしてやればいいわけです。
ところでget_composition.cppではImmGetCompositionString関数を二回呼び出していますが、
一度目の呼び出しはコンポジション文字列のサイズ(バイト単位)を得るためだけの呼び出しです。
このようにサイズの取得を目的とする場合は、第三、第四引数にNULLと0を渡します。
ちなみに第二引数は「俺が得たいのはコンポジション文字列だよ」ということを表しています。
この辺の定数はMicrosoftのドキュメントを参照してください。
次は
確定された文字列を取得する方法です。
これも先ほどと同じように
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
char compStr[1028];
int size = ImmGetCompositionStringA(hImc, GCS_RESULTSTR, NULL, 0);
ImmGetCompositionStringA(hImc, GCS_RESULTSTR, compStr, size);
compStr[size] = '\0';
ImmReleaseContext(hWnd, hImc);
//return compStr;
こんな感じにしていけばいいわけです。
さっきと違うのは第二引数のGCS_RESULTSTRですね。
こいつを引数として渡してやることで「俺が得たいのは確定済み文字列だよ」ということを伝えています。
次は、コンポジション文字列をセットする方法について見ていきましょう。
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
char cmpStr[] = "テスト文字列~この文字列が表示される~"
ImmSetCompositionStringA(hImc, SCS_SETSTR, cmpStr, sizeof(cmpStr), NULL, 0);
ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CONVERT, 0);
ImmReleaseContext(hWnd, hImc);
今回は新しい関数が出ましたね。まずはImmSetCompositionStringについて。
この関数は第二、第三引数にそれぞれセットしたい文字列のポインタとそのサイズを渡してやることでコンポジション文字列をセットできます。
あ、第二引数のNI_COMPOSITIONSTRは「俺がセットしたいのはコンポジション文字列だよ」ということを表しています。
次のImmNotifyIME関数は、「コンポジション文字列をセットさせてもらったからよろしく」
ということをIME側に伝える関数です。この関数の引数についてはMicrosoftのドキュメントを参照してください。
最後にIMEが開いているか否かを得る方法について。
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
bool is_opening = ImmGetOpenStatus(hImc) ? true:false;
ImmReleaseContext(hWnd, hImc);
これは解説するまでもないですね。
以上ーーー!!
##kivy
kivy側の解説は後日やる気があったら
##ctypes
c++ <=> python間の連携はctypesを使いました。やる気があったら後日載せます。
#Usage
試してみたい方はこちら をcloneして
python multi_language_textinput.py
もしくは
python3 multi_language_textinput.py
として試してみてください。