Skip to content

fix: forward InputMethodQuery to searchEdit for correct IME candidate…#731

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
Ivy233:fix-ime-candidate-window-position
Mar 17, 2026
Merged

fix: forward InputMethodQuery to searchEdit for correct IME candidate…#731
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
Ivy233:fix-ime-candidate-window-position

Conversation

@Ivy233
Copy link
Contributor

@Ivy233 Ivy233 commented Mar 12, 2026

… window positioning

When launcher opens, focus is on InputEventItem (root node) while searchEdit has no focus or cursor, as per design requirements. However, IMEs like Sogou send InputMethodQuery events to the focused control during pre-edit stage to query cursor position for candidate window placement. Since InputEventItem is not a text input control, it cannot return meaningful cursor position, causing the candidate window to appear at incorrect positions (e.g., top-left corner or other wrong locations).

This commit implements a forwarding mechanism: when InputEventItem receives InputMethodQuery, it forwards the query to searchEdit and maps the returned cursor rectangle coordinates from searchEdit's local coordinate system to the query target's coordinate system, then returns the mapped result to the IME framework. This allows the candidate window to be positioned correctly near the search box while keeping focus on InputEventItem (no visible cursor in search box).

Changes:

  • Add inputMethodSource property to InputEventItem for specifying the text control to forward queries to
  • Implement InputMethodQuery event forwarding and coordinate mapping in eventFilter
  • Set inputMethodSource to searchEdit in FullscreenFrame and WindowedFrame
  • Clean up temporary diagnostic logs

启动器打开时,焦点在 InputEventItem(根节点)上,searchEdit 无焦点、无光标,这是设计要求。但搜狗等输入法在预编辑阶段会向焦点控件发送 InputMethodQuery 事件查询光标位置以定位候选框。由于 InputEventItem 不是文本输入控件,无法返回有意义的光标位置,导致候选框出现在错误位置(如屏幕左上角或其他位置)。

本次提交实现了转发机制:InputEventItem 收到 InputMethodQuery 时,将查询转发给 searchEdit,并将 searchEdit 返回的光标矩形坐标从其局部坐标系映射到查询目标的坐标系,再将映射后的结果返回给输入法框架。这样候选框能正确定位到搜索框附近,同时焦点保持在 InputEventItem 上(搜索框不显示光标)。

修改内容:

  • 为 InputEventItem 添加 inputMethodSource 属性,用于指定转发查询的文本控件
  • 在 eventFilter 中实现 InputMethodQuery 事件转发和坐标映射
  • 在 FullscreenFrame 和 WindowedFrame 中设置 inputMethodSource 为 searchEdit
  • 清理临时诊断日志

PMS: BUG-301743

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Ivy233, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-bot
Copy link

deepin-bot bot commented Mar 12, 2026

TAG Bot

New tag: 2.0.31
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #734

@Ivy233 Ivy233 force-pushed the fix-ime-candidate-window-position branch 2 times, most recently from e03a9e0 to e4107f7 Compare March 13, 2026 06:26
@18202781743 18202781743 self-requested a review March 17, 2026 02:01
18202781743
18202781743 previously approved these changes Mar 17, 2026
QVariant InputEventItem::inputMethodQuery(Qt::InputMethodQuery query) const
{
if (m_inputMethodSource) {
QVariant result = m_inputMethodSource->inputMethodQuery(query);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个变量的定义放在query == Qt::ImCursorRect里面吧,只有它使用了,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

分别删除测试了一下:

  1. Qt::ImCursorRectangle需要完成从searchEdit的相对坐标转换成InputEventItem的相对坐标。这个删不动。
  2. Qt::ImEnabled看起来可以去掉。这个是防御性的,防止某些情况下无法输入。
  3. 其他情况正常返回result即可。

@Ivy233 Ivy233 force-pushed the fix-ime-candidate-window-position branch from e4107f7 to be3b392 Compare March 17, 2026 03:07
@Ivy233 Ivy233 requested a review from 18202781743 March 17, 2026 03:07
… window positioning

Override inputMethodQuery() virtual function in InputEventItem to forward input method queries to searchEdit. When IME queries cursor position for candidate window placement, the function forwards the query to searchEdit and maps the returned cursor rectangle coordinates from searchEdit's local coordinate system to InputEventItem's coordinate system. This ensures the candidate window appears at the correct position near the search box while keeping focus on InputEventItem.

Changes:
- Add inputMethodSource property to InputEventItem for specifying the text control to forward queries to
- Override inputMethodQuery() to forward queries and map coordinates for ImCursorRectangle
- Set inputMethodSource to searchEdit and add focus property in FullscreenFrame and WindowedFrame
- Remove redundant ImEnabled override as SearchEdit already returns correct state

重写 InputEventItem 的 inputMethodQuery() 虚函数,将输入法查询转发给 searchEdit。当输入法查询光标位置以定位候选框时,该函数将查询转发给 searchEdit,并将返回的光标矩形坐标从 searchEdit 的局部坐标系映射到 InputEventItem 的坐标系。这确保候选框出现在搜索框附近的正确位置,同时焦点保持在 InputEventItem 上。

修改内容:
- 为 InputEventItem 添加 inputMethodSource 属性,用于指定转发查询的文本控件
- 重写 inputMethodQuery() 以转发查询并映射 ImCursorRectangle 的坐标
- 在 FullscreenFrame 和 WindowedFrame 中设置 inputMethodSource 为 searchEdit 并添加 focus 属性
- 移除冗余的 ImEnabled 覆盖,因为 SearchEdit 已经返回正确状态

PMS: BUG-301743
@Ivy233 Ivy233 force-pushed the fix-ime-candidate-window-position branch from be3b392 to eeba2de Compare March 17, 2026 03:15
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, Ivy233

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要是为 InputEventItem 类增加了对输入法源(inputMethodSource)的支持,使得该类能够将输入法查询(特别是光标位置)代理给指定的子项,并在 QML 中进行了相应的绑定。以下是对该 diff 的详细审查和改进建议:

1. 语法逻辑审查

  • 版权年份更新

    • // SPDX-FileCopyrightText: 2023 - 2026
    • 意见:通常版权年份是“起始年份 - 当前年份”或“起始年份 - 结束年份”。直接写 2026 年可能意味着这是一个长期维护的版本,或者仅仅是预测。建议确认是否应改为 2023 - 2024(当前年份)。
  • 空指针检查

    • inputMethodQuery 中,使用了 if (m_inputMethodSource) 进行检查,逻辑正确。
    • 意见:逻辑正确,符合安全编程规范。
  • 属性绑定逻辑

    • QML 中 inputMethodSource: searchEdit 绑定了具体的输入控件。
    • 意见:逻辑清晰,符合 Qt/QML 的属性绑定机制。

2. 代码质量

  • 头文件包含

    • inputeventitem.cpp 中使用了 QRectFQPointF,但 diff 中未显示头文件部分。
    • 建议:请确保 #include <QRectF>#include <QPointF>(或包含它们的通用头文件如 <QtGlobal>)已被添加到 .cpp 文件中。
  • 事件过滤逻辑

    • eventFilter(this->children().contains(obj) || obj == this) 这里的逻辑是判断事件源是否是自身或子对象。
    • 建议:在 QQuickItem 层级结构中,通常 children() 返回的是 QQuickItem 列表,而 objQObject*。虽然 QObject 列表包含 QQuickItem,但直接使用 contains 比较指针在逻辑上是可行的。不过,如果 obj 不是 QQuickItem(例如是普通的 QObject 子类),children() 可能不包含它。鉴于上下文是输入事件,这通常是没问题的,但需注意 children() 只包含直接子对象,不包含子孙对象。如果输入框嵌套较深,可能需要递归检查。

3. 代码性能

  • 坐标映射

    • QPointF mapped = m_inputMethodSource->mapToItem(this, rect.topLeft());
    • 意见mapToItem 涉及坐标变换,虽然开销不大,但在高频触发的输入法查询中(如光标闪烁),应确保其效率。目前的实现是合理的,因为输入法查询通常由输入法上下文驱动,频率可控。
  • 类型转换

    • QVariant result = m_inputMethodSource->inputMethodQuery(query);
    • 意见QVariant 的转换有一定开销,但在处理跨层查询时是必要的。代码中仅针对 Qt::ImCursorRectangle 做了特殊处理,其他查询透传,性能考虑得当。

4. 代码安全

  • 空指针解引用风险

    • QVariant result = m_inputMethodSource->inputMethodQuery(query);
    • 意见:虽然有外层的 if (m_inputMethodSource) 保护,但 inputMethodQuery 内部可能依赖于对象状态。如果 m_inputMethodSource 处于正在析构的过程中(多线程环境下极少见,但在异步信号槽中可能存在),可能会有风险。不过在 Qt GUI 单线程模型下,这通常是安全的。
  • 对象生命周期管理

    • m_inputMethodSource 是一个裸指针。
    • 风险:如果 searchEdit 在 QML 中被销毁,而 InputEventItem 仍然持有这个悬空指针,下次调用 inputMethodQuery 时会导致崩溃。
    • 改进建议
      • 方案 1(推荐):使用 QPointer<QQuickItem> 代替裸指针 QQuickItem*QPointer 会在对象被销毁时自动置为 nullptr,防止悬空指针访问。
      • 方案 2:在 QML 绑定中,如果 searchEdit 是动态创建的,需要确保 InputEventItem 的生命周期不比 searchEdit 长,或者在 searchEdit 销毁时手动将 inputMethodSource 置空。
  • 类型安全

    • QRectF rect = result.toRectF();
    • 意见:如果 inputMethodQuery 返回的 QVariant 无法转换为 QRectFtoRectF() 会返回一个空矩形。这通常不会导致崩溃,但可能导致输入法候选框位置错误。
    • 改进建议:可以增加一个 result.isValid() 的检查,虽然 toRectF() 对无效值有容错,但显式检查更严谨。

综合改进代码示例

针对上述安全和质量建议,以下是修改后的代码片段建议:

inputeventitem.h

#include <QPointer> // 引入 QPointer

// ...
private:
    QPointer<QQuickItem> m_inputMethodSource; // 使用 QPointer 防止悬空指针
// ...

inputeventitem.cpp

QVariant InputEventItem::inputMethodQuery(Qt::InputMethodQuery query) const
{
    // QPointer 会在对象销毁时自动置空,这里检查既检查了是否为空,也检查了对象是否存活
    if (m_inputMethodSource) {
        if (query == Qt::ImCursorRectangle) {
            QVariant result = m_inputMethodSource->inputMethodQuery(query);
            // 增加有效性检查
            if (result.isValid()) {
                QRectF rect = result.toRectF();
                // 坐标映射
                QPointF mapped = m_inputMethodSource->mapToItem(this, rect.topLeft());
                rect.moveTopLeft(mapped);
                return rect;
            }
        }
    }
    return QQuickItem::inputMethodQuery(query);
}

总结

这段代码实现了预期的功能,逻辑基本正确。主要改进点在于对象生命周期的安全性(使用 QPointer)以及防御性编程(检查 QVariant 有效性)。此外,建议确认版权年份的准确性。

@Ivy233
Copy link
Contributor Author

Ivy233 commented Mar 17, 2026

/merge

@deepin-bot deepin-bot bot merged commit 03cd04f into linuxdeepin:master Mar 17, 2026
11 checks passed
@Ivy233 Ivy233 deleted the fix-ime-candidate-window-position branch March 17, 2026 03:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants