aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2023-08-02 22:19:13 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-09-13 18:36:20 +0000
commitc8276e977606c7c27c659a7a74c6361eb813347e (patch)
tree6b99688aa124351dfcc6cb0516fe6e7b7ceffe83
parentb6676a4823e058572c9a6b199951ba8f7d4b6365 (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.cpp6
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h1
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp35
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"));