diff --git a/devel/200_54.md b/devel/200_54.md new file mode 100644 index 0000000000..a271a851d3 --- /dev/null +++ b/devel/200_54.md @@ -0,0 +1,58 @@ +# [200_54] 修复 Fedora/GNOME 输入法候选窗口不跟随光标问题 + +## 如何测试 + +此 PR 在 Fedora 43 + GNOME (Wayland) 平台下测试,使用 ibus 或 fcitx 输入法框架 + +测试项一:ibus 候选窗口应跟随光标 +1. 启动 Mogan +2. 切换到 ibus 输入法(如 ibus-libpinyin) +3. 在文档中输入中文,观察候选窗口位置 +4. 候选窗口应始终跟随光标,不应偏移到屏幕固定位置 + +测试项二:fcitx 候选窗口应跟随光标 +1. 切换到 fcitx5 输入法 +2. 在文档中输入中文 +3. 候选窗口应跟随光标移动 + +测试项三:跨行/滚动时光标跟踪 +1. 输入多行中文内容 +2. 在行尾、行首、段落中间等不同位置输入 +3. 滚动文档后继续输入 +4. 候选窗口应始终出现在当前输入位置附近 + +测试项四:其他平台不应出现回归 +1. 在 Windows/macOS/其他 Linux 桌面环境下测试中文输入 +2. 候选窗口定位行为应与修复前一致或更好 + +## 2026/04/23 修复 Fedora/GNOME 输入法悬浮框定位问题 + +### What +修复了在 Fedora/GNOME (Wayland) 环境下,ibus/fcitx 输入法候选窗口不跟随光标、偏移到屏幕固定位置的问题。 + +### Why +在 Qt6 + Wayland 环境下,ibus/fcitx 通过 `text-input-v3` 协议与 compositor 通信。输入法框架在候选窗口弹出后,不会持续主动重新查询光标位置(`Qt::ImCursorRectangle`),只在窗口显示前查询一次。这导致光标移动后,候选窗口仍停留在第一次查询时的旧位置,表现为"固定在右侧居中不动"。 + +`QTMWidget::inputMethodQuery()` 本身已正确实现了光标矩形计算,但缺少触发输入法重新查询的机制。 + +### How +`src/Plugins/Qt/qt_simple_widget.cpp` :26-29, 276-279 +- 在 Linux 平台下添加 `#include ` 和 `#include ` +- 在 `SLOT_CURSOR` 处理中,仅限 Linux 平台显式调用 `QInputMethod::update(Qt::ImCursorRectangle)` +- 这会通知输入法框架光标矩形已改变,触发其重新调用 `QTMWidget::inputMethodQuery()` 获取最新坐标 + +```cpp +case SLOT_CURSOR: { + check_type (val, s); + coord2 p= open_box (val); + canvas ()->setCursorPos (to_qpoint (p)); +#ifdef Q_OS_LINUX + QInputMethod* im= QGuiApplication::inputMethod (); + if (im) im->update (Qt::ImCursorRectangle); +#endif +} break; +``` + +### 影响范围 +- **修复平台**:Linux(Fedora/GNOME Wayland 下的 ibus/fcitx) +- **其他平台**:通过 `#ifdef Q_OS_LINUX` 条件编译隔离,macOS 和 Windows 完全不受影响 diff --git a/src/Plugins/Qt/qt_simple_widget.cpp b/src/Plugins/Qt/qt_simple_widget.cpp index 449cc8e888..61531d43be 100644 --- a/src/Plugins/Qt/qt_simple_widget.cpp +++ b/src/Plugins/Qt/qt_simple_widget.cpp @@ -23,6 +23,10 @@ #include "QTMStyle.hpp" #include "QTMTextPopup.hpp" #include "QTMWidget.hpp" +#ifdef Q_OS_LINUX +#include +#include +#endif #include #include #if QT_VERSION >= 0x060000 @@ -269,6 +273,10 @@ qt_simple_widget_rep::send (slot s, blackbox val) { check_type (val, s); coord2 p= open_box (val); canvas ()->setCursorPos (to_qpoint (p)); +#ifdef Q_OS_LINUX + QInputMethod* im= QGuiApplication::inputMethod (); + if (im) im->update (Qt::ImCursorRectangle); +#endif } break; default: