From fbdb66791da3291b740edf3c337032674e4377e8 Mon Sep 17 00:00:00 2001 From: nameoverflow Date: Thu, 22 Mar 2018 23:45:02 +0800 Subject: [PATCH] fix(composition): improve compositions and edit sessions (#146) * fix(composition): update compositions in edit session * fix(composition): insert commit text by set range text --- WeaselTSF/Composition.cpp | 125 ++++++++++++++++++++++--------------- WeaselTSF/EditSession.cpp | 69 ++++++++++---------- WeaselTSF/TextEditSink.cpp | 2 +- WeaselTSF/WeaselTSF.h | 2 +- 4 files changed, 112 insertions(+), 86 deletions(-) diff --git a/WeaselTSF/Composition.cpp b/WeaselTSF/Composition.cpp index cd60f7a86..10463809d 100644 --- a/WeaselTSF/Composition.cpp +++ b/WeaselTSF/Composition.cpp @@ -69,6 +69,16 @@ STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) void WeaselTSF::_StartComposition(ITfContext *pContext, BOOL fCUASWorkaroundEnabled) { + if (!_fCUASWorkaroundTested) + { + /* Test if we need to apply the workaround */ + _UpdateCompositionWindow(_pEditSessionContext); + } + else if (!fCUASWorkaroundEnabled) + { + /* Workaround not applied, update candidate window position at this point. */ + _UpdateCompositionWindow(_pEditSessionContext); + } CStartCompositionEditSession *pStartCompositionEditSession; if ((pStartCompositionEditSession = new CStartCompositionEditSession(this, pContext, fCUASWorkaroundEnabled)) != NULL) { @@ -82,8 +92,8 @@ void WeaselTSF::_StartComposition(ITfContext *pContext, BOOL fCUASWorkaroundEnab class CEndCompositionEditSession: public CEditSession { public: - CEndCompositionEditSession(WeaselTSF *pTextService, ITfContext *pContext, ITfComposition *pComposition) - : CEditSession(pTextService, pContext) + CEndCompositionEditSession(WeaselTSF *pTextService, ITfContext *pContext, ITfComposition *pComposition, bool clear = true) + : CEditSession(pTextService, pContext), _clear(clear) { _pComposition = pComposition; } @@ -93,13 +103,14 @@ class CEndCompositionEditSession: public CEditSession private: ITfComposition *_pComposition; + bool _clear; }; STDAPI CEndCompositionEditSession::DoEditSession(TfEditCookie ec) { /* Clear the dummy text we set before, if any. */ ITfRange *pCompositionRange; - if (_pComposition->GetRange(&pCompositionRange) == S_OK) + if (_clear && _pComposition->GetRange(&pCompositionRange) == S_OK) pCompositionRange->SetText(ec, 0, L"", 0); _pComposition->EndComposition(ec); @@ -107,12 +118,12 @@ STDAPI CEndCompositionEditSession::DoEditSession(TfEditCookie ec) return S_OK; } -void WeaselTSF::_EndComposition(ITfContext *pContext) +void WeaselTSF::_EndComposition(ITfContext *pContext, BOOL clear) { CEndCompositionEditSession *pEditSession; HRESULT hr; - if ((pEditSession = new CEndCompositionEditSession(this, pContext, _pComposition)) != NULL) + if ((pEditSession = new CEndCompositionEditSession(this, pContext, _pComposition, clear)) != NULL) { pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); pEditSession->Release(); @@ -265,57 +276,73 @@ BOOL WeaselTSF::_ShowInlinePreedit(ITfContext *pContext, const std::shared_ptrGetRange(&pRange)) != S_OK) + goto Exit; - auto context = std::make_shared(); + if ((hRet = pRange->SetText(ec, 0, _text.c_str(), _text.length())) != S_OK) + goto Exit; - weasel::ResponseParser parser(&commit, context.get(), &status, &config); + /* update the selection to an insertion point just past the inserted text. */ + pRange->Collapse(ec, TF_ANCHOR_END); - bool ok = m_client.GetResponseData(std::ref(parser)); + tfSelection.range = pRange; + tfSelection.style.ase = TF_AE_NONE; + tfSelection.style.fInterimChar = FALSE; - if (ok) + _pContext->SetSelection(ec, 1, &tfSelection); + +Exit: + if (pRange != NULL) + pRange->Release(); + + return hRet; + +} + +BOOL WeaselTSF::_InsertText(ITfContext *pContext, const std::wstring& text) +{ + CInsertTextEditSession *pEditSession; + HRESULT hr; + + if ((pEditSession = new CInsertTextEditSession(this, pContext, _pComposition, text)) != NULL) { - if (!commit.empty()) - { - // 修复顶字上屏的吞字问题: - // 顶字上屏(如五笔 4 码上屏时),当候选词数 > 1 时, - // 第 5 码输入时会将首选项顶屏。 - // 此时由于第五码的输入,composition 应是开启的,同时也要在输入处插入顶字。 - // 这里先关闭上一个字的 composition,然后为后续输入开启一个新 composition。 - // 有点 dirty 但是 it works ... - if (_IsComposing()) { - _EndComposition(pContext); - } - _InsertText(pContext, commit); - } - if (status.composing && !_IsComposing()) - { - 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 && _IsComposing()) - { - _EndComposition(pContext); - } - if (_IsComposing() && config.inline_preedit) - { - _ShowInlinePreedit(pContext, context); - } + pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); + pEditSession->Release(); } + + return TRUE; +} + +void WeaselTSF::_UpdateComposition(ITfContext *pContext) +{ + HRESULT hr; + + _pEditSessionContext = pContext; + + _pEditSessionContext->RequestEditSession(_tfClientId, this, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); + } /* Composition State */ diff --git a/WeaselTSF/EditSession.cpp b/WeaselTSF/EditSession.cpp index 6ac7c6f18..c481414df 100644 --- a/WeaselTSF/EditSession.cpp +++ b/WeaselTSF/EditSession.cpp @@ -1,46 +1,45 @@ #include "stdafx.h" #include "WeaselTSF.h" +#include "ResponseParser.h" STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) { - ITfInsertAtSelection *pInsertAtSelection; - ITfRange *pRange; - TF_SELECTION tfSelection; + // get commit string from server + std::wstring commit; + weasel::Status status; + weasel::Config config; - if (_pEditSessionContext->QueryInterface(IID_ITfInsertAtSelection, (LPVOID *) &pInsertAtSelection) != S_OK) - return E_FAIL; + auto context = std::make_shared(); - /* insert the text */ - if (pInsertAtSelection->InsertTextAtSelection(ec, 0, _editSessionText.c_str(), _editSessionText.length(), &pRange) != S_OK) - { - pInsertAtSelection->Release(); - return E_FAIL; - } - - /* update the selection to an insertion point just past the inserted text. */ - pRange->Collapse(ec, TF_ANCHOR_END); - - tfSelection.range = pRange; - tfSelection.style.ase = TF_AE_NONE; - tfSelection.style.fInterimChar = FALSE; + weasel::ResponseParser parser(&commit, context.get(), &status, &config); - _pEditSessionContext->SetSelection(ec, 1, &tfSelection); + bool ok = m_client.GetResponseData(std::ref(parser)); - pRange->Release(); - pInsertAtSelection->Release(); - - return S_OK; + if (ok) + { + if (!commit.empty()) + { + // For auto-selecting, commit and preedit can both exist. + // Commit and close the original composition first. + if (!_IsComposing()) { + _StartComposition(_pEditSessionContext, _fCUASWorkaroundEnabled && !config.inline_preedit); + } + _InsertText(_pEditSessionContext, commit); + _EndComposition(_pEditSessionContext, false); + } + if (status.composing && !_IsComposing()) + { + _StartComposition(_pEditSessionContext, _fCUASWorkaroundEnabled && !config.inline_preedit); + } + else if (!status.composing && _IsComposing()) + { + _EndComposition(_pEditSessionContext, true); + } + if (_IsComposing() && config.inline_preedit) + { + _ShowInlinePreedit(_pEditSessionContext, context); + } + } + return TRUE; } -BOOL WeaselTSF::_InsertText(ITfContext *pContext, const std::wstring& text) -{ - HRESULT hr; - - _pEditSessionContext = pContext; - _editSessionText = text; - - if (_pEditSessionContext->RequestEditSession(_tfClientId, this, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr) != S_OK || hr != S_OK) - return FALSE; - - return TRUE; -} \ No newline at end of file diff --git a/WeaselTSF/TextEditSink.cpp b/WeaselTSF/TextEditSink.cpp index 9d32cff96..f21fc9343 100644 --- a/WeaselTSF/TextEditSink.cpp +++ b/WeaselTSF/TextEditSink.cpp @@ -33,7 +33,7 @@ STDAPI WeaselTSF::OnEndEdit(ITfContext *pContext, TfEditCookie ecReadOnly, ITfEd if (_pComposition->GetRange(&pRangeComposition) == S_OK) { if (!IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) - _EndComposition(pContext); + _EndComposition(pContext, true); pRangeComposition->Release(); } } diff --git a/WeaselTSF/WeaselTSF.h b/WeaselTSF/WeaselTSF.h index 111d5187f..19698a23f 100644 --- a/WeaselTSF/WeaselTSF.h +++ b/WeaselTSF/WeaselTSF.h @@ -59,7 +59,7 @@ class WeaselTSF: /* Composition */ void _StartComposition(ITfContext *pContext, BOOL fCUASWorkaroundEnabled); - void _EndComposition(ITfContext *pContext); + void _EndComposition(ITfContext *pContext, BOOL clear); BOOL _ShowInlinePreedit(ITfContext *pContext, const std::shared_ptr context); void _UpdateComposition(ITfContext *pContext); BOOL _IsComposing();