Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion WeaselTSF/CandidateList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ HRESULT CCandidateList::_UpdateUIElement() {
}

void CCandidateList::StartUI() {
if (_uiStarted)
return;

com_ptr<ITfThreadMgr> pThreadMgr = _tsf->_GetThreadMgr();
if (!pThreadMgr) {
return;
Expand All @@ -302,7 +305,9 @@ void CCandidateList::StartUI() {
bool* const next, bool* const scroll_next) {
_tsf->HandleUICallback(sel, hov, next, scroll_next);
});
pUIElementMgr->BeginUIElement(this, &_pbShow, &uiid);
if (FAILED(pUIElementMgr->BeginUIElement(this, &_pbShow, &uiid)))
return;
_uiStarted = true;
// pUIElementMgr->UpdateUIElement(uiid);
if (_pbShow) {
_ui->style() = _style;
Expand All @@ -311,6 +316,9 @@ void CCandidateList::StartUI() {
}

void CCandidateList::EndUI() {
if (!_uiStarted)
return;

com_ptr<ITfThreadMgr> pThreadMgr = _tsf->_GetThreadMgr();
if (pThreadMgr) {
com_ptr<ITfUIElementMgr> emgr;
Expand All @@ -320,6 +328,7 @@ void CCandidateList::EndUI() {
if (emgr != NULL)
emgr->EndUIElement(uiid);
}
_uiStarted = false;
_DisposeUIWindow();
}

Expand Down
1 change: 1 addition & 0 deletions WeaselTSF/CandidateList.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class CCandidateList : public ITfIntegratableCandidateListUIElement,
STYLE_ACTIVE_SELECTION;

BOOL _pbShow;
bool _uiStarted = false;
weasel::UIStyle _style;

com_ptr<ITfContext> _pContextDocument;
Expand Down
68 changes: 41 additions & 27 deletions WeaselTSF/Composition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ class CStartCompositionEditSession : public CEditSession {
public:
CStartCompositionEditSession(com_ptr<WeaselTSF> pTextService,
com_ptr<ITfContext> pContext,
BOOL fCUASWorkaroundEnabled,
BOOL inlinePreeditEnabled)
: CEditSession(pTextService, pContext),
_inlinePreeditEnabled(inlinePreeditEnabled) {
BOOL fCUASWorkaroundEnabled)
: CEditSession(pTextService, pContext) {
_fCUASWorkaroundEnabled = fCUASWorkaroundEnabled;
}

Expand All @@ -21,7 +19,6 @@ class CStartCompositionEditSession : public CEditSession {

private:
BOOL _fCUASWorkaroundEnabled;
BOOL _inlinePreeditEnabled;
};

STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) {
Expand All @@ -45,26 +42,18 @@ STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) {
(pComposition != NULL)) {
_pTextService->_SetComposition(pComposition);

/* WORKAROUND:
* CUAS does not provide a correct GetTextExt() position unless the
* composition is filled with characters. So we insert a zero width space
* here. The workaround is only needed when inline preedit is not enabled.
* See https://github.com/rime/weasel/pull/883#issuecomment-1567625762
*/
if (!_inlinePreeditEnabled) {
pRangeComposition->SetText(ec, TF_ST_CORRECTION, L" ", 1);
}

/* set selection */
TF_SELECTION tfSelection;
if (_inlinePreeditEnabled)
pRangeComposition->Collapse(ec, TF_ANCHOR_END);
else
pRangeComposition->Collapse(ec, TF_ANCHOR_START);
pRangeComposition->Collapse(ec, TF_ANCHOR_END);
tfSelection.range = pRangeComposition;
tfSelection.style.ase = TF_AE_NONE;
tfSelection.style.fInterimChar = FALSE;
_pContext->SetSelection(ec, 1, &tfSelection);

// The old composition's range is still visible while its asynchronous
// end session is pending. Position only after the new composition has
// actually been created, not from the response handler's stale range.
_pTextService->_UpdateCompositionWindow(_pContext);
}

return hr;
Expand All @@ -73,8 +62,8 @@ STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) {
void WeaselTSF::_StartComposition(com_ptr<ITfContext> pContext,
BOOL fCUASWorkaroundEnabled) {
com_ptr<CStartCompositionEditSession> pStartCompositionEditSession;
pStartCompositionEditSession.Attach(new CStartCompositionEditSession(
this, pContext, fCUASWorkaroundEnabled, _cand->style().inline_preedit));
pStartCompositionEditSession.Attach(
new CStartCompositionEditSession(this, pContext, fCUASWorkaroundEnabled));
_cand->StartUI();
if (pStartCompositionEditSession != nullptr) {
HRESULT hr;
Expand Down Expand Up @@ -116,19 +105,28 @@ STDAPI CEndCompositionEditSession::DoEditSession(TfEditCookie ec) {
if (_clear && _pComposition->GetRange(&pCompositionRange) == S_OK)
pCompositionRange->SetText(ec, 0, L"", 0);

_pComposition->EndComposition(ec);
if (_pTextService) // if _pTextService released, skip _FinalizeComposition
// Drop ownership before EndComposition(). Some applications notify
// OnCompositionTerminated synchronously while the old composition ends.
// Keeping it as the current composition makes that normal notification
// look like an external abort and can clear a new Rime composition during
// auto-commit.
if (_pTextService && _pTextService->_IsCurrentComposition(_pComposition))
_pTextService->_FinalizeComposition();
_pComposition->EndComposition(ec);
return S_OK;
}

void WeaselTSF::_EndComposition(com_ptr<ITfContext> pContext, BOOL clear) {
void WeaselTSF::_EndComposition(com_ptr<ITfContext> pContext,
BOOL clear,
BOOL endUI) {
CEndCompositionEditSession* pEditSession;
HRESULT hr;
com_ptr<ITfComposition> pComposition = _pComposition;

_cand->EndUI();
if (endUI)
_cand->EndUI();
if ((pEditSession = new CEndCompositionEditSession(
this, pContext, _pComposition, clear)) != NULL) {
this, pContext, pComposition, clear)) != NULL) {
pContext->RequestEditSession(_tfClientId, pEditSession,
TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr);
pEditSession->Release();
Expand Down Expand Up @@ -389,7 +387,6 @@ void WeaselTSF::_UpdateComposition(com_ptr<ITfContext> pContext) {
_pEditSessionContext->RequestEditSession(
_tfClientId, this, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr);
_async_edit = !!(hr == TF_S_ASYNC);
_UpdateCompositionWindow(pContext);
}

/* Composition State */
Expand All @@ -399,6 +396,19 @@ STDAPI WeaselTSF::OnCompositionTerminated(TfEditCookie ecWrite,
// This will be called when an edit session ended up with an empty composition
// string, Even if it is closed normally. Silly M$.

// EndComposition() may generate this callback for the composition we just
// closed. Only an active, matching composition is an external termination.
if (!_IsCurrentComposition(pComposition))
return S_OK;

// A host may terminate the empty TSF composition used for a non-inline
// preedit. Keep Rime's composing state; the next key will create a fresh
// TSF composition. Only an inactive Rime session should be aborted here.
if (_status.composing) {
_FinalizeComposition();
return S_OK;
}

_AbortComposition();
return S_OK;
}
Expand All @@ -423,3 +433,7 @@ void WeaselTSF::_SetComposition(com_ptr<ITfComposition> pComposition) {
BOOL WeaselTSF::_IsComposing() {
return _pComposition != NULL;
}

BOOL WeaselTSF::_IsCurrentComposition(ITfComposition* pComposition) {
return _pComposition != nullptr && _pComposition == pComposition;
}
22 changes: 18 additions & 4 deletions WeaselTSF/EditSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,30 @@ STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) {

_UpdateLanguageBar(_status);

bool compositionEnded = false;
if (ok) {
compositionEnded = false;
if (!commit.empty()) {
// For auto-selecting, commit and preedit can both exist.
// Commit and close the original composition first.
// Commit the old TSF composition. If Rime immediately has a new
// preedit (top-word input), _EndComposition() drops the local pointer
// synchronously, so the following state check starts a new TSF
// composition instead of observing the old one.
if (!_IsComposing()) {
_StartComposition(_pEditSessionContext,
_fCUASWorkaroundEnabled && !config.inline_preedit);
}
_InsertText(_pEditSessionContext, commit);
_EndComposition(_pEditSessionContext, false);
// Keep the candidate UI alive while the replacement composition is
// being created; otherwise the key-down path destroys the old window
// and the new one cannot be positioned until key-up.
_EndComposition(_pEditSessionContext, false, !_status.composing);
compositionEnded = true;
_committed = TRUE;
} else {
_committed = FALSE;
}
if (_status.composing && !_IsComposing()) {
if (_status.composing && (compositionEnded || !_IsComposing())) {
_StartComposition(_pEditSessionContext,
_fCUASWorkaroundEnabled && !config.inline_preedit);
} else if (!_status.composing && _IsComposing()) {
Expand All @@ -38,9 +47,14 @@ STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) {
if (_IsComposing() && config.inline_preedit) {
_ShowInlinePreedit(_pEditSessionContext, context);
}
_UpdateCompositionWindow(_pEditSessionContext);
}

if (ok && !compositionEnded)
_UpdateCompositionWindow(_pEditSessionContext);
// Keep the existing candidate window alive during top-word input, but
// publish the new candidates in this key-down edit session. Positioning is
// still updated by the queued read session after the new composition is
// created.
_UpdateUI(*context, _status);

return TRUE;
Expand Down
5 changes: 4 additions & 1 deletion WeaselTSF/WeaselTSF.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,14 @@ class WeaselTSF : public ITfTextInputProcessorEx,
/* Composition */
void _StartComposition(com_ptr<ITfContext> pContext,
BOOL fCUASWorkaroundEnabled);
void _EndComposition(com_ptr<ITfContext> pContext, BOOL clear);
void _EndComposition(com_ptr<ITfContext> pContext,
BOOL clear,
BOOL endUI = TRUE);
BOOL _ShowInlinePreedit(com_ptr<ITfContext> pContext,
const std::shared_ptr<weasel::Context> context);
void _UpdateComposition(com_ptr<ITfContext> pContext);
BOOL _IsComposing();
BOOL _IsCurrentComposition(ITfComposition* pComposition);
void _SetComposition(com_ptr<ITfComposition> pComposition);
void _SetCompositionPosition(const RECT& rc);
BOOL _UpdateCompositionWindow(com_ptr<ITfContext> pContext);
Expand Down
4 changes: 1 addition & 3 deletions output/data/weasel.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Weasel settings
# encoding: utf-8

config_version: "0.22"
config_version: "0.23"

app_options:
cmd.exe:
ascii_mode: true
conhost.exe:
ascii_mode: true
firefox.exe:
inline_preedit: true # workaround for #946

show_notifications: true
# how long a period notifications shows
Expand Down
Loading