From 8cdc0ec68e73acdac5f3d2fe4ec50f325711bcd1 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Fri, 27 Mar 2026 22:45:25 +0700 Subject: [PATCH 01/10] feat: use deleteSurroundingText for app support --- src/lotus-engine.h | 14 ++++----- src/lotus-state.cpp | 74 +++++++++++++++++++++++++++++++-------------- src/lotus-state.h | 2 +- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/lotus-engine.h b/src/lotus-engine.h index 0b617e3..c73521e 100644 --- a/src/lotus-engine.h +++ b/src/lotus-engine.h @@ -177,6 +177,13 @@ namespace fcitx { */ uintptr_t macroTable() const; + /** + * @brief Get name of current program + * @param ic Current input context. + * @return Name of current program + */ + std::string getProgramName(InputContext* ic); + /** * @brief Gets the emoji loader. * @return Reference to emoji loader instance. @@ -318,13 +325,6 @@ namespace fcitx { * @param ic Current input context. */ static void setMode(LotusMode mode, InputContext* ic); - - /** - * @brief Get name of current program - * @param ic Current input context. - * @return Name of current program - */ - static std::string getProgramName(InputContext* ic); }; /** diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 15cddb2..62a83cf 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -478,24 +478,49 @@ namespace fcitx { return false; } - void LotusState::performReplacement(const std::string& deletedPart, const std::string& addedPart) { + bool LotusState::performReplacement(const std::string& deletedPart, const std::string& addedPart) { LOTUS_INFO("Perform replacement: " + deletedPart + " -> " + addedPart); //NOLINT - int my_id = ++current_thread_id_; - current_backspace_count_ = 0; - pending_commit_string_ = addedPart; - const auto& surrounding = ic_->surroundingText(); - // Enable Autofill detection for all frontends (Wayland/IBus). - // This fixes the "toôi" duplication bug in Chromium-based search bars. - // The isAutofillCertain function has been optimized to differentiate - // between browser autofill and AI ghost text. - int autofillOffset = isAutofillCertain(surrounding) ? 1 : 0; - expected_backspaces_ = static_cast(utf8::length(deletedPart)) + 1 + autofillOffset; - replacement_thread_id_.store(my_id, std::memory_order_release); - replacement_start_ms_.store(now_ms(), std::memory_order_release); - is_deleting_.store(true, std::memory_order_release); - monitor_cv.notify_one(); - send_backspace_uinput(expected_backspaces_); - LOTUS_INFO("Send " + std::to_string(expected_backspaces_) + " backspaces"); + int my_id = ++current_thread_id_; + current_backspace_count_ = 0; + pending_commit_string_ = addedPart; + const auto& surrounding = ic_->surroundingText(); + int autofillOffset = isAutofillCertain(surrounding) ? 1 : 0; + expected_backspaces_ = static_cast(utf8::length(deletedPart)) + 1 + autofillOffset; + // Use deleteSurroundingText for apps that support it for smooth typing + if (engine_->getProgramName(ic_) == "soffice" && // Lmfao, only this work :> + surrounding.isValid() && ic_->capabilityFlags().test(CapabilityFlag::SurroundingText) && + (surrounding.text()).back() != '\n' // firefox and discord insert '\n' into surrounding cause bug + && !(autofillOffset) // TODO: Guard, remove this when bug of surrounding is fixes + ) { + auto cur = static_cast(surrounding.cursor()); + const int bsCount = static_cast(utf8::length(deletedPart)); + if (autofillOffset) { + int surrLen = static_cast(utf8::length(surrounding.text())); + int realLen = static_cast(cur); + int suggestionLen = surrLen - realLen; + // delete suggestion tail + if (suggestionLen > 0) + ic_->deleteSurroundingText(0, 1); + // delete addedPart + if (bsCount > 0) + ic_->deleteSurroundingText(-bsCount, static_cast(bsCount)); + } else { + if (bsCount > 0) { + ic_->deleteSurroundingText(-bsCount, static_cast(bsCount)); + } + } + ic_->commitString(addedPart); + //clearAllBuffers(); + return true; + } else { + replacement_thread_id_.store(my_id, std::memory_order_release); + replacement_start_ms_.store(now_ms(), std::memory_order_release); + is_deleting_.store(true, std::memory_order_release); + monitor_cv.notify_one(); + send_backspace_uinput(expected_backspaces_); + LOTUS_INFO("Send " + std::to_string(expected_backspaces_) + " backspaces"); + } + return false; } bool LotusState::checkForwardSpecialKey(KeyEvent& keyEvent, KeySym& currentSym) { @@ -600,19 +625,20 @@ namespace fcitx { compareAndSplitStrings(oldPreBuffer_, commitStr, commonPrefix, deletedPart, addedPart); if (!deletedPart.empty()) { - performReplacement(deletedPart, addedPart); keyEvent.filterAndAccept(); + if (performReplacement(deletedPart, addedPart)) + keyEvent.forward(); } else { bool wasAutoCapitalized = (currentSym != keyEvent.rawKey().sym()); if (!addedPart.empty() && (keyUtf8 != addedPart || wasAutoCapitalized)) { // Prevent auto-capitalized character replacement from stripping out Vietnamese chars if (addedPart.size() > 1 && addedPart.back() == ' ') { // Stripping the trigger key (space) from addedPart -#if __cplusplus >= 202002L + #if __cplusplus >= 202002L addedPart.resize(addedPart.size() - 1); -#else + #else addedPart = addedPart.substr(0, addedPart.size() - 1); -#endif + #endif } ic_->commitString(addedPart); LOTUS_INFO("Commit: " + addedPart); @@ -629,7 +655,7 @@ namespace fcitx { return; } - if (!processed) { + if (!processed) { if (checkEmptyPreedit) { UniqueCPtr preeditC(EnginePullPreedit(lotusEngine_.handle())); if (!preeditC || (*preeditC.get() == 0)) { @@ -689,7 +715,8 @@ namespace fcitx { if (!wa_chromium_flag) keyEvent.filterAndAccept(); - performReplacement(deletedPart, addedPart); + if (performReplacement(deletedPart, addedPart)) + keyEvent.forward(); oldPreBuffer_ = preeditStr; } } @@ -1199,6 +1226,7 @@ namespace fcitx { } } performReplacement(deletedPart, addedPart); + oldPreBuffer_ = preeditStr; return; } diff --git a/src/lotus-state.h b/src/lotus-state.h index cbef003..91d784f 100644 --- a/src/lotus-state.h +++ b/src/lotus-state.h @@ -171,7 +171,7 @@ namespace fcitx { * @param deletedPart Text to delete. * @param addedPart Text to insert. */ - void performReplacement(const std::string& deletedPart, const std::string& addedPart); + bool performReplacement(const std::string& deletedPart, const std::string& addedPart); /** * @brief Handles the double space to period replacement. From 2c4ba66e619d7ac613a2857011a6c76e9c44419f Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Sun, 29 Mar 2026 02:21:07 +0700 Subject: [PATCH 02/10] personal config --- src/ack-apps.h | 6 ++++++ src/lotus-engine.cpp | 8 ++++++++ src/lotus-state.cpp | 4 ++-- src/lotus-state.h | 1 + 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ack-apps.h b/src/ack-apps.h index 06ca67b..e15a522 100644 --- a/src/ack-apps.h +++ b/src/ack-apps.h @@ -21,3 +21,9 @@ * Chromium-based browsers that need special handling for text replacement. */ static std::vector ack_apps = {"chrome", "chromium", "brave", "edge", "vivaldi", "opera", "coccoc", "cromite", "helium", "thorium", "slimjet", "yandex"}; + +/** + * @brief List of application names have goood support surrowding text + * + */ +static std::vector surrtp_apps = {"mullvad", "soffice"}; diff --git a/src/lotus-engine.cpp b/src/lotus-engine.cpp index 30ab257..0eeff34 100644 --- a/src/lotus-engine.cpp +++ b/src/lotus-engine.cpp @@ -376,6 +376,8 @@ namespace fcitx { // TODO: Properly fixes instead ugly WA state->wa_chromium_flag = false; + state->wa_flag = false; + state->surrtp = false; state->waitAck_ = false; if (*config_.fixUinputWithAck) { if (targetMode == LotusMode::Uinput || targetMode == LotusMode::UinputHC || targetMode == LotusMode::Smooth) { @@ -394,6 +396,12 @@ namespace fcitx { break; } } + for (const auto& _App : surrtp_app) { + if (appName.find(_App) != std::string::npos) { + state->surrtp = true; + break; + } + } } } if (event.type() == EventType::InputContextFocusIn && is_dbus && !surrvalid) { diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 62a83cf..675c5b0 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -487,8 +487,8 @@ namespace fcitx { int autofillOffset = isAutofillCertain(surrounding) ? 1 : 0; expected_backspaces_ = static_cast(utf8::length(deletedPart)) + 1 + autofillOffset; // Use deleteSurroundingText for apps that support it for smooth typing - if (engine_->getProgramName(ic_) == "soffice" && // Lmfao, only this work :> - surrounding.isValid() && ic_->capabilityFlags().test(CapabilityFlag::SurroundingText) && + if (surrtp // Lmfao, only this work :> + && surrounding.isValid() && ic_->capabilityFlags().test(CapabilityFlag::SurroundingText) && (surrounding.text()).back() != '\n' // firefox and discord insert '\n' into surrounding cause bug && !(autofillOffset) // TODO: Guard, remove this when bug of surrounding is fixes ) { diff --git a/src/lotus-state.h b/src/lotus-state.h index 91d784f..930bd7b 100644 --- a/src/lotus-state.h +++ b/src/lotus-state.h @@ -107,6 +107,7 @@ namespace fcitx { bool isPrevPunctuation_ = false; int64_t lastDeactivateTime_ = 0; bool wa_chromium_flag = false; + bool surrtp = false; /** * @brief Connects to the uinput server. From ee7809fbd58c86b35b994702f2ccd5b7fb9412b5 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Sun, 29 Mar 2026 02:22:10 +0700 Subject: [PATCH 03/10] typo --- src/lotus-engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lotus-engine.cpp b/src/lotus-engine.cpp index 0eeff34..3211413 100644 --- a/src/lotus-engine.cpp +++ b/src/lotus-engine.cpp @@ -396,7 +396,7 @@ namespace fcitx { break; } } - for (const auto& _App : surrtp_app) { + for (const auto& _App : surrtp_apps) { if (appName.find(_App) != std::string::npos) { state->surrtp = true; break; From 6b12a7eb045a1e64dcc801e6f0bd2dc6f7d57642 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Sun, 29 Mar 2026 04:03:25 +0700 Subject: [PATCH 04/10] fix typo false :v, and reomve some func --- src/{ack-apps.h => app_quirks.h} | 9 +++++---- src/lotus-engine.cpp | 5 ++--- src/lotus-state.cpp | 26 ++++++++++++-------------- 3 files changed, 19 insertions(+), 21 deletions(-) rename src/{ack-apps.h => app_quirks.h} (59%) diff --git a/src/ack-apps.h b/src/app_quirks.h similarity index 59% rename from src/ack-apps.h rename to src/app_quirks.h index e15a522..30d6ac1 100644 --- a/src/ack-apps.h +++ b/src/app_quirks.h @@ -6,24 +6,25 @@ */ /** - * @file ack-apps.h + * @file app_quirks.h * @brief List of applications requiring acknowledgment workaround. * * These browsers need special handling for uinput mode to work correctly. */ #include -#include +#include /** * @brief List of application names requiring ACK workaround. * * Chromium-based browsers that need special handling for text replacement. */ -static std::vector ack_apps = {"chrome", "chromium", "brave", "edge", "vivaldi", "opera", "coccoc", "cromite", "helium", "thorium", "slimjet", "yandex"}; +inline constexpr std::array ack_apps = {"chrome", "chromium", "brave", "edge", "vivaldi", "opera", + "coccoc", "cromite", "helium", "thorium", "slimjet", "yandex"}; /** * @brief List of application names have goood support surrowding text * */ -static std::vector surrtp_apps = {"mullvad", "soffice"}; +inline constexpr std::array surrtp_apps = {"soffice"}; diff --git a/src/lotus-engine.cpp b/src/lotus-engine.cpp index 3211413..af548f4 100644 --- a/src/lotus-engine.cpp +++ b/src/lotus-engine.cpp @@ -12,7 +12,7 @@ #include "lotus-candidates.h" #include "lotus-monitor.h" #include "lotus-utils.h" -#include "ack-apps.h" +#include "app_quirks.h" #include #include #ifndef DISABLE_VERSION_ACTION @@ -390,7 +390,7 @@ namespace fcitx { if (appName.find(ackApp) != std::string::npos) { if (is_dbus) { state->waitAck_ = true; - LOTUS_INFO(ackApp + " detected, waiting for ack"); + LOTUS_INFO(std::string(ackApp) + " detected, waiting for ack"); } state->wa_chromium_flag = true; break; @@ -623,7 +623,6 @@ namespace fcitx { auto* state = ic->propertyFor(&factory_); const bool surrvalid = ic->surroundingText().isValid(); const bool is_dbus = getFrontendName(ic) == "dbus"; - state->lastDeactivateTime_ = now_ms(); if (realMode == LotusMode::Preedit && event.type() != EventType::InputContextFocusOut) { state->commitBuffer(); } else { diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 675c5b0..c977146 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -455,9 +455,9 @@ namespace fcitx { if (surr.isValid() && surr.cursor() == realtextLen.load(std::memory_order_acquire)) { LOTUS_INFO("Skip retry"); } else { - // Retry x3 (2 ms each), khi can (chromium,electron,...) - for (int retry = 0; retry < 3; ++retry) { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); + // Retry x5 (1 ms each), khi can (chromium,electron,...) + for (int retry = 0; retry < 5; ++retry) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); const auto& surr2 = ic_->surroundingText(); if (surr2.isValid() && surr2.cursor() == realtextLen.load(std::memory_order_acquire)) { break; @@ -471,8 +471,8 @@ namespace fcitx { pending_commit_string_ = ""; event.filterAndAccept(); // Filter out the final trigger backspace. - if (getFrontendName(ic_) == "dbus" && !ic_->surroundingText().isValid()) - replayBufferedKeys(); // Does we need drop this? + //if (getFrontendName(ic_) == "dbus" && !ic_->surroundingText().isValid()) + // replayBufferedKeys(); // Does we need drop this? return true; } return false; @@ -930,8 +930,8 @@ namespace fcitx { } replacement_thread_id_.store(0, std::memory_order_release); replacement_start_ms_.store(0, std::memory_order_release); - if (getFrontendName(ic_) == "dbus" && !ic_->surroundingText().isValid()) - replayBufferedKeys(); // Does we need drop this? + //if (getFrontendName(ic_) == "dbus" && !ic_->surroundingText().isValid()) + // replayBufferedKeys(); // Does we need drop this? } KeySym currentSym = keyEvent.rawKey().sym(); if (*engine_->config().autoCapitalizeAfterPunctuation && realMode != LotusMode::Off) { @@ -1123,11 +1123,9 @@ namespace fcitx { } oldPreBuffer_.clear(); hasHistory_ = false; - if (!is_deleting_.load(std::memory_order_acquire)) { - expected_backspaces_ = 0; - current_backspace_count_ = 0; - pending_commit_string_.clear(); - } + expected_backspaces_ = 0; + current_backspace_count_ = 0; + pending_commit_string_.clear(); emojiBuffer_.clear(); emojiCandidates_.clear(); buffered_keys_.clear(); @@ -1140,14 +1138,13 @@ namespace fcitx { bool LotusState::isEmptyHistory() const { return !hasHistory_; } - + /* void LotusState::replayBufferedKeys() { LOTUS_INFO("Starting replay buffered keys"); if (buffered_keys_.empty()) { return; } auto keys = std::move(buffered_keys_); - buffered_keys_.clear(); for (size_t i = 0; i < keys.size(); ++i) { auto sym = static_cast(keys[i].sym); uint32_t state = keys[i].state; @@ -1234,4 +1231,5 @@ namespace fcitx { } LOTUS_INFO("Replay buffered keys done"); } +*/ } // namespace fcitx From 8292c10b07349f763f71f62d93009749458ae876 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Sun, 29 Mar 2026 22:37:11 +0700 Subject: [PATCH 05/10] only need retry for chromium,electron ack --- src/lotus-engine.cpp | 8 ++++---- src/lotus-state.cpp | 24 ++++++++++++++++++------ src/lotus-state.h | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/lotus-engine.cpp b/src/lotus-engine.cpp index af548f4..025a129 100644 --- a/src/lotus-engine.cpp +++ b/src/lotus-engine.cpp @@ -619,10 +619,10 @@ namespace fcitx { } void LotusEngine::deactivate(const InputMethodEntry& /*entry*/, InputContextEvent& event) { - auto* ic = event.inputContext(); - auto* state = ic->propertyFor(&factory_); - const bool surrvalid = ic->surroundingText().isValid(); - const bool is_dbus = getFrontendName(ic) == "dbus"; + auto* ic = event.inputContext(); + auto* state = ic->propertyFor(&factory_); + const bool surrvalid = ic->surroundingText().isValid(); + const bool is_dbus = getFrontendName(ic) == "dbus"; if (realMode == LotusMode::Preedit && event.type() != EventType::InputContextFocusOut) { state->commitBuffer(); } else { diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index c977146..8ef8a2e 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -138,6 +138,16 @@ namespace fcitx { } } + void LotusState::send_backspace_forward(int count) const { + if (count <= 0) + return; + for (int i = 0; i < count - 1; ++i) { + ic_->forwardKey(Key(FcitxKey_BackSpace, KeyState::NoState), false); + ic_->forwardKey(Key(FcitxKey_BackSpace, KeyState::NoState), true); + } + send_backspace_uinput(0); // trigger 1bs to make all bs prev release + } + bool LotusState::isAutofillCertain(const SurroundingText& s) { if (!s.isValid() || oldPreBuffer_.empty()) { return false; @@ -456,13 +466,14 @@ namespace fcitx { LOTUS_INFO("Skip retry"); } else { // Retry x5 (1 ms each), khi can (chromium,electron,...) - for (int retry = 0; retry < 5; ++retry) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - const auto& surr2 = ic_->surroundingText(); - if (surr2.isValid() && surr2.cursor() == realtextLen.load(std::memory_order_acquire)) { - break; + if (waitAck_) + for (int retry = 0; retry < 5; ++retry) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + const auto& surr2 = ic_->surroundingText(); + if (surr2.isValid() && surr2.cursor() == realtextLen.load(std::memory_order_acquire)) { + break; + } } - } } ic_->commitString(pending_commit_string_); LOTUS_INFO("Commit: " + pending_commit_string_); @@ -517,6 +528,7 @@ namespace fcitx { replacement_start_ms_.store(now_ms(), std::memory_order_release); is_deleting_.store(true, std::memory_order_release); monitor_cv.notify_one(); + //send_backspace_forward(expected_backspaces_ - 1); send_backspace_uinput(expected_backspaces_); LOTUS_INFO("Send " + std::to_string(expected_backspaces_) + " backspaces"); } diff --git a/src/lotus-state.h b/src/lotus-state.h index 930bd7b..fd4e03b 100644 --- a/src/lotus-state.h +++ b/src/lotus-state.h @@ -126,7 +126,7 @@ namespace fcitx { * @param count Number of backspaces to send. */ void send_backspace_uinput(int count) const; - + void send_backspace_forward(int count) const; /** * @brief Checks if autofill is certain for surrounding text. * @param s The surrounding text. From f9b80b8091f47046a2309051d0718537e56405fc Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Mon, 30 Mar 2026 19:22:04 +0700 Subject: [PATCH 06/10] demorgan --- src/lotus-state.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 8ef8a2e..84b1243 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -461,12 +461,10 @@ namespace fcitx { replacement_thread_id_.store(0, std::memory_order_release); std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); // Validate surr cursor pos should match realtextLen after all BS applied - const auto& surr = ic_->surroundingText(); - if (surr.isValid() && surr.cursor() == realtextLen.load(std::memory_order_acquire)) { - LOTUS_INFO("Skip retry"); - } else { - // Retry x5 (1 ms each), khi can (chromium,electron,...) - if (waitAck_) + if (waitAck_) { + const auto& surr = ic_->surroundingText(); + if (!surr.isValid() || surr.cursor() != realtextLen.load(std::memory_order_acquire)) { + // Retry x5 (1 ms each), khi can (chromium,electron,...) for (int retry = 0; retry < 5; ++retry) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); const auto& surr2 = ic_->surroundingText(); @@ -474,6 +472,7 @@ namespace fcitx { break; } } + } } ic_->commitString(pending_commit_string_); LOTUS_INFO("Commit: " + pending_commit_string_); From 531b1168eefaddb17a0fbb0b3a838c4918185f86 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Mon, 30 Mar 2026 19:30:04 +0700 Subject: [PATCH 07/10] e --- src/lotus-state.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 84b1243..f027618 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -645,11 +645,11 @@ namespace fcitx { // Prevent auto-capitalized character replacement from stripping out Vietnamese chars if (addedPart.size() > 1 && addedPart.back() == ' ') { // Stripping the trigger key (space) from addedPart - #if __cplusplus >= 202002L +#if __cplusplus >= 202002L addedPart.resize(addedPart.size() - 1); - #else +#else addedPart = addedPart.substr(0, addedPart.size() - 1); - #endif +#endif } ic_->commitString(addedPart); LOTUS_INFO("Commit: " + addedPart); @@ -666,7 +666,7 @@ namespace fcitx { return; } - if (!processed) { + if (!processed) { if (checkEmptyPreedit) { UniqueCPtr preeditC(EnginePullPreedit(lotusEngine_.handle())); if (!preeditC || (*preeditC.get() == 0)) { @@ -1133,7 +1133,7 @@ namespace fcitx { return; } oldPreBuffer_.clear(); - hasHistory_ = false; + hasHistory_ = false; expected_backspaces_ = 0; current_backspace_count_ = 0; pending_commit_string_.clear(); From 87d6267d1dcf7a5af4ccb4ed54e810c6a789ca4f Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Mon, 30 Mar 2026 20:22:27 +0700 Subject: [PATCH 08/10] O(1) --- bamboo/bamboo-c.go | 3 ++- bamboo/bamboo-core | 2 +- bamboo/fcitxbambooengine.go | 16 ++++++++++++++-- src/lotus-engine.h | 14 +++++++------- src/lotus-state.cpp | 15 +++++++++++++++ 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/bamboo/bamboo-c.go b/bamboo/bamboo-c.go index 1965f7b..2e75d4a 100644 --- a/bamboo/bamboo-c.go +++ b/bamboo/bamboo-c.go @@ -158,6 +158,7 @@ func NewEngine(name *C.cchar, dictHandle uintptr, tableHandle uintptr) uintptr { timeFormat: "%H:%M", dateFormat: "%d/%m/%Y", } + engine.rebuildAppendingKeySet() return uintptr(cgo.NewHandle(engine)) } @@ -201,7 +202,7 @@ func NewCustomEngine(definition **C.char, dictHandle uintptr, tableHandle uintpt timeFormat: "%H:%M", dateFormat: "%d/%m/%Y", } - + engine.rebuildAppendingKeySet() return uintptr(cgo.NewHandle(engine)) } diff --git a/bamboo/bamboo-core b/bamboo/bamboo-core index de3d5b0..5f1974a 160000 --- a/bamboo/bamboo-core +++ b/bamboo/bamboo-core @@ -1 +1 @@ -Subproject commit de3d5b08c52b8862b38b75fea67baf0631564df1 +Subproject commit 5f1974ac5eb6a540fdb05887dcd21131137f1605 diff --git a/bamboo/fcitxbambooengine.go b/bamboo/fcitxbambooengine.go index c0dcbf6..b4ba24d 100644 --- a/bamboo/fcitxbambooengine.go +++ b/bamboo/fcitxbambooengine.go @@ -17,6 +17,7 @@ import ( type FcitxBambooEngine struct { preeditor bamboo.IEngine + appendingKeySet map[rune]struct{} macroTable *MacroTable dictionary map[string]bool autoNonVnRestore bool @@ -208,6 +209,14 @@ func (e *FcitxBambooEngine) getBambooInputMode() bamboo.Mode { return bamboo.VietnameseMode } +func (e *FcitxBambooEngine) rebuildAppendingKeySet() { + keys := e.preeditor.GetInputMethod().AppendingKeys + e.appendingKeySet = make(map[rune]struct{}, len(keys)) + for _, k := range keys { + e.appendingKeySet[k] = struct{}{} + } +} + func inKeyList(list []rune, key rune) bool { for _, s := range list { if s == key { @@ -225,7 +234,10 @@ func (e *FcitxBambooEngine) toUpper(keyRune rune) rune { '}': ']', } - if upperSpecialKey, found := keyMapping[keyRune]; found && inKeyList(e.preeditor.GetInputMethod().AppendingKeys, keyRune) { + if upperSpecialKey, found := keyMapping[keyRune]; found { + if _, ok := e.appendingKeySet[keyRune]; !ok { + return keyRune + } keyRune = upperSpecialKey } return keyRune @@ -272,7 +284,7 @@ func (e *FcitxBambooEngine) getCommitText(keyVal, state uint32) (string, bool) { keyRune = e.toUpper(keyRune) } e.preeditor.ProcessKey(keyRune, e.getBambooInputMode()) - if inKeyList(e.preeditor.GetInputMethod().AppendingKeys, keyRune) { + if _, ok := e.appendingKeySet[keyRune]; ok { var newText string if e.shouldFallbackToEnglish(true) { newText = e.getProcessedString(bamboo.EnglishMode) diff --git a/src/lotus-engine.h b/src/lotus-engine.h index c73521e..8f10cf2 100644 --- a/src/lotus-engine.h +++ b/src/lotus-engine.h @@ -177,13 +177,6 @@ namespace fcitx { */ uintptr_t macroTable() const; - /** - * @brief Get name of current program - * @param ic Current input context. - * @return Name of current program - */ - std::string getProgramName(InputContext* ic); - /** * @brief Gets the emoji loader. * @return Reference to emoji loader instance. @@ -325,6 +318,13 @@ namespace fcitx { * @param ic Current input context. */ static void setMode(LotusMode mode, InputContext* ic); + + /** + * @brief Get name of current program + * @param ic Current input context. + * @return Name of current program + */ + std::string getProgramName(InputContext* ic); }; /** diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index f027618..4a28538 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -705,6 +705,21 @@ namespace fcitx { keyEvent.filterAndAccept(); isCommit = true; } + } + if (!wa_chromium_flag) + if (!isCommit) { + keyEvent.forward(); + bool hasMultibyte = false; + for (unsigned char c : oldPreBuffer_) + if (c > 0x7F) { + hasMultibyte = true; + break; + } + if (!hasMultibyte && utf8::length(oldPreBuffer_) > 8) { + ResetEngine(lotusEngine_.handle()); + hasHistory_ = false; + oldPreBuffer_.clear(); + } } } if (!wa_chromium_flag && !isCommit) { From c67e71518f3a5a6844739aaed154bd83888f3166 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Tue, 31 Mar 2026 02:10:13 +0700 Subject: [PATCH 09/10] chromium fk u --- src/lotus-state.cpp | 27 +++++++++++++++++++-------- src/lotus-state.h | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 4a28538..0d4a1ed 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -117,9 +117,7 @@ namespace fcitx { LOTUS_ERROR("Cannot send backspace since cannot connect to uinput server"); return; } - ssize_t n = send(uinput_client_fd_, &count, sizeof(count), MSG_NOSIGNAL); - if (n < 0) { LOTUS_WARN("Failed to send backspace: " + std::string(strerror(errno))); int old_fd = uinput_client_fd_.exchange(-1); @@ -490,12 +488,23 @@ namespace fcitx { bool LotusState::performReplacement(const std::string& deletedPart, const std::string& addedPart) { LOTUS_INFO("Perform replacement: " + deletedPart + " -> " + addedPart); //NOLINT - int my_id = ++current_thread_id_; - current_backspace_count_ = 0; - pending_commit_string_ = addedPart; - const auto& surrounding = ic_->surroundingText(); - int autofillOffset = isAutofillCertain(surrounding) ? 1 : 0; - expected_backspaces_ = static_cast(utf8::length(deletedPart)) + 1 + autofillOffset; + int my_id = ++current_thread_id_; + current_backspace_count_ = 0; + pending_commit_string_ = addedPart; + const auto& surrounding = ic_->surroundingText(); + LOTUS_INFO("surroundingText: \"" + surrounding.text() + "\""); + int autofillOffset = isAutofillCertain(surrounding) ? 1 : 0; + // This is bushjt wa + if (wa_flag && !autofillOffset) { + if (surrounding.isValid()) + everHadValidSurr_ = true; + bool surroundingCapable = ic_->capabilityFlags().test(CapabilityFlag::SurroundingText); + if (!everHadValidSurr_ && surroundingCapable && !oldPreBuffer_.empty()) + autofillOffset = 1; + } + + LOTUS_INFO("surroundingText: \"" + surrounding.text() + "\""); + expected_backspaces_ = static_cast(utf8::length(deletedPart)) + 1 + autofillOffset; // Use deleteSurroundingText for apps that support it for smooth typing if (surrtp // Lmfao, only this work :> && surrounding.isValid() && ic_->capabilityFlags().test(CapabilityFlag::SurroundingText) && @@ -692,6 +701,7 @@ namespace fcitx { if (wa_chromium_flag) keyEvent.filterAndAccept(); + LOTUS_INFO("surroundingText: \"" + ic_->surroundingText().text() + "\""); if (compareAndSplitStrings(oldPreBuffer_, preeditStr, commonPrefix, deletedPart, addedPart) != 0) { if (deletedPart.empty()) { bool isCommit = false; @@ -1157,6 +1167,7 @@ namespace fcitx { buffered_keys_.clear(); shouldCapitalize_ = false; isPrevPunctuation_ = false; + everHadValidSurr_ = false; if (lotusEngine_) ResetEngine(lotusEngine_.handle()); } diff --git a/src/lotus-state.h b/src/lotus-state.h index fd4e03b..1f2f6f5 100644 --- a/src/lotus-state.h +++ b/src/lotus-state.h @@ -108,6 +108,7 @@ namespace fcitx { int64_t lastDeactivateTime_ = 0; bool wa_chromium_flag = false; bool surrtp = false; + bool everHadValidSurr_ = false; /** * @brief Connects to the uinput server. From 2869b43f30acb47c5091c2e019f6b5bc4cee25a4 Mon Sep 17 00:00:00 2001 From: Zebra2711 Date: Tue, 31 Mar 2026 02:21:49 +0700 Subject: [PATCH 10/10] e --- src/lotus-engine.cpp | 1 - src/lotus-state.cpp | 30 +++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/lotus-engine.cpp b/src/lotus-engine.cpp index 025a129..9e9a6b7 100644 --- a/src/lotus-engine.cpp +++ b/src/lotus-engine.cpp @@ -376,7 +376,6 @@ namespace fcitx { // TODO: Properly fixes instead ugly WA state->wa_chromium_flag = false; - state->wa_flag = false; state->surrtp = false; state->waitAck_ = false; if (*config_.fixUinputWithAck) { diff --git a/src/lotus-state.cpp b/src/lotus-state.cpp index 0d4a1ed..c4cd034 100644 --- a/src/lotus-state.cpp +++ b/src/lotus-state.cpp @@ -495,7 +495,7 @@ namespace fcitx { LOTUS_INFO("surroundingText: \"" + surrounding.text() + "\""); int autofillOffset = isAutofillCertain(surrounding) ? 1 : 0; // This is bushjt wa - if (wa_flag && !autofillOffset) { + if (wa_chromium_flag && !autofillOffset) { if (surrounding.isValid()) everHadValidSurr_ = true; bool surroundingCapable = ic_->capabilityFlags().test(CapabilityFlag::SurroundingText); @@ -715,22 +715,22 @@ namespace fcitx { keyEvent.filterAndAccept(); isCommit = true; } - } - if (!wa_chromium_flag) - if (!isCommit) { - keyEvent.forward(); - bool hasMultibyte = false; - for (unsigned char c : oldPreBuffer_) - if (c > 0x7F) { - hasMultibyte = true; - break; + } + if (!wa_chromium_flag) + if (!isCommit) { + keyEvent.forward(); + bool hasMultibyte = false; + for (unsigned char c : oldPreBuffer_) + if (c > 0x7F) { + hasMultibyte = true; + break; + } + if (!hasMultibyte && utf8::length(oldPreBuffer_) > 8) { + ResetEngine(lotusEngine_.handle()); + hasHistory_ = false; + oldPreBuffer_.clear(); } - if (!hasMultibyte && utf8::length(oldPreBuffer_) > 8) { - ResetEngine(lotusEngine_.handle()); - hasHistory_ = false; - oldPreBuffer_.clear(); } - } } if (!wa_chromium_flag && !isCommit) { keyEvent.forward();