none
CRitchEditCtrlの日本語入力時の変換される文字の開始/終了位置を取得したい

    質問

  • VS2013 MFC C++でソフトを開発しています。
    日本語入力は IMEです。

    同じような質問を上げていたのですが、Resが付かなかったので、質問内容をもう少し絞って再アップしました。

    文字を選択しないでカーソルがある位置で「変換」キーを押すと、カーソル前の文字列が変換されるのですが、
    その変換される文字の 開始/終了位置 の取る方法を知りたいです。



    添付したソースはCRichEditCtrlを継承して日本語入力の確定をPreTranslateMessageで捕まえて、
    OnCharに飛ばして処理を行うサンプルになっております。
     (既存のCEditの処理を流用しているのと、CRichEditCtrlでは日本語の確定でOnCharに来ないので このような処理になっております)

    CEditでは OnChar内でGetSelを使って選択領域を得ているのですが、CRitchEditCtrlのサンプルのOnCharの位置でGetSelを使っても上手く取れないのでWM_IME_STARTCOMPOSITION時に取得していました。
    通常の日本語入力時はこれで問題なかったのですが、


    たとえば、 ”ああああとうきょう"  いう既存の文字列の最後にカーソルを移動した状態で「変換」キーを押すと、"とうきょう"が"東京"に変換されます。
    この"とうきょう"の位置 start:4 end:8 を取りたいです。 ちなみにこの操作ではWM_IME_STARTCOMPOSITIONは来ません

    よろしくお願い致します。

    BOOL CTestRichEditCtrl::PreTranslateMessage(MSG* pMsg) 
    {
    	if( pMsg->message == WM_IME_STARTCOMPOSITION )
    	{
    		_SelectStart = -1;
    		_SelectEnd = -1;
    		GetSel( _SelectStart, _SelectEnd );
    
    	} else if( pMsg->message == WM_IME_ENDCOMPOSITION )
    	{
    	} else if( pMsg->message == WM_IME_COMPOSITION )
    	{
    		if( pMsg->lParam & GCS_RESULTSTR )
    		{ // 2バイト入力の確定
    
    			TCHAR tchar[1024];
    
    			HIMC _hImc = ::ImmGetContext( m_hWnd );
    
    			// IME の変換文字列を取得します。
    			int len = ImmGetCompositionStringW( _hImc, GCS_RESULTSTR, NULL, 0 );
    			memset( tchar , NULL, BUFF_SIZE );		
    			ImmGetCompositionStringW( _hImc, GCS_RESULTSTR, tchar, len );
    			ImmReleaseContext( m_hWnd, _hImc );
    
    			for ( int i = 0; i < len; i++ )
    			{
    				PostMessageW( WM_CHAR, (WPARAM)tchar[i], 0 );
    			}
    			ImmReleaseContext( m_hWnd, _hImc );
    		}
    	}
    
       	return CRichEditCtrl::PreTranslateMessage(pMsg);
    }
    
    
    BOOL CTestRichEditCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
    {
    	CString strPrev;
    	GetWindowText( strPrev );    
    
    	CString strInput;
    	strInput += (TCHAR)nChar;
    	MSG msg;
    
    	// 2バイト文字入力処理
    	while (::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR, PM_REMOVE) )
    	{// キューに入っている文字列を取得
    		strInput += (TCHAR)msg.wParam;
    	}
    
    	
    	//_SelectStart/_SelectEndを使って所定の位置にSetWindowTextで入れなおしたり、諸々の処理を行う
    	SetWindowText( strPrevText + strInput ); -- ①
    
    	CRichEditCtrl::OnChar(nChar, nRepCnt, nFlags);
    }



    2018年5月2日 0:00

回答

  • 素のCRichEditCtrlであれば、再変換される範囲はPreTranslateMessageよりも前のOnWndMsgでWM_IME_STARTCOMPOSITIONをつかまえられますよ。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2018年5月5日 2:42

すべての返信

  • 素のCRichEditCtrlであれば、再変換される範囲はPreTranslateMessageよりも前のOnWndMsgでWM_IME_STARTCOMPOSITIONをつかまえられますよ。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2018年5月5日 2:42
  • 情報ありがとうございます。

    現状では、変換前の全文字列、変換後の全文字列、ImmGetCompositionStringWで得られる変換文字列 の3つの文字列からどの文字が変換されたか割り出していました。

    因みに、OnKeyDown時に GetSelしましたが、現在のカーソル位置だけで範囲は得られなかったです。

    OnWndMsgを定義してみましたが、このメソッドに来ませんでした。 なにか使い方は悪いでしょうか? (BEGIN_MESSAGE_MAP~END_MESSAGE_MAPには何も追加していません)

    class CTestRichEditCtrl : public CRichEditCtrl
    {
    	DECLARE_DYNAMIC(CVerticalEditCtrl)
    
    protected:
    	DECLARE_MESSAGE_MAP()
    	virtual BOOL	OnWndMsg(CWnd* lpWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult);
    	virtual BOOL	PreTranslateMessage(MSG* pMsg);
          
            ...
    }
    
         
    
    BOOL CTestRichEditCtrl::OnWndMsg(CWnd* lpWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
    {
    	return FALSE;
    } 

    2018年5月5日 11:49
  • 引数定義が違っているからかなぁ

    virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) override;
    #あと基底クラスを呼ぶ必要もあるでしょう。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2018年5月5日 12:57 override指定子を追加
    2018年5月5日 12:54
  • ご指摘ありがとうございました。

    OnWndMsg の第一引数の CWndが余計だったようです。
     
    無事OnWndMsgは呼ばれるようになりましたが、OnWndMsgで「変換」キーを押したタイミングを捕まえて GetSelをしてもOnKeyDownと同じ値の変換後のカーソル位置でした。

    せっかく情報を頂いたのですが、前述した3つの文字列から変換された範囲を割り出すようにします。

    ありがとうございました

    2018年5月5日 13:43
  • すくなくともWin7+OfficeIME,Win10+MS IMEの環境ではWM_IME_STARTCOMPOSITIONでGetSel,GetTextを見れば取れてるんですが。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2018年5月5日 21:02
  • Resありがとうございます。

    WM_IME_STARTCOMPOSITIONが来たときに、GetSelすれば変換範囲が取れる事は判っています。

    カーソルを文字の後に置いただけ(選択もしない)で 「変換」キーを押すとWM_IME_STARTCOMPOSITIONには来ません。(WM_IME_ENDCOMPOSITION/WM_IME_COMPOSITION は来ます)
    この場合IMEまかせで任意の文字が変換されるのですが、その任意の文字の位置を取得したいです

    2018年5月6日 2:00
  • PreTranslateMessageまでは来ないがOnWndMsgでならWM_IME_STARTCOMPOSITIONをつかまえられるという話なのですが…

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2018年5月6日 3:21
  • たしかに

    OnWndMsgでWM_IME_STARTCOMPOSITIONの時 GetSelしたら取れました。

    もう少し検証して良さそうなら回答マークを付けさせて頂きます。

    ありがとうございました。

    2018年5月6日 4:06