第8回 IME制御
BTMemoで行っているIME制御は
・起動時にIMEをONにする。
・未確定文字列を自ウィンドウ内に表示させる
・確定文字列を取り込む
の3点です。では、順に見ていきましょう。
(1)プログラム起動直後に(自動で)IMEをONにする
// WM_CREATEメッセージを処理します。 int CChildView::OnCreate(LPCREATESTRUCT
lpCreateStruct) { … // (A)IMEコンテキストを取得します。IMEを操作する場合には必要なおまじないです。 HIMC
hImc = ImmGetContext(this->m_hWnd); // (B)IMEをONにします。たったこれだけです。 ImmSetOpenStatus(hImc,
TRUE); // (C)IMEコンテキストを開放します。IMEを操作し終わった場合のおまじないです。 ImmReleaseContext(this->m_hWnd,
hImc); … } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 備考: IMEはキーボード入力を取り扱うウィンドウ単位に処理されます。従ってウィンドウが存在しない時点ではIMEを制御できません。 |
(2)未確定文字列を自ウィンドウ内に表示させる
// WM_IME_STARTCOMPOSITIONメッセージを処理します。 //
このメッセージは、新たに未確定文字列が生じた場合に送られてきます。 LRESULT
CChildView::OnIMEStartComposition(WPARAM wParam, LPARAM lParam) { // (A)IMEコンテキストを取得します。IMEを操作する場合には必要なおまじないです。 HIMC
hIMC = ImmGetContext(this->m_hWnd); // (B)未確定文字列を表示するときに使用するフォントを指定します。 // BTMemoでは、カレット位置の文字のフォントと同じ物を指定しています。 LOGFONT lf = … ; ImmSetCompositionFont(hIMC,
&lf); // (C)未確定文字列を表示する領域の左上隅座標を指定します。 // BTMemoでは、カレット位置の文字領域の左上隅座標を指定しています。 CPoint
pt = … ; COMPOSITIONFORM
cf; cf.dwStyle
= CFS_POINT; cf.ptCurrentPos
= pt; ImmSetCompositionWindow(hIMC,
&cf); // (D)IMEコンテキストを開放します。IMEを操作し終わった場合のおまじないです。 ImmReleaseContext(this->m_hWnd,
hIMC); // (E)デフォルト処理を呼び出さないとうまく動作しなかったような記憶があるのですが、もしかしたら不要かも
(^^;; return
DefWindowProc(WM_IME_STARTCOMPOSITION, wParam, lParam); } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 備考: テキスト入力を扱うとき、ほとんどの場合はエディットコントロールを使用すると思います。 私自身、文字入力を自分でハンドリングするのは初めてだったのですが、 自分で(この項の)コードを書かないと、未確定文字列が別ウィンドウに表示されるということを知りました。 |
(3)確定文字列を取り込む−その1
// WM_IME_COMPOSITIONメッセージを処理します。 //
このメッセージでは、IMEからのさまざまな通知が送られてきます。 LRESULT
CChildView::OnIMEComposition(WPARAM wParam, LPARAM lParam) { //(A)確定文字列が生じたのかどうかを検査します。
if
(lParam & GCS_RESULTSTR) { //(B)IMEコンテキストを取得します。IMEを操作する場合には必要なおまじないです。 HIMC
hIMC = ImmGetContext(this->m_hWnd); //(C)確定文字列の長さを調べ、その分のメモリを獲得してから確定文字列を取り込みます。 int
len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0); HANDLE
hData = (HANDLE)::GlobalAlloc(GPTR, (DWORD)len+1); char
*pData = (char *)::GlobalLock(hData); ImmGetCompositionString(hIMC,
GCS_RESULTSTR, pData, len + 1); ::GlobalUnlock(hData); //(D)ここで取得した文字列を処理します。終わったらメモリの開放を忘れずに! … ::GlobalFree(hData); //(E)未確定文字列が残っている場合がありますので、その未確定文字列を表示する領域の左上隅座標を指定します。 CPoint
pt = … ; COMPOSITIONFORM
cf; cf.dwStyle
= CFS_POINT; cf.ptCurrentPos
= pt; ImmSetCompositionWindow(hIMC,
&cf); //(F)IMEコンテキストを開放します。IMEを操作し終わった場合のおまじないです。 ImmReleaseContext(this->m_hWnd,
hIMC); } return
DefWindowProc(WM_IME_COMPOSITION, wParam, lParam); } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 備考: 当初、確定文字列を取り込む処理は行っていませんでした。(WM_CHARで確定文字を受取っていました) しかし、文字の入力の仕方によっては、カレット位置と未確定文字列の表示位置がずれてしまい、 上記の(E)を行う必要が生じたのです。 |
(4)確定文字列を取り込む−その2
//WM_IME_CHARメッセージを処理します。 LRESULT
CChildView::OnIMEChar(WPARAM wParam, LPARAM lParam) { //(A)メッセージを無視します return
0; } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 備考: WM_IME_COMPOSITIONメッセージで確定文字列を処理しているのですが、そこで処理した文字列がこのメッセージで1文字づつ送られてきます。 WM_IME_COMPOSITIONメッセージでの処理を工夫すればこのメッセージが生じないようにできるかもしれませんが、未調査です。 なお、このメッセージをDefWindowProcに渡すと、今度はWM_CHARのメッセージが生じますのでご注意ください。 |