diff options
author | Peter Varga <pvarga@inf.u-szeged.hu> | 2017-09-05 16:10:41 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-09-17 00:39:59 +0000 |
commit | a12a811026baa86d7d8e4728d893114c76feec20 (patch) | |
tree | 102b3893f438dad2a48ebe3454ede5a2b2c218f0 | |
parent | a6d3799cf34569f5618e4b95f56a42f0e350e403 (diff) |
Commit the done-so-far IME composition on touch event
Fix is based on afc9e2d9674f7ab5800df4803cc68c71d1ae691a
Moreover, new quick auto test has been added to check that the commit
happens in case mouse and touch input events.
Task-number: QTBUG-62942
Change-Id: Ie9d55e0bb5b3bbc34c099502e735b94f37c5d5f8
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 13 | ||||
-rw-r--r-- | tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp | 93 | ||||
-rw-r--r-- | tests/auto/quick/shared/util.h | 77 |
3 files changed, 183 insertions, 0 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 9968d3e49..980550620 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -1414,6 +1414,19 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) break; } + if (m_imeInProgress && ev->type() == QEvent::TouchBegin) { + m_imeInProgress = false; + // Tell input method to commit the pre-edit string entered so far, and finish the + // composition operation. +#ifdef Q_OS_WIN + // Yes the function name is counter-intuitive, but commit isn't actually implemented + // by the Windows QPA, and reset does exactly what is necessary in this case. + qApp->inputMethod()->reset(); +#else + qApp->inputMethod()->commit(); +#endif + } + // Make sure that ACTION_POINTER_DOWN is delivered before ACTION_MOVE, // and ACTION_MOVE before ACTION_POINTER_UP. std::sort(touchPoints.begin(), touchPoints.end(), compareTouchPoints); diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 2f9063ea5..4bc136539 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -35,7 +35,9 @@ #include <QtQml/QQmlEngine> #include <QtTest/QtTest> #include <QtWebEngine/QQuickWebEngineProfile> +#include <private/qinputmethod_p.h> #include <private/qquickwebengineview_p.h> +#include <qpa/qplatforminputcontext.h> #include <functional> @@ -70,6 +72,8 @@ private Q_SLOTS: void inputMethod(); void inputMethodHints(); + void interruptImeTextComposition_data(); + void interruptImeTextComposition(); void basicRenderingSanity(); void setZoomFactor(); void printToPdf(); @@ -450,6 +454,95 @@ void tst_QQuickWebEngineView::inputMethod() #endif } +class TestInputContext : public QPlatformInputContext +{ +public: + TestInputContext() + : commitCallCount(0) + , resetCallCount(0) + { + QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = this; + } + + ~TestInputContext() + { + QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; + } + + virtual void commit() { + commitCallCount++; + } + + virtual void reset() { + resetCallCount++; + } + + int commitCallCount; + int resetCallCount; +}; + +void tst_QQuickWebEngineView::interruptImeTextComposition_data() +{ + QTest::addColumn<QString>("eventType"); + + QTest::newRow("MouseButton") << QString("MouseButton"); +#ifndef Q_OS_MACOS + QTest::newRow("Touch") << QString("Touch"); +#endif +} + +void tst_QQuickWebEngineView::interruptImeTextComposition() +{ + m_window->show(); + QTRY_VERIFY(qApp->focusObject()); + QQuickItem *input; + + QQuickWebEngineView *view = webEngineView(); + view->loadHtml("<html><body>" + " <input type='text' id='input1' /><br>" + " <input type='text' id='input2' />" + "</body></html>"); + QVERIFY(waitForLoadSucceeded(view)); + + runJavaScript("document.getElementById('input1').focus();"); + QTRY_COMPARE(activeElementId(view), QStringLiteral("input1")); + + TestInputContext testContext; + + // Send temporary text, which makes the editor has composition 'x' + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("x", attributes); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QGuiApplication::sendEvent(input, &event); + QTRY_COMPARE(elementValue(view, "input1"), QStringLiteral("x")); + + // Focus 'input2' input field by an input event + QFETCH(QString, eventType); + if (eventType == "MouseButton") { + QPoint textInputCenter = elementCenter(view, QStringLiteral("input2")); + QTest::mouseClick(view->window(), Qt::LeftButton, 0, textInputCenter); + } else if (eventType == "Touch") { + QPoint textInputCenter = elementCenter(view, QStringLiteral("input2")); + QTouchDevice *touchDevice = QTest::createTouchDevice(); + QTest::touchEvent(view->window(), touchDevice).press(0, textInputCenter, view->window()); + QTest::touchEvent(view->window(), touchDevice).release(0, textInputCenter, view->window()); + } + QTRY_COMPARE(activeElementId(view), QStringLiteral("input2")); +#ifndef Q_OS_WIN + QTRY_COMPARE(testContext.commitCallCount, 1); +#else + QTRY_COMPARE(testContext.resetCallCount, 2); +#endif + + // Check the composition text has been committed + runJavaScript("document.getElementById('input1').focus();"); + QTRY_COMPARE(activeElementId(view), QStringLiteral("input1")); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QTRY_COMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QStringLiteral("x")); +} + void tst_QQuickWebEngineView::inputMethodHints() { #if !defined(QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD) diff --git a/tests/auto/quick/shared/util.h b/tests/auto/quick/shared/util.h index dce0afb8e..8e7169be7 100644 --- a/tests/auto/quick/shared/util.h +++ b/tests/auto/quick/shared/util.h @@ -142,4 +142,81 @@ inline QString bodyInnerText(QQuickWebEngineView *webEngineView) return arguments.at(1).toString(); } +inline QString activeElementId(QQuickWebEngineView *webEngineView) +{ + qRegisterMetaType<QQuickWebEngineView::JavaScriptConsoleMessageLevel>("JavaScriptConsoleMessageLevel"); + QSignalSpy consoleMessageSpy(webEngineView, &QQuickWebEngineView::javaScriptConsoleMessage); + + webEngineView->runJavaScript( + "if (document.activeElement == null)" + " console.log('');" + "else" + " console.log(document.activeElement.id);" + ); + + if (!consoleMessageSpy.wait()) + return QString(); + + QList<QVariant> arguments = consoleMessageSpy.takeFirst(); + if (static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(arguments.at(0).toInt()) != QQuickWebEngineView::InfoMessageLevel) + return QString(); + + return arguments.at(1).toString(); +} + +inline QString elementValue(QQuickWebEngineView *webEngineView, const QString &id) +{ + qRegisterMetaType<QQuickWebEngineView::JavaScriptConsoleMessageLevel>("JavaScriptConsoleMessageLevel"); + QSignalSpy consoleMessageSpy(webEngineView, &QQuickWebEngineView::javaScriptConsoleMessage); + + webEngineView->runJavaScript(QString( + "var element = document.getElementById('" + id + "');" + "if (element == null)" + " console.log('');" + "else" + " console.log(element.value);") + ); + + if (!consoleMessageSpy.wait()) + return QString(); + + QList<QVariant> arguments = consoleMessageSpy.takeFirst(); + if (static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(arguments.at(0).toInt()) != QQuickWebEngineView::InfoMessageLevel) + return QString(); + + return arguments.at(1).toString(); +} + +inline QPoint elementCenter(QQuickWebEngineView *webEngineView, const QString &id) +{ + qRegisterMetaType<QQuickWebEngineView::JavaScriptConsoleMessageLevel>("JavaScriptConsoleMessageLevel"); + QSignalSpy consoleMessageSpy(webEngineView, &QQuickWebEngineView::javaScriptConsoleMessage); + + webEngineView->runJavaScript(QString( + "var element = document.getElementById('" + id + "');" + "var rect = element.getBoundingClientRect();" + "console.log((rect.left + rect.right) / 2);" + "console.log((rect.top + rect.bottom) / 2);") + ); + + QTRY_LOOP_IMPL(consoleMessageSpy.count() == 2, 5000, 50); + if (consoleMessageSpy.count() != 2) + return QPoint(); + + QList<QVariant> arguments; + double x, y; + + arguments = consoleMessageSpy.takeFirst(); + if (static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(arguments.at(0).toInt()) != QQuickWebEngineView::InfoMessageLevel) + return QPoint(); + x = arguments.at(1).toDouble(); + + arguments = consoleMessageSpy.takeLast(); + if (static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(arguments.at(0).toInt()) != QQuickWebEngineView::InfoMessageLevel) + return QPoint(); + y = arguments.at(1).toDouble(); + + return QPoint(x, y); +} + #endif /* UTIL_H */ |