スポンサーリンク

Win32APIでIMEを使用(3)入力中の文字列(コンポジションウィンドウ)の枠を取得

変換中の文字列が表示されている領域(コンポジションウィンドウ)を直接取得する方法は見つからなかったが、IMEが使用中のフォントを指定してGetTextExtentPoint32を使えば、編集中の文字列の縦・横のサイズと同じものをピクセルで取得できる。

ただ、コンポジションウィンドウのフォントを取得する方法がない。

取得する方法はないが設定はImmSetCompositionFontでできるので、設定した後であれば使用中のフォントがわかるのでそれを使う。

 

#pragma warning(disable:4996)

#include <windows.h>
#include <imm.h>
#pragma comment(lib, "imm32.lib")

#include <string>

// IMEで使用するフォントを設定
void SetFont(HIMC hIMC,HFONT hFont) {

    // フォントの情報を取得
    LOGFONT logFont = {};
    GetObject(hFont, sizeof(LOGFONT), &logFont);

    // IMEのコンポジションウィンドウにフォントを設定
    ImmSetCompositionFont(hIMC, &logFont);

}

// 変換中の文字列を取得
std::wstring GetCompositionString(HIMC hIMC) {
    std::wstring str;

    if (hIMC) {
        DWORD dwSize = ImmGetCompositionString(hIMC, GCS_COMPSTR, NULL, 0);
        if (dwSize > 0) {
            wchar_t* compStr = new wchar_t[dwSize / sizeof(wchar_t) + 1];
            ImmGetCompositionString(hIMC, GCS_COMPSTR, compStr, dwSize);
            compStr[dwSize / sizeof(wchar_t)] = L'\0';
            str = compStr;
            delete[] compStr;
        }
    }

    return str;
}
      
// 文字列を描画するサイズを取得
SIZE
GetTextDrawSize(const std::wstring& str, HWND hWnd, HDC hdc) { // フォントの情報を取得 HFONT hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0); // HDCにフォントを選択 HFONT old = (HFONT)SelectObject(hdc, hFont); // 変換中の文字列のサイズを計算 SIZE textSize; GetTextExtentPoint32(hdc, str.data(), str.length(), &textSize); SelectObject(hdc,old); return textSize; }

// 変換中の文字列の描画領域を計算
SIZE CalculateCompositionStringSIZE(HWND hWnd, HIMC hIMC,HDC hdc) {

    SIZE size = { 0, 0 };

    if (hIMC) {
        std::wstring test = GetCompositionString(hIMC);

        size = GetTextDrawSize(test,hWnd,hdc);
        OutputDebugStringW(test.c_str());

    }

    return size;
}
      
// 変換中の文字列
void test_GCS_COMPSTR(HWND hWnd,HIMC hIMC, HDC hdc) {

    DWORD inputBytes = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);

    int inx = 100;
    int iny = 100;
    if (inputBytes) {

        SIZE size = CalculateCompositionStringSIZE(hWnd, hIMC, hdc);

        int iny2 = iny - 50;
        // inx ,iny-50 にsizeの矩形を描画
        RECT rect;
        rect.left = inx;
        rect.top = iny2;
        rect.right = inx + size.cx;
        rect.bottom = iny2 + size.cy;
        Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);

    }
    if (inputBytes) {

        std::wstring text = GetCompositionString(hIMC);

        SetBkMode(hdc, TRANSPARENT);
        // 確定した文字列を描画
        TextOutW(hdc, inx, iny, text.data(), text.length());
        SetBkMode(hdc, OPAQUE);

    }

}

// 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を使用可能にする
        hIMC = ImmAssociateContext(hWnd, ImmCreateContext());

        SetFont(hIMC, (HFONT)GetStockObject(DEFAULT_GUI_FONT));

        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);

            RECT rc{ 0,0,640,480 };// 画面クリア
            FillRect(hdc, &rc, (HBRUSH)(WHITE_BRUSH));



            if (lParam & GCS_COMPSTR) {
                test_GCS_COMPSTR(hWnd,hIMC, hdc); // 編集中の処理
            }
            if (lParam & GCS_RESULTSTR) {
                test_GCS_RESULTSTR(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);;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {

    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"SZL-IME-TEST";

    RegisterClass(&wc);

    HWND hWnd = CreateWindowW(L"SZL-IME-TEST", L"title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL);


    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: