From ce0d6ba9ae346dc9ef4d8a50d914dc1c0c5b0971 Mon Sep 17 00:00:00 2001 From: JustMe Date: Mon, 19 Oct 2026 23:36:54 +0800 Subject: [PATCH] Only forget the candidate the user picked from the menu The menu remembered the index of the candidate it was opened on. Cloud Pinyin results arrive asynchronously, so the list can be refreshed between the right click and the click on an action, and the index would then point at a different word. That word would have been forgotten and added to the block list. The word itself is stored when the menu opens and compared when an action is clicked, nothing is done if it is no longer the same. Co-Authored-By: Claude Sonnet 5.5 --- src/inputwindow.cpp | 11 +++++++++-- src/inputwindow.h | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/inputwindow.cpp b/src/inputwindow.cpp index c871956..8a0ea4f 100644 --- a/src/inputwindow.cpp +++ b/src/inputwindow.cpp @@ -977,6 +977,7 @@ void InputWindow::click(int x, int y) { int actionId = -1; std::string actionText; const auto candidateIndex = menuCandidate_; + const std::string candidateText = menuCandidateText_; for (size_t i = 0; i < menuRegions_.size(); i++) { if (menuRegions_[i].contains(x, y)) { actionId = menuActions_[i].id(); @@ -989,11 +990,15 @@ void InputWindow::click(int x, int y) { auto *actionable = candidateList->toActionable(); const auto *candidate = nthCandidateIgnorePlaceholder(*candidateList, candidateIndex); - if (actionable && candidate) { + // The list may have been refreshed since the menu was opened. Only + // act when the candidate is still the one the user picked, a + // different word must never be forgotten or blocked. + if (actionable && candidate && + candidate->text().toString() == candidateText) { // Block before the engine refreshes its list so the refreshed // list is already filtered. if (isForgetAction(actionText)) { - parent_->blockWord(candidate->text().toString()); + parent_->blockWord(candidateText); } actionable->triggerAction(*candidate, actionId); } @@ -1065,6 +1070,7 @@ void InputWindow::rightClick(int x, int y) { } menuActions_ = std::move(actions); menuCandidate_ = idx; + menuCandidateText_ = candidate->text().toString(); menuHover_ = -1; menuOpen_ = true; inputContext->updateUserInterface(UserInterfaceComponent::InputPanel); @@ -1075,6 +1081,7 @@ void InputWindow::rightClick(int x, int y) { void InputWindow::closeMenu() { menuOpen_ = false; menuCandidate_ = -1; + menuCandidateText_.clear(); menuHover_ = -1; menuActions_.clear(); menuRegions_.clear(); diff --git a/src/inputwindow.h b/src/inputwindow.h index 692000b..46cdfe7 100644 --- a/src/inputwindow.h +++ b/src/inputwindow.h @@ -198,6 +198,10 @@ protected: std::pair menuSize(); bool menuOpen_ = false; int menuCandidate_ = -1; + // The word the menu was opened on. The list can be refreshed between the + // right click and the click on an action, the index alone would then point + // at a different word. + std::string menuCandidateText_; int menuHover_ = -1; std::vector menuActions_; std::vector menuRegions_;