コード例 #1
0
ファイル: KeyHandler.cpp プロジェクト: aungkozaw/zawgyi
HRESULT CTextService::_HandleCharacterKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam)
{
	if (!_IsComposing())
		_StartComposition(pContext);
    // 
    // create an instance of the candidate list class.
    // 
    if (_pCandidateList == NULL)
        _pCandidateList = new CCandidateList(this);

    // 
    // The document manager object is not cached. Get it from pContext.
    // 
    ITfDocumentMgr *pDocumentMgr;
    if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK)
    {
        // 
        // get the composition range.
        // 
        ITfRange *pRange;
        if (_pComposition->GetRange(&pRange) == S_OK)
        {
            _pCandidateList->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange);
            pRange->Release();
        }
        pDocumentMgr->Release();
    }
	
	if (_IsComposing())
		_TerminateComposition(ec, pContext);

	return S_OK;
}
コード例 #2
0
HRESULT CTextService::_HandleCharacterKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam)
{
    ITfRange *pRangeComposition;
    TF_SELECTION tfSelection;
    ULONG cFetched;
    WCHAR ch;
    BOOL fCovered;

    // Start the new compositon if there is no composition.
    OutputDebugString("test compositing");
    if (!_IsComposing())
        _StartComposition(pContext);

    OutputDebugString("after test compositing");
    //
    // Assign VK_ value to the char. So the inserted the character is always
    // uppercase.
    //
    ch = (WCHAR)wParam;

    // first, test where a keystroke would go in the document if an insert is done
    if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1)
        return S_FALSE;

    // is the insertion point covered by a composition?
    if (_pComposition->GetRange(&pRangeComposition) == S_OK)
    {
        fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition);

        pRangeComposition->Release();

        if (!fCovered)
        {
            goto Exit;
        }
    }

    // insert the text
    // use SetText here instead of InsertTextAtSelection because a composition was already started
    //Don't allow to the app to adjust the insertion point inside the composition
    if (tfSelection.range->SetText(ec, 0, &ch, 1) != S_OK)
        goto Exit;

    // update the selection, make it an insertion point just past
    // the inserted text.
    tfSelection.range->Collapse(ec, TF_ANCHOR_END);
    pContext->SetSelection(ec, 1, &tfSelection);

    //
    // set the display attribute to the composition range.
    //
    _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput);

Exit:
    tfSelection.range->Release();
    return S_OK;
}
コード例 #3
0
ファイル: Composition.cpp プロジェクト: jrywu/DIME
HRESULT CDIME::_ProbeCompositionRangeNotification(_In_ TfEditCookie ec, _In_ ITfContext *pContext)
{
	debugPrint(L"CDIME::_ProbeCompositionRangeNotification(), \n");


	HRESULT hr = S_OK;
	if(!_IsComposing())
		_StartComposition(pContext);
	
	hr = E_FAIL;
    ULONG fetched = 0;
    TF_SELECTION tfSelection;

    if ( pContext == nullptr || (hr = pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) != S_OK || fetched != 1 ||tfSelection.range==nullptr)
	{
		_TerminateComposition(ec,pContext);
        return hr;
	}
	tfSelection.range->Release();
   
	
	ITfRange *pRange;
	ITfContextView* pContextView;
	ITfDocumentMgr* pDocumgr;
	if (_pComposition&&SUCCEEDED(_pComposition->GetRange(&pRange)) && pRange)
	{
		if(pContext && SUCCEEDED(pContext->GetActiveView(&pContextView)) && pContextView)
		{
			if(pContext && SUCCEEDED( pContext->GetDocumentMgr(&pDocumgr)) && pDocumgr && _pThreadMgr &&_pUIPresenter)
			{
				ITfDocumentMgr* pFocusDocuMgr;
				_pThreadMgr->GetFocus(&pFocusDocuMgr);
				if(pFocusDocuMgr == pDocumgr)
				{
					_pUIPresenter->_StartLayout(pContext, ec, pRange);
					_pUIPresenter->_MoveUIWindowsToTextExt();
				}
				else 
					_pUIPresenter->ClearNotify();

				pDocumgr->Release();
			}
		pContextView->Release();
		}
		pRange->Release();
	}


    
	_TerminateComposition(ec,pContext);
	return hr;
}
コード例 #4
0
ファイル: Composition.cpp プロジェクト: wyrover/weasel
/* Update Composition */
void WeaselTSF::_UpdateComposition(ITfContext *pContext)
{
	// get commit string from server
	std::wstring commit;
	weasel::Status status;
	weasel::Config config;

	auto context = std::make_shared<weasel::Context>();

	weasel::ResponseParser parser(&commit, context.get(), &status, &config);

	bool ok = m_client.GetResponseData(std::ref(parser));

	if (ok)
	{
		bool composing = _IsComposing();
		if (!commit.empty())
		{
			// 修复顶字上屏的吞字问题:
			// 顶字上屏(如五笔 4 码上屏时),当候选词数 > 1 时,
			// 第 5 码输入时会将首选项顶屏。
			// 此时由于第五码的输入,composition 应是开启的,同时也要在输入处插入顶字。
			// 这里先关闭上一个字的 composition,然后为后续输入开启一个新 composition。
			// 有点 dirty 但是 it works ...
			if (composing) {
				_EndComposition(pContext);
				composing = false;
			}
			_InsertText(pContext, commit);
		}
		if (status.composing && !composing)
		{
			if (!_fCUASWorkaroundTested)
			{
				/* Test if we need to apply the workaround */
				_UpdateCompositionWindow(pContext);
			}
			else if (!_fCUASWorkaroundEnabled || config.inline_preedit)
			{
				/* Workaround not applied, update candidate window position at this point. */
				_UpdateCompositionWindow(pContext);
			}
			_StartComposition(pContext, _fCUASWorkaroundEnabled && !config.inline_preedit);
		}
		else if (!status.composing && composing) {
			_EndComposition(pContext);
			composing = false;
		}
		if (composing && config.inline_preedit)
			_ShowInlinePreedit(pContext, context);
	}
}
コード例 #5
0
HRESULT COVTSF::_HandleCompositionInput(TfEditCookie ec, _In_ ITfContext *pContext, WCHAR wch)
{
    ITfRange* pRangeComposition = nullptr;
    TF_SELECTION tfSelection;
    ULONG fetched = 0;
    BOOL isCovered = TRUE;

    CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr;
    pCompositionProcessorEngine = _pCompositionProcessorEngine;

    if ((_pCandidateListUIPresenter != nullptr) && (_candidateMode != CANDIDATE_INCREMENTAL))
    {
        _HandleCompositionFinalize(ec, pContext, FALSE);
    }

    // Start the new (std::nothrow) compositon if there is no composition.
    if (!_IsComposing())
    {
        _StartComposition(pContext);
    }

    // first, test where a keystroke would go in the document if we did an insert
    if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched) != S_OK || fetched != 1)
    {
        return S_FALSE;
    }

    // is the insertion point covered by a composition?
    if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition)))
    {
        isCovered = _IsRangeCovered(ec, tfSelection.range, pRangeComposition);

        pRangeComposition->Release();

        if (!isCovered)
        {
            goto Exit;
        }
    }

    // Add virtual key to composition processor engine
    pCompositionProcessorEngine->AddVirtualKey(wch);

    _HandleCompositionInputWorker(pCompositionProcessorEngine, ec, pContext);

Exit:
    tfSelection.range->Release();
    return S_OK;
}
コード例 #6
0
ファイル: WeaselIME.cpp プロジェクト: n3wc0d3r/weasel
BOOL WeaselIME::ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState)
{
	EZDBGONLYLOGGERPRINT("Process key event: vKey = 0x%x, kinfo = 0x%x, HIMC = 0x%x", vKey, UINT32(kinfo), m_hIMC);  
	bool accepted = false;

	if (!m_client.Echo())
	{
		m_client.Connect(launch_server);
		m_client.StartSession();
	}

	weasel::KeyEvent ke;
	if (!ConvertKeyEvent(vKey, kinfo, lpbKeyState, ke))
	{
		// unknown key event
		return FALSE;
	}

	accepted = m_client.ProcessKeyEvent(ke);

	// get commit string from server
	wstring commit;
	weasel::Status status;
	weasel::ResponseParser parser(&commit, NULL, &status);
	bool ok = m_client.GetResponseData(boost::ref(parser));

	if (ok)
	{
		if (!commit.empty())
		{
			_EndComposition(commit.c_str());
		}
		else if (status.composing != m_composing)
		{
			if (m_composing)
				_EndComposition(NULL);
			else
				_StartComposition();
		}
	}

	return (BOOL)accepted;
}
コード例 #7
0
ファイル: KeyHandler.cpp プロジェクト: PCMan/TSF-chewing
HRESULT CTextService::_HandleKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam)
{

    /*
     * FIXME: the following keys are not handled:
     * shift left		VK_LSHIFT
     * shift right		VK_RSHIFT
     * caps lock		VK_CAPITAL
     * page up			VK_PRIOR
     * page down		VK_NEXT
     * ctrl num
     * shift space
     * numlock num		VK_NUMLOCK
	 */

    if (('A' <= wParam && wParam <= 'Z')) {
            chewing_handle_Default(mChewingContext, wParam - 'A' + 'a');
    } else if ('0' <= wParam && wParam <= '9') {
            chewing_handle_Default(mChewingContext, wParam);
    } else {
        switch(wParam) {
            case VK_OEM_COMMA:
                chewing_handle_Default(mChewingContext, ',');
                break;

            case VK_OEM_MINUS:
                chewing_handle_Default(mChewingContext, '-');
                break;

            case VK_OEM_PERIOD:
                chewing_handle_Default(mChewingContext, '.');
                break;

            case VK_OEM_1:
                chewing_handle_Default(mChewingContext, ';');
                break;

            case VK_OEM_2:
                chewing_handle_Default(mChewingContext, '/');
                break;

            case VK_OEM_3:
                chewing_handle_Default(mChewingContext, '`');
                break;

            case VK_SPACE:
                chewing_handle_Space(mChewingContext);
                break;

            case VK_ESCAPE:
                chewing_handle_Esc(mChewingContext);
                break;

            case VK_RETURN:
                chewing_handle_Enter(mChewingContext);
                break;

            case VK_DELETE:
                chewing_handle_Del(mChewingContext);
                break;

            case VK_BACK:
                chewing_handle_Backspace(mChewingContext);
                break;

            case VK_UP:
                chewing_handle_Up(mChewingContext);
                break;

            case VK_DOWN:
                chewing_handle_Down(mChewingContext);

            case VK_LEFT:
                chewing_handle_Left(mChewingContext);
                break;

            case VK_RIGHT:
                chewing_handle_Right(mChewingContext);
                break;

            case VK_HOME:
                chewing_handle_Home(mChewingContext);
                break;

            case VK_END:
                chewing_handle_End(mChewingContext);
                break;

            default:
                return S_OK;
        }
    }

    // Remove old candidate list. We will create a new one if necessary.
    _pCandidateList->_EndCandidateList();

    ChewingCandidates candidate(mChewingContext);
    if (!candidate.IsEmpty()) {
        _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeConverted);

        //
        // The document manager object is not cached. Get it from pContext.
        //
        ITfDocumentMgr *pDocumentMgr;
        if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK)
        {
            //
            // get the composition range.
            //
            ITfRange *pRange;
            if (_pComposition->GetRange(&pRange) == S_OK)
            {
                _pCandidateList->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange, candidate);
                pRange->Release();
            }
            pDocumentMgr->Release();
        }
        return S_OK;
    }

    ChewingString commit(mChewingContext, CHEWING_STRING_COMMIT);
    if (!commit.IsEmpty()) {
        // FIXME: Need a better way to submit a string
        if (!_IsComposing())
            _StartComposition(pContext);

        ULONG cFetched;
        BOOL fCovered;
        TF_SELECTION tfSelection;

        // FIXME: Why we need this here?
        // first, test where a keystroke would go in the document if an insert is done
        if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1)
            return S_FALSE;

        // FIXME: Why we need this here?
        // is the insertion point covered by a composition?
        ITfRange *pRangeComposition;
        if (_pComposition->GetRange(&pRangeComposition) == S_OK)
        {
            fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition);

            pRangeComposition->Release();

            if (!fCovered)
            {
                goto End3;
            }
        }

        if (tfSelection.range->SetText(ec, 0, commit.GetString(), commit.GetLength()) != S_OK)
            goto End3;

        _TerminateComposition(ec, pContext);
End3: // FIXME: RAII?
        tfSelection.range->Release();
    }

    /*
     * Composition is mapped to preedit buffer + zuin buffer
     */
    ChewingString preedit_zuin(mChewingContext, CHEWING_STRING_PREEDIT_ZUIN);
    if (preedit_zuin.IsEmpty()) {
        // Remove composition
        if (_IsComposing())
        {
            ULONG cFetched;
            BOOL fCovered;
            TF_SELECTION tfSelection;

            // FIXME: Why we need this here?
            // first, test where a keystroke would go in the document if an insert is done
            if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1)
                return S_FALSE;

            // FIXME: Why we need this here?
            // is the insertion point covered by a composition?
            ITfRange *pRangeComposition;
            if (_pComposition->GetRange(&pRangeComposition) == S_OK)
            {
                fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition);

                pRangeComposition->Release();

                if (!fCovered)
                {
                    goto End;
                }
            }

            // Empties the composition
            tfSelection.range->SetText(ec, 0, L"", 0);

            _TerminateComposition(ec, pContext);
End: // FIXME: RAII?
            tfSelection.range->Release();
        }
    } else {
        if (!_IsComposing())
            _StartComposition(pContext);

        ULONG cFetched;
        BOOL fCovered;
        TF_SELECTION tfSelection;
        // FIXME: Why we need this here?
        // first, test where a keystroke would go in the document if an insert is done
        if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1)
            return S_FALSE;

        // FIXME: Why we need this here?
        // is the insertion point covered by a composition?
        ITfRange *pRangeComposition;
        if (_pComposition->GetRange(&pRangeComposition) == S_OK)
        {
            fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition);

            pRangeComposition->Release();

            if (!fCovered)
            {
                goto End2;
            }
        }
        if (tfSelection.range->SetText(ec, 0, preedit_zuin.GetString(), preedit_zuin.GetLength()) != S_OK)
            goto End2;

        _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput);
End2: // FIXME: RAII?
        tfSelection.range->Release();
    }

    return S_OK;
}
コード例 #8
0
HRESULT CTextService::_SetText(TfEditCookie ec, ITfContext *pContext, const std::wstring &text, LONG cchCursor, LONG cchOkuri, BOOL fixed)
{
	TF_SELECTION tfSelection;
	ULONG cFetched = 0;
	LONG cch, cchRes;

	if(pContext == NULL && _pCandidateList != NULL)	//辞書登録用
	{
		_pCandidateList->_SetText(text, fixed, FALSE, FALSE);
		return S_OK;
	}

	if(!_IsComposing())
	{
		if(!_StartComposition(pContext))
		{
			return S_FALSE;
		}
	}

	if(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK)
	{
		return S_FALSE;
	}

	if(cFetched != 1)
	{
		SafeRelease(&tfSelection.range);
		return S_FALSE;
	}

	ITfRange *pRange;
	if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK)
	{
		if(_IsRangeCovered(ec, tfSelection.range, pRange))
		{
			pRange->SetText(ec, 0, text.c_str(), (LONG)text.size());

			// shift from end to start.
			// shift over mathematical operators (U+2200-U+22FF) is rejected by OneNote.
			if(cchCursor == 0)
			{
				cchRes = (LONG)cursoridx - (LONG)kana.size();
				if((complement && okuriidx != 0) ||
					(!cx_showmodemark && okuriidx != 0 && cursoridx <= okuriidx && cursoridx < kana.size()))
				{
					cchRes += 1;
				}
			}
			else
			{
				cchRes = cchCursor - (LONG)text.size();
				if(cchRes > 0)
				{
					cchRes = 0;
				}
				else if(cchRes < -(LONG)text.size())
				{
					cchRes = -(LONG)text.size();
				}
			}

			tfSelection.range->ShiftEndToRange(ec, pRange, TF_ANCHOR_END);
			tfSelection.range->ShiftStartToRange(ec, pRange, TF_ANCHOR_END);
			tfSelection.range->ShiftStart(ec, cchRes, &cch, NULL);
			//decide cursor position
			tfSelection.range->Collapse(ec, TF_ANCHOR_START);
			pContext->SetSelection(ec, 1, &tfSelection);

			//composition attribute
			if(!fixed)
			{
				ITfRange *pRangeClone;
				if(pRange->Clone(&pRangeClone) == S_OK)
				{
					pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END);
					pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START);

					if(cchCursor == 0 || !showentry)
					{
						if(inputkey)
						{
							_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputMark);
							if(cx_showmodemark)
							{
								pRangeClone->ShiftStart(ec, 1, &cch, NULL);
							}
						}

						if(!display_attribute_series[1] || !inputkey)
						{
							_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText);
						}

						if(cchOkuri != 0)
						{
							pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START);
							pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL);
							if(!display_attribute_series[2])
							{
								_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputOkuri);
							}

							if(hintmode && text.find_first_of(CHAR_SKK_HINT) != std::wstring::npos)
							{
								LONG hintpos = (LONG)text.find_first_of(CHAR_SKK_HINT);
								if(cchOkuri < hintpos)
								{
									pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START);
									pRangeClone->ShiftStart(ec, hintpos, &cch, NULL);
									_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText);
								}
							}
						}
					}
					else
					{
						_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvMark);
						if(cx_showmodemark)
						{
							pRangeClone->ShiftStart(ec, 1, &cch, NULL);
						}

						if(!display_attribute_series[4])
						{
							_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvText);
						}

						if(cchOkuri != 0)
						{
							pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START);
							pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL);
							if(!display_attribute_series[5])
							{
								_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvOkuri);
							}
						}

						pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END);
						pRangeClone->ShiftStartToRange(ec, tfSelection.range, TF_ANCHOR_END);
						if(!display_attribute_series[6])
						{
							_SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvAnnot);
						}
					}
					SafeRelease(&pRangeClone);
				}
			}

			// for Excel's PHONETIC function
			if(fixed && !text.empty())
			{
				ITfProperty *pProperty;
				if(pContext->GetProperty(GUID_PROP_READING, &pProperty) == S_OK)
				{
					VARIANT var;
					var.vt = VT_BSTR;
					std::wstring phone(kana);
					if(okuriidx == 0)
					{
						switch(inputmode)
						{
						case im_hiragana:
						case im_katakana:
						case im_katakana_ank:
							//接辞
							if(!abbrevmode && kana.size() >= 2)
							{
								if(kana.front() == L'>')
								{
									phone = kana.substr(1);
								}
								else if(kana.back() == L'>')
								{
									phone = kana.substr(0, kana.size() - 1);
								}
							}
							break;
						default:
							break;
						}
					}
					else
					{
						if(kana.size() > (okuriidx + 1))
						{
							phone = kana.substr(0, okuriidx) + kana.substr(okuriidx + 1);
						}
						else if(kana.size() >= okuriidx)
						{
							phone = kana.substr(0, okuriidx);
						}
					}
					if(!phone.empty())
					{
						var.bstrVal = SysAllocString(phone.c_str());
						pProperty->SetValue(ec, pRange, &var);
						SysFreeString(var.bstrVal);
					}
					SafeRelease(&pProperty);
				}
			}
		}

		SafeRelease(&pRange);
	}

	SafeRelease(&tfSelection.range);

	return S_OK;
}
コード例 #9
0
ファイル: CandidateHandler.cpp プロジェクト: t37990909/DIME
HRESULT CDIME::_HandleCandidateWorker(TfEditCookie ec, _In_ ITfContext *pContext)
{

	debugPrint(L"CDIME::_HandleCandidateWorker() \n");
    HRESULT hr = S_OK;
	CStringRange commitString, convertedString;
	CDIMEArray<CCandidateListItem> candidatePhraseList;	
	CStringRange lastChar;
	CStringRange notify;
	
    if (nullptr == _pUIPresenter)
    {
        goto Exit; //should not happen
    }
	
	const WCHAR* pCandidateString = nullptr;
	DWORD_PTR candidateLen = 0;
	BOOL arrayUsingSPCode =FALSE;

	if (!_IsComposing())
		_StartComposition(pContext);

	if (Global::imeMode == IME_MODE_ARRAY)// check if the _strokebuffer is array special code
	{
		candidateLen = _pCompositionProcessorEngine->CollectWordFromArraySpeicalCode(&pCandidateString);
		if(candidateLen) arrayUsingSPCode = TRUE;
	}
	candidateLen = 0;
	candidateLen = _pUIPresenter->_GetSelectedCandidateString(&pCandidateString);
	if (candidateLen == 0)
    {
		if(_candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION || _candidateMode == CANDIDATE_PHRASE)
		{
			_HandleCancel(ec, pContext);
			goto Exit;
		}
		else
		{
			hr = S_FALSE;
			_HandleCancel(ec, pContext);
			DoBeep(BEEP_COMPOSITION_ERROR); //beep for no valid mapping found
			goto Exit;
		}
    }
	if (_pCompositionProcessorEngine->IsArrayShortCode() && candidateLen == 1 && *pCandidateString == 0x2394) // empty position in arry short code table.
	{
		hr = S_FALSE;
		if (Global::imeMode == IME_MODE_PHONETIC)
			DoBeep(BEEP_WARNING);
		else
		{
			if (CConfig::GetClearOnBeep()) _HandleCancel(ec, pContext);
			DoBeep(BEEP_COMPOSITION_ERROR); //beep for no valid mapping found
		}
		goto Exit;
	}
	
	
	StringCchCopy(_commitString, 1, L"\0");
	StringCchCatN(_commitString, MAX_COMMIT_LENGTH, pCandidateString, candidateLen);
	commitString.Set(_commitString, candidateLen);
	//_commitString = commitString;
	
	PWCHAR pwch = new (std::nothrow) WCHAR[2];  // pCandidateString will be destroyed after _detelteCanddiateList was called.
	if(candidateLen > 1)
	{	
		StringCchCopyN(pwch, 2, pCandidateString + candidateLen -1, 1); 
	}else // cnadidateLen ==1
	{
		StringCchCopyN(pwch, 2, pCandidateString, 1); 	
	}
	lastChar.Set(pwch, 1 );
	//-----------------do reverse conversion notify. We should not show notify in UI-less mode, thus cancel reverse conversion notify in UILess Mode
	if (!_IsUILessMode())
	{
		if (_pITfReverseConversion[Global::imeMode])
		{
			_AsyncReverseConversion(pContext); //asynchronized the reverse conversion with editsession for better perfomance
		}
		//-----------------or complete real key code when input with wildcard
		else if (_isCandidateWithWildcard)
		{
			const WCHAR* pCandidateKeyCode = nullptr;
			DWORD_PTR keyCodeLen = _pUIPresenter->_GetSelectedCandidateKeyCode(&pCandidateKeyCode);
			StringCchCopy(_commitKeyCode, 1, L"\0");
			StringCchCatN(_commitKeyCode, MAX_KEY_LENGTH, pCandidateKeyCode, keyCodeLen);
			CStringRange commitKeyCode, convertedKeyCode;
			_pCompositionProcessorEngine->GetReadingString(&convertedKeyCode, NULL, &commitKeyCode.Set(_commitKeyCode, wcslen(_commitKeyCode)));
			_pUIPresenter->ShowNotifyText(&convertedKeyCode);
		}

	}
	//-----------------do  array spcial code notify. We should not show notify in UI-less mode, thus cancel forceSP mode in UILess Mode---
	BOOL ArraySPFound = FALSE;            
	if(Global::imeMode == IME_MODE_ARRAY && !_IsUILessMode()  && !arrayUsingSPCode && (CConfig::GetArrayForceSP() || CConfig::GetArrayNotifySP()))
	{
		CStringRange specialCode;
		CStringRange notifyText;
		ArraySPFound = _pCompositionProcessorEngine->GetArraySpeicalCodeFromConvertedText(&commitString, &specialCode); 
		if(specialCode.Get())
			_pUIPresenter->ShowNotifyText(&specialCode);
	}
	convertedString = commitString;
	//----------------- do TC to SC covert if required----------------------------------------------------------------------------------
	if(CConfig::GetDoHanConvert())
	{
		_pCompositionProcessorEngine->GetSCFromTC(&commitString, &convertedString);
	}
	//----------------- commit the selected string  ------------------------------------------------------------------------------------ 
	if(Global::imeMode == IME_MODE_ARRAY && !_IsUILessMode()  && !arrayUsingSPCode && CConfig::GetArrayForceSP() &&  ArraySPFound )
	{
		_HandleCancel(ec, pContext);
		DoBeep(BEEP_WARNING);
		return hr;
	}
	else
	{
		hr = _AddComposingAndChar(ec, pContext, &convertedString);
		if (FAILED(hr))	return hr;
		// Do not send _endcandidatelist (or handleComplete) here to avoid cand dissapear in win8 metro
		_HandleComplete(ec,pContext);
	}
	//-----------------do accociated phrase (make phrase)--------------------------------------------------------------------------------
	if (CConfig::GetMakePhrase())
	{
		_pCompositionProcessorEngine->GetCandidateStringInConverted(lastChar, &candidatePhraseList);


		// We have a candidate list if candidatePhraseList.Cnt is not 0
		// If we are showing reverse conversion, use UIPresenter

		if (candidatePhraseList.Count())
		{
			CStringRange emptyComposition;
			if (!_IsComposing())
				_StartComposition(pContext);  //StartCandidateList require a valid selection from a valid pComposition to determine the location to show the candidate window
			_AddComposingAndChar(ec, pContext, &emptyComposition.Set(L" ",1)); 

			_pUIPresenter->_ClearCandidateList();
			_pUIPresenter->_SetCandidateTextColor(CConfig::GetPhraseColor(), CConfig::GetItemBGColor());    // Text color is green
			_pUIPresenter->_SetCandidateSelectedTextColor(CConfig::GetSelectedColor(), CConfig::GetSelectedBGColor());    
			_pUIPresenter->_SetCandidateNumberColor(CConfig::GetNumberColor(), CConfig::GetItemBGColor());    
			_pUIPresenter->_SetCandidateFillColor(CConfig::GetItemBGColor());//(HBRUSH)(COLOR_WINDOW+1));    // Background color is window
			_pUIPresenter->_SetCandidateText(&candidatePhraseList, _pCompositionProcessorEngine->GetCandidateListIndexRange(),
				TRUE, _pCompositionProcessorEngine->GetCandidateWindowWidth());
			_pUIPresenter->_SetCandidateSelection(-1, FALSE); // set selected index to -1 if showing phrase candidates
			_candidateMode = CANDIDATE_PHRASE;
			_isCandidateWithWildcard = FALSE;	
			
		}
		else
		{   //cancel the composition if the phrase lookup return 0 results
			_HandleCancel(ec,pContext);
		}


	}
	else
		_DeleteCandidateList(TRUE, pContext); // endCanddiateUI if not doing associated phrase.
		
Exit:
    return hr;
}