WM_IME_COMPOSITIONはlParamによって取得できる情報を区別している。特にGCS_COMPATTRは変換中の文字列の一文字ずつの情報を扱うのでATTR_*でさらに分岐が必要。
#pragma warning(disable:4996) #include <windows.h> #include <imm.h> #pragma comment(lib, "imm32.lib") #include <string> // https://learn.microsoft.com/ja-jp/windows/win32/intl/ime-composition-string-values
// 変換中の文字列 GCS_COMPSTR void test_GCS_COMPSTR(HIMC hIMC, HDC hdc) { DWORD inputBytes = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0); if (inputBytes) { size_t U16Count = inputBytes / sizeof(wchar_t) + 1;// wchar_tでの、NULLを含んだ文字数 wchar_t* buffer = new wchar_t[U16Count]; // 確定した文字列を取得 ImmGetCompositionStringW(hIMC, GCS_COMPSTR, buffer, inputBytes); buffer[U16Count - 1] = L'\0'; // 確定した文字列を描画 int inx = 0; int iny = 0; TextOutW(hdc, inx, iny, buffer, wcslen(buffer)); delete[] buffer; } }
// 変換中の文字列の属性情報 GCS_COMPATTR void test_GCS_COMPATTR(HIMC hIMC, HDC hdc) { DWORD attr = ImmGetCompositionString(hIMC, GCS_COMPATTR, NULL, 0); BYTE* buffer = new BYTE[attr];// 変換中の文字数と同じ個数の要素を確保 ImmGetCompositionString(hIMC, GCS_COMPATTR, buffer, attr);// 変換中の各文字ごとに状態情報が格納される char str[256] = {}; for (size_t i = 0; i < 256; i++) str[i] = ' '; str[255] = '\0'; TextOutA(hdc, 0, 30, str, strlen(str)); size_t i; for (i = 0; i < attr; i++) { switch (buffer[i]) { case ATTR_INPUT: str[i] = 'I'; break; case ATTR_TARGET_CONVERTED: str[i] = 'T'; break; case ATTR_CONVERTED: str[i] = 'C'; break; case ATTR_FIXEDCONVERTED: str[i] = 'F'; break; case ATTR_TARGET_NOTCONVERTED: str[i] = 'N'; break; case ATTR_INPUT_ERROR: str[i] = 'E'; break; } } str[i] = '*'; TextOutA(hdc, 0, 30, str, strlen(str)); delete[] buffer; }
// 変換中の文字列内のカーソル位置 void test_GCS_CURSORPOS(HIMC hIMC, HDC hdc) { LONG cursorPos = ImmGetCompositionString(hIMC, GCS_CURSORPOS, NULL, 0); char str[256] = {}; sprintf(str, "cursorPos:%d", cursorPos); TextOutA(hdc, 0, 50, str, strlen(str)); }
// 変換開始位置 GCS_DELTASTART void test_GCS_DELTASTART(HIMC hIMC, HDC hdc) { LONG deltaStart = ImmGetCompositionString(hIMC, GCS_DELTASTART, NULL, 0); char str[256] = {}; sprintf(str, "deltaStart:%d", deltaStart); TextOutA(hdc, 0, 90, str, strlen(str)); }
// GCS_RESULTSTR void test_GCS_RESULTSTR(HIMC hIMC,HDC hdc) { // GCS_RESULTSTR ... IMEの入力が確定されたフラグ // 確定した文字列のバイト数を取得(NULLは含まない) DWORD inputBytes = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0); if (inputBytes) { size_t U16Count = inputBytes / sizeof(wchar_t) + 1;// wchar_tでの、NULLを含んだ文字数 wchar_t* buffer = new wchar_t[U16Count]; // 確定した文字列を取得 ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buffer, inputBytes); buffer[U16Count - 1] = L'\0'; // 確定した文字列を描画 int inx = 100; int iny = 100; TextOutW(hdc, inx, iny, buffer, wcslen(buffer)); delete[] buffer; } }
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HIMC hIMC; int inx = 100; int iny = 100; switch (message) { case WM_CREATE: // IMEを使用可能にする ImmAssociateContext(hWnd, ImmCreateContext()); break; case WM_IME_STARTCOMPOSITION: OutputDebugString(L"IME 入力開始\n"); hIMC = ImmGetContext(hWnd); // IMEコンテキストを取得 if (hIMC) { // IMEのウィンドウ位置を設定 COMPOSITIONFORM cf2; cf2.dwStyle = CFS_POINT; cf2.ptCurrentPos.x = inx; cf2.ptCurrentPos.y = iny; ImmSetCompositionWindow(hIMC, &cf2); // IMEのウィンドウ位置を設定 ImmReleaseContext(hWnd, hIMC); } break; case WM_IME_COMPOSITION: // IMEの入力中の処理 hIMC = ImmGetContext(hWnd); if (hIMC) { HDC hdc = GetDC(hWnd); if (lParam & GCS_RESULTSTR) { test_GCS_RESULTSTR(hIMC,hdc); } if (lParam & GCS_COMPSTR) { test_GCS_COMPSTR(hIMC, hdc); } if (lParam & GCS_COMPATTR) { test_GCS_COMPATTR(hIMC, hdc); } if (lParam & GCS_CURSORPOS) { test_GCS_CURSORPOS(hIMC, hdc); } if (lParam & GCS_DELTASTART) { test_GCS_DELTASTART(hIMC, hdc); } ReleaseDC(hWnd, hdc); ImmReleaseContext(hWnd, hIMC); } break; case WM_IME_ENDCOMPOSITION: OutputDebugString(L"IME 入力終了\n"); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return DefWindowProc(hWnd, message, wParam, lParam);; }