// // reconv.cpp // #include "private.h" #include "globals.h" #include "common.h" #include "korimx.h" #include "candlstx.h" #include "fnrecon.h" #include "funcprv.h" #include "helpers.h" #include "immxutil.h" #include "editcb.h" #include "hanja.h" #include "ucutil.h" ////////////////////////////////////////////////////////////////////////////// // // CFunction // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CFunction::CFunction(CFunctionProvider *pFuncPrv) { _pFuncPrv = pFuncPrv; _pFuncPrv->AddRef(); } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CFunction::~CFunction() { SafeRelease(_pFuncPrv); } #if 1 //+--------------------------------------------------------------------------- // // CFunction::GetTarget // //---------------------------------------------------------------------------- HRESULT CFunction::GetTarget(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, BOOL bAdjust, ITfRange **ppRangeTmp, WCHAR **ppszText, ULONG *pcch) { ITfProperty* pProp; ITfRange* pRangeTmp = NULL; // init *pcch = 0; // AIMM? if (CKorIMX::GetAIMM(pic)) { // Allocate just one char string buffer *ppszText = new WCHAR[2]; Assert(*ppszText != NULL); if (*ppszText == NULL) return E_OUTOFMEMORY; pRange->Clone(&pRangeTmp); *pcch = 1; pRangeTmp->GetText(ec, 0, *ppszText, sizeof(WCHAR), pcch); *((*ppszText) + 1) = L'\0'; *ppRangeTmp = pRangeTmp; return S_OK; } // if reading prop exist. if (SUCCEEDED(pic->GetProperty(GUID_PROP_READING, &pProp))) { ITfRange *pPropRange; HRESULT hr = pProp->FindRange(ec, pRange, &pPropRange, TF_ANCHOR_START); if (SUCCEEDED(hr) && pPropRange) { BSTR bstr; if (SUCCEEDED(GetBSTRPropertyData(ec, pProp, pPropRange, &bstr))) { pPropRange->Clone(&pRangeTmp); if (bAdjust || CompareRanges(ec, pRange, pRangeTmp) == CR_EQUAL) { *pcch = SysStringLen(bstr); *ppszText = new WCHAR[*pcch + 1]; if (*ppszText) StringCchCopyW(*ppszText, *pcch + 1, bstr); } } SysFreeString(bstr); pPropRange->Release(); } pProp->Release(); } // If no reading property if (!(*ppszText)) { LONG cch; BOOL fEmpty; pRange->IsEmpty(ec, &fEmpty); pRange->Clone(&pRangeTmp); // Select only one char if (!fEmpty) { pRangeTmp->Collapse(ec, TF_ANCHOR_START); pRangeTmp->ShiftEnd(ec, 1, &cch, NULL); } else { pRangeTmp->ShiftEnd(ec, 1, &cch, NULL); if (cch==0) pRangeTmp->ShiftStart(ec, -1, &cch, NULL); } Assert(cch != 0); if (cch) { // Allocate just one char string buffer *ppszText = new WCHAR[2]; Assert(*ppszText != NULL); if (*ppszText == NULL) return E_OUTOFMEMORY; *pcch = 1; pRangeTmp->GetText(ec, 0, *ppszText, sizeof(WCHAR), pcch); *((*ppszText) + 1) = L'\0'; // Office #154974 // If there is any embedded char exist, skip it forward. while (**ppszText == TS_CHAR_EMBEDDED) { pRangeTmp->ShiftStart(ec, 1, &cch, NULL); if (cch == 0) break; pRangeTmp->ShiftEnd(ec, 1, &cch, NULL); if (cch == 0) break; *pcch = 1; pRangeTmp->GetText(ec, 0, *ppszText, sizeof(WCHAR), pcch); *((*ppszText) + 1) = L'\0'; } } } *ppRangeTmp = pRangeTmp; return S_OK; } #else //+--------------------------------------------------------------------------- // // CFunction::GetTarget // //---------------------------------------------------------------------------- HRESULT CFunction::GetTarget(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, BOOL bAdjust, ITfRange **ppRangeTmp, WCHAR **ppszText, ULONG *pcch) { ITfRange *pRangeTmp = NULL; LONG cch; BOOL fEmpty; *pcch = 0; pRange->IsEmpty(ec, &fEmpty); if (!fEmpty) { pRange->Clone(&pRangeTmp); pRangeTmp->Collapse(ec, TF_ANCHOR_START); pRangeTmp->ShiftEnd(ec, 1, &cch, NULL); if (cch) { *ppszText = new WCHAR[2]; *pcch = 1; pRangeTmp->GetText(ec, 0, *ppszText, sizeof(WCHAR), pcch); *((*ppszText) + 1) = L'\0'; } } else { pRange->Clone(&pRangeTmp); pRangeTmp->ShiftEnd(ec, 1, &cch, NULL); if (cch) { *ppszText = new WCHAR[2]; *pcch = 1; pRangeTmp->GetText(ec, 0, *ppszText, sizeof(WCHAR), pcch); *((*ppszText) + 1) = L'\0'; } } *ppRangeTmp = pRangeTmp; return S_OK; } #endif //+--------------------------------------------------------------------------- // // CFunction::GetFocusedTarget // //---------------------------------------------------------------------------- BOOL CFunction::GetFocusedTarget(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, BOOL bAdjust, ITfRange **ppRangeTmp) { ITfRange *pRangeTmp = NULL; ITfRange *pRangeTmp2 = NULL; IEnumTfRanges *pEnumTrack = NULL; ITfRange *pPropRange; ITfReadOnlyProperty *pProp = NULL; BOOL bRet = FALSE; BOOL fWholeDoc = FALSE; if (!pRange) { fWholeDoc = TRUE; if (FAILED(GetRangeForWholeDoc(ec, pic, &pRange))) return FALSE; } if (bAdjust) { // // multi owner and PF_FOCUS range support. // if (FAILED(AdjustRangeByTextOwner(ec, pic, pRange, &pRangeTmp2, CLSID_KorIMX))) goto Exit; GUID rgGuid[1]; rgGuid[0] = GUID_ATTR_KORIMX_INPUT; if (FAILED(AdjustRangeByAttribute(_pFuncPrv->_pime->_GetLibTLS(), ec, pic, pRangeTmp2, &pRangeTmp, rgGuid, 1))) goto Exit; } else { pRange->Clone(&pRangeTmp); } // // check if there is an intersection of PF_FOCUS range and owned range. // if there is no such range, we return FALSE. // if (FAILED(EnumTrackTextAndFocus(ec, pic, pRangeTmp, &pProp, &pEnumTrack))) goto Exit; while(pEnumTrack->Next(1, &pPropRange, 0) == S_OK) { if (IsOwnerAndFocus(_pFuncPrv->_pime->_GetLibTLS(), ec, CLSID_KorIMX, pProp, pPropRange)) bRet = TRUE; pPropRange->Release(); } pProp->Release(); if (bRet) { *ppRangeTmp = pRangeTmp; (*ppRangeTmp)->AddRef(); } Exit: SafeRelease(pEnumTrack); SafeRelease(pRangeTmp); SafeRelease(pRangeTmp2); if (fWholeDoc) pRange->Release(); return bRet; } ////////////////////////////////////////////////////////////////////////////// // // CFnReconversion // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // IUnknown // //---------------------------------------------------------------------------- STDAPI CFnReconversion::QueryInterface(REFIID riid, void **ppvObj) { #if NEVER *ppvObj = NULL; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfFnReconversion)) { *ppvObj = SAFECAST(this, CFnReconversion *); } if (*ppvObj) { AddRef(); return S_OK; } #endif return E_NOINTERFACE; } STDAPI_(ULONG) CFnReconversion::AddRef() { return InterlockedIncrement(&_cRef); } STDAPI_(ULONG) CFnReconversion::Release() { long cr; cr = InterlockedDecrement(&_cRef); Assert(cr >= 0); if (cr == 0) { delete this; } return cr; } //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CFnReconversion::CFnReconversion(CKorIMX *pKorImx, CFunctionProvider *pFuncPrv) : CFunction(pFuncPrv) { m_pKorImx = pKorImx; _cRef = 1; } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CFnReconversion::~CFnReconversion() { } //+--------------------------------------------------------------------------- // // CFnReconversion::GetDisplayName // //---------------------------------------------------------------------------- STDAPI CFnReconversion::GetDisplayName(BSTR *pbstrName) { *pbstrName = SysAllocString(L"Hanja Conv"); return S_OK; } //+--------------------------------------------------------------------------- // // CFnReconversion::IsEnabled // //---------------------------------------------------------------------------- STDAPI CFnReconversion::IsEnabled(BOOL *pfEnable) { *pfEnable = TRUE; return S_OK; } //+--------------------------------------------------------------------------- // // CFnReconversion::QueryRange // //---------------------------------------------------------------------------- STDAPI CFnReconversion::QueryRange(ITfRange *pRange, ITfRange **ppNewRange, BOOL *pfConvertable) { CEditSession2 *pes; ITfContext *pic; ESSTRUCT ess; HRESULT hr = E_OUTOFMEMORY; if (!pRange || !ppNewRange || !pfConvertable) return E_INVALIDARG; if (FAILED(pRange->GetContext(&pic))) goto Exit; ESStructInit(&ess, ESCB_RECONV_QUERYRECONV); ess.pRange = pRange; ess.pv1 = this; ess.pv2 = ppNewRange; if ((pes = new CEditSession2(pic, m_pKorImx, &ess, CKorIMX::_EditSessionCallback2)) != NULL) { pes->Invoke(ES2_READONLY | ES2_SYNC, &hr); pes->Release(); } *pfConvertable = (hr == S_OK); if (hr == S_FALSE) hr = S_OK; pic->Release(); Exit: return hr; } //+--------------------------------------------------------------------------- // // CFnReconversion::_QueryRange // //---------------------------------------------------------------------------- HRESULT CFnReconversion::_QueryRange(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, ITfRange **ppNewRange) { ULONG cch = 0; WCHAR *pszText = NULL; HRESULT hr = E_FAIL; ITfRange *pRangeTmp = NULL; // // KIMX doesn't support entire document reconversion. // if (!pRange) return hr; GetTarget(ec, pic, pRange, ppNewRange ? TRUE : FALSE, &pRangeTmp, &pszText, &cch); if (cch) { if (ppNewRange) pRangeTmp->Clone(ppNewRange); hr = S_OK; // In case of AIMM we should return error if the input char can't be coverted. if (CKorIMX::GetAIMM(pic)) { HANJA_CAND_STRING_LIST CandStrList; if (GetConversionList(*pszText, &CandStrList)) { // free buffer and return cicMemFree(CandStrList.pwsz); cicMemFree(CandStrList.pHanjaString); } else hr = S_FALSE; } } else hr = S_FALSE; if (pszText) delete pszText; SafeRelease(pRangeTmp); return hr; } //+--------------------------------------------------------------------------- // // CFnReconversion::GetReconversion // //---------------------------------------------------------------------------- STDAPI CFnReconversion::GetReconversion(ITfRange *pRange, ITfCandidateList **ppCandList) { ITfContext *pic; CCandidateListEx *pCandList; HRESULT hr; if (!pRange || !ppCandList) return E_INVALIDARG; if (FAILED(pRange->GetContext(&pic))) return E_FAIL; hr = GetReconversionProc(pic, pRange, &pCandList, fFalse); if (pCandList != NULL) { pCandList->QueryInterface( IID_ITfCandidateList, (void**)ppCandList ); pCandList->Release(); } pic->Release(); return hr; } //+--------------------------------------------------------------------------- // // CFnReconversion::_GetReconversion // //---------------------------------------------------------------------------- HRESULT CFnReconversion::_GetReconversion(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, CCandidateListEx **ppCandList, BOOL fSelection) { ULONG cch = 0; WCHAR *pszReading = NULL; HRESULT hr = E_FAIL; ITfRange *pRangeTmp = NULL; CCandidateStringEx *pCandExtraStr; GetTarget(ec, pic, pRange, TRUE, &pRangeTmp, &pszReading, &cch); if (cch) { CCandidateListEx *pCandList; HANJA_CAND_STRING_LIST CandStrList; WCHAR szCand[2]; WCHAR wch = 0; ULONG cch; // build candidate list pCandList = new CCandidateListEx(SetResult, pic, pRangeTmp); Assert(pCandList != NULL); if (pCandList == NULL) return E_OUTOFMEMORY; // Copy reading string StringCchCopyW(_szReading, ARRAYSIZE(_szReading), pszReading); // Get conv list from Hanja dict if (GetConversionList(*pszReading, &CandStrList)) { // If AIMM, don't select coversion char. if (!CKorIMX::GetAIMM(pic)) { // If there candidate exist, Set selection converting char if (fSelection) SetSelectionSimple(ec, pic, pRangeTmp); // if it is Hanja already converted, Add Hangul pronoun as extra cand str. pRangeTmp->GetText(ec, 0, &wch, sizeof(WCHAR), &cch); if (cch && !fIsHangul(wch)) { pCandList->AddExtraString(pszReading, MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), NULL, this, &pCandExtraStr); pCandExtraStr->Release(); } } for (UINT i=0; iAddString(szCand, MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), NULL, this, &pCandStr); pCandStr->SetInlineComment(CandStrList.pHanjaString[i].wzMeaning); pCandStr->m_bHanjaCat = CandStrList.pHanjaString[i].bHanjaCat; pCandStr->SetReadingString(_szReading); pCandStr->Release(); } // free buffer and return cicMemFree(CandStrList.pwsz); cicMemFree(CandStrList.pHanjaString); *ppCandList = pCandList; hr = S_OK; } } if (pszReading) delete pszReading; SafeRelease(pRangeTmp); return hr; } //+--------------------------------------------------------------------------- // // CFnReconversion::Reconvert // //---------------------------------------------------------------------------- HRESULT CFnReconversion::Reconvert(ITfRange *pRange) { CCandidateListEx *pCandList = NULL; ITfRange *pRangeTmp = NULL; ITfContext *pic; HRESULT hr; if (!pRange) return E_INVALIDARG; hr = E_FAIL; if (FAILED(pRange->Clone(&pRangeTmp))) goto Exit; if (FAILED(pRange->GetContext(&pic))) goto Exit; if (SUCCEEDED(hr = GetReconversionProc(pic, pRange, &pCandList, fTrue))) { hr = ShowCandidateList(pic, pRange, pCandList); SafeRelease(pCandList); } SafeRelease(pRangeTmp); SafeRelease(pic); Exit: return hr; } /* G E T R E C O N V E R S I O N P R O C */ /*------------------------------------------------------------------------------ Get candidate list of reconversion ------------------------------------------------------------------------------*/ HRESULT CFnReconversion::GetReconversionProc(ITfContext *pic, ITfRange *pRange, CCandidateListEx **ppCandList, BOOL fSelection) { CEditSession2 *pes; ESSTRUCT ess; HRESULT hr; if (!ppCandList) return E_INVALIDARG; *ppCandList = NULL; ESStructInit(&ess, ESCB_RECONV_GETRECONV); ess.pRange = pRange; ess.pv1 = this; ess.pv2 = ppCandList; ess.fBool = fSelection; hr = E_OUTOFMEMORY; if ((pes = new CEditSession2(pic, m_pKorImx, &ess, CKorIMX::_EditSessionCallback2))) { if (fSelection) pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr); else pes->Invoke(ES2_READONLY | ES2_SYNC, &hr); pes->Release(); } return hr; } //+--------------------------------------------------------------------------- // // CFnReconversion::ShowCandidateList // //---------------------------------------------------------------------------- HRESULT CFnReconversion::ShowCandidateList(ITfContext *pic, ITfRange *pRange, CCandidateListEx *pCandList) { CEditSession2 *pes; ESSTRUCT ess; HRESULT hr; hr = E_OUTOFMEMORY; ESStructInit(&ess, ESCB_RECONV_SHOWCAND); ess.pRange = pRange; ess.pv1 = this; ess.pCandList = pCandList; if ((pes = new CEditSession2(pic, m_pKorImx, &ess, CKorIMX::_EditSessionCallback2))) { pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr); pes->Release(); } return hr; } //+--------------------------------------------------------------------------- // // CFnReconversion::SetResult // (Static function) // //---------------------------------------------------------------------------- HRESULT CFnReconversion::SetResult(ITfContext *pic, ITfRange *pRange, CCandidateListEx *pCandList, CCandidateStringEx *pCand, TfCandidateResult imcr) { CEditSession2 *pes; ESSTRUCT ess; CFnReconversion *pReconv = (CFnReconversion *)(pCand->m_punk); ITfRange *pRangeTmp; HRESULT hr; hr = E_OUTOFMEMORY; if (SUCCEEDED(pRange->Clone(&pRangeTmp))) { if (imcr == CAND_FINALIZED) { ESStructInit(&ess, ESCB_FINALIZERECONVERSION); ess.pCandList = pCandList; ess.pCandStr = pCand; //pCandList->AddRef(); // be released in edit session callback //pCand->AddRef(); } else if (imcr == CAND_SELECTED) ESStructInit(&ess, ESCB_ONSELECTRECONVERSION); else if (imcr == CAND_CANCELED) ESStructInit(&ess, ESCB_ONCANCELRECONVERSION); // Save useful parameters ess.pv1 = pReconv; ess.lParam = pReconv->_pFuncPrv->_pime->GetTID(); ess.pRange = pRangeTmp; if ((pes = new CEditSession2(pic, pReconv->m_pKorImx, &ess, CKorIMX::_EditSessionCallback2))) { pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr); pes->Release(); } // Call back function must release pRangeTmp // pRangeTmp->Release(); } return S_OK; }