diff --git a/vnkey-fcitx5/src/vnkey-fcitx5.cpp b/vnkey-fcitx5/src/vnkey-fcitx5.cpp index b754931..a87a0ea 100644 --- a/vnkey-fcitx5/src/vnkey-fcitx5.cpp +++ b/vnkey-fcitx5/src/vnkey-fcitx5.cpp @@ -813,6 +813,12 @@ void VnKeyState::commitPreedit(bool soft) { } } preedit_.clear(); + /* Xóa cả client-side và server-side preedit sau khi commit, + * tránh text cũ còn sót lại trên panel Fcitx5 (đặc biệt với + * sandbox apps không hỗ trợ ClientPreedit). */ + ic_->inputPanel().setClientPreedit(Text()); + ic_->inputPanel().setPreedit(Text()); + ic_->updatePreedit(); } if (soft) vnkey_engine_soft_reset(vnkeyEngine_); @@ -871,13 +877,18 @@ bool VnKeyState::isTerminalProgram(const std::string &prog) { void VnKeyState::updatePreeditDisplay() { if (preedit_.empty()) { ic_->inputPanel().setClientPreedit(Text()); + ic_->inputPanel().setPreedit(Text()); ic_->updatePreedit(); return; } Text preeditText; preeditText.append(preedit_); preeditText.setCursor(static_cast(preedit_.size())); + /* Ưu tiên client-side preedit (hiển thị ngay trong app); + * nếu app không hỗ trợ ClientPreedit (vd: Flatpak/Snap sandbox), + * dùng server-side preedit (hiển thị qua panel của Fcitx5). */ ic_->inputPanel().setClientPreedit(preeditText); + ic_->inputPanel().setPreedit(preeditText); ic_->updatePreedit(); } @@ -975,7 +986,13 @@ void VnKeyState::keyEvent(KeyEvent &keyEvent) { /* Xử lý Backspace */ if (key.check(FcitxKey_BackSpace)) { - if (isTerminal_) { + /* Flatpak/Snap sandbox app không hỗ trợ SurroundingText → + * không thể deleteSurroundingText → phải dùng preedit mode. + * Giống logic terminal: duy trì preedit buffer nội bộ. */ + bool hasSurrounding = ic_->capabilityFlags().test(CapabilityFlag::SurroundingText); + bool usePreedit = isTerminal_ || !hasSurrounding; + + if (usePreedit) { /* Chế độ preedit cho terminal: cập nhật preedit */ if (preedit_.empty()) { return; /* không có gì để xóa, để hệ thống xử lý */ @@ -1015,7 +1032,7 @@ void VnKeyState::keyEvent(KeyEvent &keyEvent) { return; } - /* Chế độ commit trực tiếp (ứng dụng GUI) */ + /* Chế độ commit trực tiếp (ứng dụng GUI có SurroundingText) */ uint8_t buf[256]; size_t actualLen = 0; size_t backspaces = 0; @@ -1024,8 +1041,7 @@ void VnKeyState::keyEvent(KeyEvent &keyEvent) { if (processed && (backspaces > 0 || actualLen > 0)) { /* Xóa ký tự đã commit */ - if (backspaces > 0 && - ic_->capabilityFlags().test(CapabilityFlag::SurroundingText)) { + if (backspaces > 0) { ic_->deleteSurroundingText( -static_cast(backspaces), static_cast(backspaces)); @@ -1053,8 +1069,18 @@ void VnKeyState::keyEvent(KeyEvent &keyEvent) { int processed = vnkey_engine_process( vnkeyEngine_, keyCode, buf, sizeof(buf), &actualLen, &backspaces, nullptr); - if (isTerminal_) { - /* Chế độ preedit cho terminal: cập nhật preedit */ + /* Flatpak/Snap sandbox app không hỗ trợ SurroundingText → + * không thể deleteSurroundingText để sửa ký tự đã commit. + * Phải dùng preedit mode: duy trì buffer nội bộ, + * chỉ commitString() khi hoàn thành từ. + * Điều này đảm bảo ký tự tiếng Việt được gửi nguyên vẹn, + * không bị nhân đôi như khi dùng direct commit + * mà không có capability SurroundingText. */ + bool hasSurrounding = ic_->capabilityFlags().test(CapabilityFlag::SurroundingText); + bool usePreedit = isTerminal_ || !hasSurrounding; + + if (usePreedit) { + /* Chế độ preedit cho terminal/sandbox: cập nhật preedit */ if (processed) { /* Xóa backspaces ký tự UTF-8 cuối từ preedit */ for (size_t i = 0; i < backspaces && !preedit_.empty(); i++) { @@ -1084,8 +1110,8 @@ void VnKeyState::keyEvent(KeyEvent &keyEvent) { return; } - /* Chế độ commit trực tiếp (ứng dụng GUI) */ - bool hasSurrounding = ic_->capabilityFlags().test(CapabilityFlag::SurroundingText); + /* Chế độ commit trực tiếp (ứng dụng GUI có SurroundingText) */ + /* hasSurrounding đã khai báo ở trên (dòng 1073) */ fprintf(stderr, "[vnkey] process: key=%c(0x%x) processed=%d bs=%zu len=%zu surrounding=%d\n", (keyCode >= 0x20 && keyCode < 0x7f) ? (char)keyCode : '?', keyCode, processed, backspaces, actualLen, hasSurrounding);