diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2023-08-02 22:19:13 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-09-13 18:36:20 +0000 |
commit | c8276e977606c7c27c659a7a74c6361eb813347e (patch) | |
tree | 6b99688aa124351dfcc6cb0516fe6e7b7ceffe83 | |
parent | b6676a4823e058572c9a6b199951ba8f7d4b6365 (diff) |
TextEdit/TextArea: don't deselect on release if IM just selected text
After 90d3fac73a10b9363fd34e6757cc730d7a0c086c we got a regression on
Android at least: if you long-press to select a word, selection handles
appear; then when you release, there's a QTouchEvent which is left
unhandled, and then a synth-mouse release. In this case, we don't want
to call setCursorPosition(), because it de-selects the selection that
was just made by the input method.
But the intention was to be able to set the cursor position (and also
deselect text) by tapping on a touchscreen on other platforms that don't
have text selection handles. (It seems to be consistent with Android
behavior: there you can also deselect and move the cursor by simply
tapping.) To avoid changing that behavior, we now set a flag if we get
a mouse press and then a QInputMethodEvent with a Selection attribute,
indicating that text got selected that way; and in that case, don't
call setCursorPosition().
Fixes: QTBUG-115004
Change-Id: I7e362da584f6e1cb1509dcc0eff024b291ef5df3
Reviewed-by: Santhosh Kumar <santhosh.kumar.selvaraj@qt.io>
Reviewed-by: Rami Potinkara <rami.potinkara@qt.io>
(cherry picked from commit c1d5e46ea79762bfcc070fabbf10ff7fdf184e01)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 2ee61d7dac1df2e7f7e0e6b789bf2176c44f079f)
-rw-r--r-- | src/quick/items/qquicktextcontrol.cpp | 6 | ||||
-rw-r--r-- | src/quick/items/qquicktextcontrol_p_p.h | 1 | ||||
-rw-r--r-- | tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp | 35 |
3 files changed, 41 insertions, 1 deletions
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 929ce10136..510ece726a 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -81,6 +81,7 @@ QQuickTextControlPrivate::QQuickTextControlPrivate() cursorRectangleChanged(false), hoveredMarker(false), selectByTouchDrag(false), + imSelectionAfterPress(false), lastSelectionStart(-1), lastSelectionEnd(-1) {} @@ -992,6 +993,7 @@ void QQuickTextControlPrivate::mousePressEvent(QMouseEvent *e, const QPointF &po mousePressed = (interactionFlags & Qt::TextSelectableByMouse) && (e->button() & Qt::LeftButton); mousePressPos = pos.toPoint(); + imSelectionAfterPress = false; if (sendMouseEventToInputContext(e, pos)) return; @@ -1177,7 +1179,7 @@ void QQuickTextControlPrivate::mouseReleaseEvent(QMouseEvent *e, const QPointF & q->insertFromMimeData(md); #endif } - if (!isMouse && !selectByTouchDrag && interactionFlags.testFlag(Qt::TextEditable)) + if (!isMouse && !selectByTouchDrag && !imSelectionAfterPress && interactionFlags.testFlag(Qt::TextEditable)) setCursorPosition(pos); repaintOldAndNewSelection(oldSelection); @@ -1322,6 +1324,8 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) for (int i = 0; i < e->attributes().size(); ++i) { const QInputMethodEvent::Attribute &a = e->attributes().at(i); if (a.type == QInputMethodEvent::Selection) { + if (mousePressed) + imSelectionAfterPress = true; QTextCursor oldCursor = cursor; int blockStart = a.start + cursor.block().position(); cursor.setPosition(blockStart, QTextCursor::MoveAnchor); diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h index 5717cf6377..f04d298e4a 100644 --- a/src/quick/items/qquicktextcontrol_p_p.h +++ b/src/quick/items/qquicktextcontrol_p_p.h @@ -131,6 +131,7 @@ public: bool cursorRectangleChanged : 1; bool hoveredMarker: 1; bool selectByTouchDrag: 1; + bool imSelectionAfterPress: 1; int lastSelectionStart; int lastSelectionEnd; diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index dc7342d162..9819494d34 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -207,6 +207,8 @@ private slots: void touchscreenDoesNotSelect(); void touchscreenSetsFocusAndMovesCursor(); + void longPressInputMethod(); + void rtlAlignmentInColumnLayout_QTBUG_112858(); private: @@ -6524,6 +6526,39 @@ void tst_qquicktextedit::touchscreenSetsFocusAndMovesCursor() QVERIFY(top->selectedText().isEmpty()); } +void tst_qquicktextedit::longPressInputMethod() // QTBUG-115004 +{ + QQuickView window; + window.setMinimumWidth(200); + window.setMinimumHeight(100); + QVERIFY(QQuickTest::showView(window, testFileUrl("positionAt.qml"))); + QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject()); + QVERIFY(edit); + + // Realistically there are touch events. But QQuickTextEdit doesn't handle them yet; + // so we only test the synth-mouse events for now. + QPoint pos = edit->positionToRectangle(20).center().toPoint(); // in the word "pi|ece" + QTest::mousePress(&window, Qt::LeftButton, {}, pos); + + // Simulate input method events as seen on Android during long-press + { + QInputMethodEvent imEvent({}, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 20, 0, {})); + QCoreApplication::sendEvent(edit, &imEvent); + } + { + QInputMethodEvent imEvent({}, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, {}) + << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 13, -5, {})); + QCoreApplication::sendEvent(edit, &imEvent); + } + + // Release later => long press + QTest::mouseRelease(&window, Qt::LeftButton, {}, pos, 1500); + + QTRY_COMPARE(edit->selectedText(), "piece"); +} + void tst_qquicktextedit::rtlAlignmentInColumnLayout_QTBUG_112858() { QQuickView window(testFileUrl("qtbug-112858.qml")); |