diff options
7 files changed, 396 insertions, 26 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 267460bdc..2326dbdf7 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -746,25 +746,29 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana Q_UNUSED(updated_view); Q_UNUSED(did_update_state); - ui::TextInputType type = getTextInputType(); - m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE, type == ui::TEXT_INPUT_TYPE_PASSWORD); - m_delegate->setInputMethodHints(toQtInputMethodHints(type)); - const content::TextInputState *state = text_input_manager_->GetTextInputState(); - if (!state) + if (!state) { + m_delegate->inputMethodStateChanged(false /*editorVisible*/, false /*passwordInput*/); + m_delegate->setInputMethodHints(Qt::ImhNone); return; + } - // At this point it is unknown whether the text input state has been updated due to a text selection. - // Keep the cursor position updated for cursor movements too. - if (GetSelectedText().empty()) - m_cursorPosition = state->selection_start; + ui::TextInputType type = getTextInputType(); + m_delegate->setInputMethodHints(toQtInputMethodHints(getTextInputType())); m_surroundingText = QString::fromStdString(state->value); - // Remove IME composition text from the surrounding text if (state->composition_start != -1 && state->composition_end != -1) m_surroundingText.remove(state->composition_start, state->composition_end - state->composition_start); + // In case of text selection, the update is expected in RenderWidgetHostViewQt::selectionChanged(). + if (GetSelectedText().empty()) { + // At this point it is unknown whether the text input state has been updated due to a text selection. + // Keep the cursor position updated for cursor movements too. + m_cursorPosition = state->selection_start; + m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE, type == ui::TEXT_INPUT_TYPE_PASSWORD); + } + if (m_imState & ImStateFlags::TextInputStateUpdated) { m_imState = ImStateFlags::TextInputStateUpdated; return; @@ -821,9 +825,10 @@ void RenderWidgetHostViewQt::selectionChanged() { // Reset input manager state m_imState = 0; + ui::TextInputType type = getTextInputType(); // Handle text selection out of an input field - if (getTextInputType() == ui::TEXT_INPUT_TYPE_NONE) { + if (type == ui::TEXT_INPUT_TYPE_NONE) { if (GetSelectedText().empty() && m_emptyPreviousSelection) return; @@ -843,12 +848,13 @@ void RenderWidgetHostViewQt::selectionChanged() // if the selection is cleared because TextInputState changes before the TextSelection change. Q_ASSERT(text_input_manager_->GetTextInputState()); m_cursorPosition = text_input_manager_->GetTextInputState()->selection_start; + m_delegate->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); m_anchorPositionWithinSelection = m_cursorPosition; m_cursorPositionWithinSelection = m_cursorPosition; if (!m_emptyPreviousSelection) { - m_emptyPreviousSelection = GetSelectedText().empty(); + m_emptyPreviousSelection = true; m_adapterClient->selectionChanged(); } @@ -883,6 +889,7 @@ void RenderWidgetHostViewQt::selectionChanged() m_cursorPosition = newCursorPositionWithinSelection; m_emptyPreviousSelection = selection->selected_text().empty(); + m_delegate->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); m_adapterClient->selectionChanged(); } diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index 1176573fd..2f65db97a 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -54,7 +54,6 @@ namespace QtWebEngineCore { RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup) : m_client(client) , m_isPopup(isPopup) - , m_isPasswordInput(false) { setFlag(ItemHasContents); setAcceptedMouseButtons(Qt::AllButtons); @@ -206,11 +205,9 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis if (parentItem()) parentItem()->setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible && !passwordInput); - if (qApp->inputMethod()->isVisible() != editorVisible || m_isPasswordInput != passwordInput) { - qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); + qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); + if (qApp->inputMethod()->isVisible() != editorVisible) qApp->inputMethod()->setVisible(editorVisible); - m_isPasswordInput = passwordInput; - } } bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index 6f6cd1509..d4d64804a 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -113,7 +113,6 @@ private: RenderWidgetHostViewQtDelegateClient *m_client; QList<QMetaObject::Connection> m_windowConnections; bool m_isPopup; - bool m_isPasswordInput; QPointF m_lastGlobalPos; QQuickWebEngineView *m_view = nullptr; }; diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index e34bca875..900ed3324 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -107,7 +107,6 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende , m_client(client) , m_rootItem(new RenderWidgetHostViewQuickItem(client)) , m_isPopup(false) - , m_isPasswordInput(false) { setFocusPolicy(Qt::StrongFocus); @@ -341,14 +340,10 @@ void RenderWidgetHostViewQtDelegateWidget::move(const QPoint &screenPos) void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVisible, bool passwordInput) { - if (qApp->inputMethod()->isVisible() == editorVisible && m_isPasswordInput == passwordInput) - return; - QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, editorVisible && !passwordInput); - m_isPasswordInput = passwordInput; - qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); - qApp->inputMethod()->setVisible(editorVisible); + if (qApp->inputMethod()->isVisible() != editorVisible) + qApp->inputMethod()->setVisible(editorVisible); } void RenderWidgetHostViewQtDelegateWidget::setInputMethodHints(Qt::InputMethodHints hints) diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index e23f13d86..c1cd90093 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -110,7 +110,6 @@ private: RenderWidgetHostViewQtDelegateClient *m_client; QScopedPointer<QQuickItem> m_rootItem; bool m_isPopup; - bool m_isPasswordInput; QColor m_clearColor; QPoint m_lastGlobalPos; QList<QMetaObject::Connection> m_windowConnections; diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 5cb904fb6..cf08ccd1d 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -75,6 +75,7 @@ private Q_SLOTS: void inputMethod(); void inputMethodHints(); + void inputContextQueryInput(); void interruptImeTextComposition_data(); void interruptImeTextComposition(); void basicRenderingSanity(); @@ -471,6 +472,24 @@ void tst_QQuickWebEngineView::inputMethod() QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); } +struct InputMethodInfo +{ + InputMethodInfo(const int cursorPosition, + const int anchorPosition, + QString surroundingText, + QString selectedText) + : cursorPosition(cursorPosition) + , anchorPosition(anchorPosition) + , surroundingText(surroundingText) + , selectedText(selectedText) + {} + + const int cursorPosition; + const int anchorPosition; + QString surroundingText; + QString selectedText; +}; + class TestInputContext : public QPlatformInputContext { public: @@ -496,8 +515,28 @@ public: resetCallCount++; } + virtual void update(Qt::InputMethodQueries queries) + { + if (!qApp->focusObject()) + return; + + if (!(queries & Qt::ImQueryInput)) + return; + + QInputMethodQueryEvent imQueryEvent(Qt::ImQueryInput); + QGuiApplication::sendEvent(qApp->focusObject(), &imQueryEvent); + + const int cursorPosition = imQueryEvent.value(Qt::ImCursorPosition).toInt(); + const int anchorPosition = imQueryEvent.value(Qt::ImAnchorPosition).toInt(); + QString surroundingText = imQueryEvent.value(Qt::ImSurroundingText).toString(); + QString selectedText = imQueryEvent.value(Qt::ImCurrentSelection).toString(); + + infos.append(InputMethodInfo(cursorPosition, anchorPosition, surroundingText, selectedText)); + } + int commitCallCount; int resetCallCount; + QList<InputMethodInfo> infos; }; void tst_QQuickWebEngineView::interruptImeTextComposition_data() @@ -561,6 +600,151 @@ void tst_QQuickWebEngineView::interruptImeTextComposition() QTRY_COMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QStringLiteral("x")); } +void tst_QQuickWebEngineView::inputContextQueryInput() +{ + m_window->show(); + QTRY_VERIFY(qApp->focusObject()); + TestInputContext testContext; + + QQuickWebEngineView *view = webEngineView(); + view->settings()->setFocusOnNavigationEnabled(true); + view->loadHtml("<html><body>" + " <input type='text' id='input1' />" + "</body></html>"); + QVERIFY(waitForLoadSucceeded(view)); + QCOMPARE(testContext.infos.count(), 0); + + // Set focus on an input field. + QPoint textInputCenter = elementCenter(view, "input1"); + QTest::mouseClick(view->window(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(testContext.infos.count(), 2); + QCOMPARE(evaluateJavaScriptSync(view, "document.activeElement.id").toString(), QStringLiteral("input1")); + foreach (const InputMethodInfo &info, testContext.infos) { + QCOMPARE(info.cursorPosition, 0); + QCOMPARE(info.anchorPosition, 0); + QCOMPARE(info.surroundingText, QStringLiteral("")); + QCOMPARE(info.selectedText, QStringLiteral("")); + } + testContext.infos.clear(); + + // Change content of an input field from JavaScript. + evaluateJavaScriptSync(view, "document.getElementById('input1').value='QtWebEngine';"); + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 11); + QCOMPARE(testContext.infos[0].anchorPosition, 11); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Change content of an input field by key press. + QTest::keyClick(view->window(), Qt::Key_Exclam); + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 12); + QCOMPARE(testContext.infos[0].anchorPosition, 12); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Change cursor position. + QTest::keyClick(view->window(), Qt::Key_Left); + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 11); + QCOMPARE(testContext.infos[0].anchorPosition, 11); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Selection by IME. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 2, 12, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("", attributes); + QGuiApplication::sendEvent(qApp->focusObject(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 2); + + // As a first step, Chromium moves the cursor to the start of the selection. + // We don't filter this in QtWebEngine because we don't know yet if this is part of a selection. + QCOMPARE(testContext.infos[0].cursorPosition, 2); + QCOMPARE(testContext.infos[0].anchorPosition, 2); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + + // The update of the selection. + QCOMPARE(testContext.infos[1].cursorPosition, 12); + QCOMPARE(testContext.infos[1].anchorPosition, 2); + QCOMPARE(testContext.infos[1].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[1].selectedText, QStringLiteral("WebEngine!")); + testContext.infos.clear(); + + // Clear selection by IME. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("", attributes); + QGuiApplication::sendEvent(qApp->focusObject(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 0); + QCOMPARE(testContext.infos[0].anchorPosition, 0); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Compose text. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("123", attributes); + QGuiApplication::sendEvent(qApp->focusObject(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 3); + QCOMPARE(testContext.infos[0].anchorPosition, 3); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + QCOMPARE(evaluateJavaScriptSync(view, "document.getElementById('input1').value").toString(), QStringLiteral("123QtWebEngine!")); + testContext.infos.clear(); + + // Cancel composition. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + QGuiApplication::sendEvent(qApp->focusObject(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 2); + foreach (const InputMethodInfo &info, testContext.infos) { + QCOMPARE(info.cursorPosition, 0); + QCOMPARE(info.anchorPosition, 0); + QCOMPARE(info.surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(info.selectedText, QStringLiteral("")); + } + QCOMPARE(evaluateJavaScriptSync(view, "document.getElementById('input1').value").toString(), QStringLiteral("QtWebEngine!")); + testContext.infos.clear(); + + // Commit text. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString(QStringLiteral("123"), 0, 0); + QGuiApplication::sendEvent(qApp->focusObject(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 3); + QCOMPARE(testContext.infos[0].anchorPosition, 3); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("123QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + QCOMPARE(evaluateJavaScriptSync(view, "document.getElementById('input1').value").toString(), QStringLiteral("123QtWebEngine!")); + testContext.infos.clear(); + + // Focus out. + QTest::keyPress(view->window(), Qt::Key_Tab); + QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(evaluateJavaScriptSync(view, "document.activeElement.id").toString(), QStringLiteral("")); + testContext.infos.clear(); +} + void tst_QQuickWebEngineView::inputMethodHints() { m_window->show(); diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index a6487d19a..eb340b6f5 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -167,6 +167,7 @@ private Q_SLOTS: void inputFieldOverridesShortcuts(); void softwareInputPanel(); + void inputContextQueryInput(); void inputMethods(); void textSelectionInInputField(); void textSelectionOutOfInputField(); @@ -1689,6 +1690,24 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() QTRY_VERIFY(actionTriggered); } +struct InputMethodInfo +{ + InputMethodInfo(const int cursorPosition, + const int anchorPosition, + QString surroundingText, + QString selectedText) + : cursorPosition(cursorPosition) + , anchorPosition(anchorPosition) + , surroundingText(surroundingText) + , selectedText(selectedText) + {} + + const int cursorPosition; + const int anchorPosition; + QString surroundingText; + QString selectedText; +}; + class TestInputContext : public QPlatformInputContext { public: @@ -1718,7 +1737,27 @@ public: return m_visible; } + virtual void update(Qt::InputMethodQueries queries) + { + if (!qApp->focusObject()) + return; + + if (!(queries & Qt::ImQueryInput)) + return; + + QInputMethodQueryEvent imQueryEvent(Qt::ImQueryInput); + QApplication::sendEvent(qApp->focusObject(), &imQueryEvent); + + const int cursorPosition = imQueryEvent.value(Qt::ImCursorPosition).toInt(); + const int anchorPosition = imQueryEvent.value(Qt::ImAnchorPosition).toInt(); + QString surroundingText = imQueryEvent.value(Qt::ImSurroundingText).toString(); + QString selectedText = imQueryEvent.value(Qt::ImCurrentSelection).toString(); + + infos.append(InputMethodInfo(cursorPosition, anchorPosition, surroundingText, selectedText)); + } + bool m_visible; + QList<InputMethodInfo> infos; }; void tst_QWebEngineView::softwareInputPanel() @@ -1779,6 +1818,156 @@ void tst_QWebEngineView::softwareInputPanel() QVERIFY(!testContext.isInputPanelVisible()); } +void tst_QWebEngineView::inputContextQueryInput() +{ + TestInputContext testContext; + QWebEngineView view; + view.resize(640, 480); + view.show(); + + QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged())); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " <input type='text' id='input1' value='' size='50'/>" + "</body></html>"); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QCOMPARE(testContext.infos.count(), 0); + + // Set focus on an input field. + QPoint textInputCenter = elementCenter(view.page(), "input1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(testContext.infos.count(), 2); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + foreach (const InputMethodInfo &info, testContext.infos) { + QCOMPARE(info.cursorPosition, 0); + QCOMPARE(info.anchorPosition, 0); + QCOMPARE(info.surroundingText, QStringLiteral("")); + QCOMPARE(info.selectedText, QStringLiteral("")); + } + testContext.infos.clear(); + + // Change content of an input field from JavaScript. + evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value='QtWebEngine';"); + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 11); + QCOMPARE(testContext.infos[0].anchorPosition, 11); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Change content of an input field by key press. + QTest::keyClick(view.focusProxy(), Qt::Key_Exclam); + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 12); + QCOMPARE(testContext.infos[0].anchorPosition, 12); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Change cursor position. + QTest::keyClick(view.focusProxy(), Qt::Key_Left); + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 11); + QCOMPARE(testContext.infos[0].anchorPosition, 11); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + + // Selection by IME. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 2, 12, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 2); + QCOMPARE(selectionChangedSpy.count(), 1); + + // As a first step, Chromium moves the cursor to the start of the selection. + // We don't filter this in QtWebEngine because we don't know yet if this is part of a selection. + QCOMPARE(testContext.infos[0].cursorPosition, 2); + QCOMPARE(testContext.infos[0].anchorPosition, 2); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + + // The update of the selection. + QCOMPARE(testContext.infos[1].cursorPosition, 12); + QCOMPARE(testContext.infos[1].anchorPosition, 2); + QCOMPARE(testContext.infos[1].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[1].selectedText, QStringLiteral("WebEngine!")); + testContext.infos.clear(); + selectionChangedSpy.clear(); + + // Clear selection by IME. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 0); + QCOMPARE(testContext.infos[0].anchorPosition, 0); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + testContext.infos.clear(); + selectionChangedSpy.clear(); + + // Compose text. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("123", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 3); + QCOMPARE(testContext.infos[0].anchorPosition, 3); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("123QtWebEngine!")); + testContext.infos.clear(); + + // Cancel composition. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 2); + foreach (const InputMethodInfo &info, testContext.infos) { + QCOMPARE(info.cursorPosition, 0); + QCOMPARE(info.anchorPosition, 0); + QCOMPARE(info.surroundingText, QStringLiteral("QtWebEngine!")); + QCOMPARE(info.selectedText, QStringLiteral("")); + } + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("QtWebEngine!")); + testContext.infos.clear(); + + // Commit text. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString(QStringLiteral("123"), 0, 0); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(testContext.infos.count(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 3); + QCOMPARE(testContext.infos[0].anchorPosition, 3); + QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("123QtWebEngine!")); + QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("123QtWebEngine!")); + testContext.infos.clear(); + + // Focus out. + QTest::keyPress(view.focusProxy(), Qt::Key_Tab); + QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("")); + testContext.infos.clear(); +} + void tst_QWebEngineView::inputMethods() { QWebEngineView view; |