diff options
author | Peter Varga <pvarga@inf.u-szeged.hu> | 2016-12-20 09:32:25 +0100 |
---|---|---|
committer | Peter Varga <pvarga@inf.u-szeged.hu> | 2017-01-25 15:14:38 +0000 |
commit | 4501b9d88662e590e14dd932a43de9055cde012c (patch) | |
tree | b9259d152d4f3f089cabb6ee39cb224e37e4663b | |
parent | eb5569186b126e7ffc507a14efd502fac32f7fb9 (diff) |
Fix confirming IME composition and newline insertion
Task-number: QTBUG-55766
Change-Id: I3be3b224dfef9ecc1ce39f4f20ec5c1d13c0fa69
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 58 | ||||
-rw-r--r-- | src/core/render_widget_host_view_qt.h | 2 | ||||
-rw-r--r-- | src/core/web_event_factory.cpp | 9 | ||||
-rw-r--r-- | tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp | 83 | ||||
-rw-r--r-- | tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp | 100 |
5 files changed, 148 insertions, 104 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 813bbe0d7..80337446f 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -576,6 +576,8 @@ void RenderWidgetHostViewQt::TextInputStateChanged(const content::TextInputState m_currentInputType = params.type; m_delegate->inputMethodStateChanged(params.type != ui::TEXT_INPUT_TYPE_NONE); m_delegate->setInputMethodHints(toQtInputMethodHints(params.type)); + + m_surroundingText = QString::fromStdString(params.value); } void RenderWidgetHostViewQt::ImeCancelComposition() @@ -837,7 +839,7 @@ QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) co case Qt::ImAnchorPosition: return static_cast<uint>(m_anchorPositionWithinSelection); case Qt::ImSurroundingText: - return toQt(selection_text_); + return m_surroundingText; case Qt::ImCurrentSelection: return toQt(GetSelectedText()); case Qt::ImMaximumTextLength: @@ -970,7 +972,13 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) } else { if (ev->type() == QEvent::KeyRelease) { m_receivedEmptyImeText = false; - m_host->ImeConfirmComposition(toString16(ev->text()), gfx::Range::InvalidRange(), + m_host->ImeSetComposition(toString16(ev->text()), + std::vector<blink::WebCompositionUnderline>(), + gfx::Range::InvalidRange(), + gfx::Range::InvalidRange().start(), + gfx::Range::InvalidRange().end()); + m_host->ImeConfirmComposition(base::string16(), + gfx::Range::InvalidRange(), false); m_imeInProgress = false; } @@ -979,17 +987,16 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) } content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); - if (webEvent.type == blink::WebInputEvent::RawKeyDown && !ev->text().isEmpty()) { + bool keyDownTextInsertion = webEvent.type == blink::WebInputEvent::RawKeyDown && webEvent.text[0]; + webEvent.skip_in_browser = keyDownTextInsertion; + m_host->ForwardKeyboardEvent(webEvent); + + if (keyDownTextInsertion) { // Blink won't consume the RawKeyDown, but rather the Char event in this case. // Make sure to skip the former on the way back. The same os_event will be set on both of them. webEvent.skip_in_browser = true; - m_host->ForwardKeyboardEvent(webEvent); - - webEvent.skip_in_browser = false; webEvent.type = blink::WebInputEvent::Char; m_host->ForwardKeyboardEvent(webEvent); - } else { - m_host->ForwardKeyboardEvent(webEvent); } } @@ -1001,9 +1008,6 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) QString commitString = ev->commitString(); QString preeditString = ev->preeditString(); - int replacementStart = ev->replacementStart(); - int replacementLength = ev->replacementLength(); - int cursorPositionInPreeditString = -1; gfx::Range selectionRange = gfx::Range::InvalidRange(); @@ -1066,33 +1070,45 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) } } - gfx::Range replacementRange = (replacementLength > 0) ? gfx::Range(replacementStart, replacementStart + replacementLength) - : gfx::Range::InvalidRange(); + int replacementLength = ev->replacementLength(); + gfx::Range replacementRange = gfx::Range::InvalidRange(); + + if (replacementLength > 0) + { + int start = ev->replacementStart(); + + if (start >= 0) + replacementRange = gfx::Range(start, start + replacementLength); + else if (m_surroundingText.length() + start >= 0) { + start = m_surroundingText.length() + start; + replacementRange = gfx::Range(start, start + replacementLength); + } + } - auto setCompositionForPreEditString = [&](){ + auto setCompositionString = [&](const QString &compositionString){ ensureValidSelectionRange(); - m_host->ImeSetComposition(toString16(preeditString), + m_host->ImeSetComposition(toString16(compositionString), underlines, replacementRange, selectionRange.start(), selectionRange.end()); }; - if (!commitString.isEmpty()) { - m_host->ImeConfirmComposition(toString16(commitString), replacementRange, false); + if (!commitString.isEmpty() || replacementLength > 0) { + setCompositionString(commitString); + m_host->ImeConfirmComposition(base::string16(), gfx::Range::InvalidRange(), false); // We might get a commit string and a pre-edit string in a single event, which means // we need to confirm thećlast composition, and start a new composition. if (!preeditString.isEmpty()) { - setCompositionForPreEditString(); + setCompositionString(preeditString); m_imeInProgress = true; } else { m_imeInProgress = false; } - m_receivedEmptyImeText = false; - + m_receivedEmptyImeText = commitString.isEmpty(); } else if (!preeditString.isEmpty()) { - setCompositionForPreEditString(); + setCompositionString(preeditString); m_imeInProgress = true; m_receivedEmptyImeText = false; } else { diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 0b2d7bc9d..2f5d97b67 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -244,6 +244,8 @@ private: gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; + + QString m_surroundingText; }; } // namespace QtWebEngineCore diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 4f5023376..9681ad629 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -1259,5 +1259,14 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e const ushort* text = ev->text().utf16(); memcpy(&webKitEvent.text, text, std::min(sizeof(webKitEvent.text), size_t(ev->text().length() * 2))); memcpy(&webKitEvent.unmodifiedText, text, std::min(sizeof(webKitEvent.unmodifiedText), size_t(ev->text().length() * 2))); + + if (webKitEvent.windowsKeyCode == VK_RETURN) { + // This is the same behavior as GTK: + // We need to treat the enter key as a key press of character \r. This + // is apparently just how webkit handles it and what it expects. + webKitEvent.unmodifiedText[0] = '\r'; + webKitEvent.text[0] = webKitEvent.unmodifiedText[0]; + } + return webKitEvent; } diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 13412ccba..cde09f5c6 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -2189,89 +2189,6 @@ void tst_QWebEnginePage::inputMethods() variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 12); - - - // START - Newline test for textarea - qApp->processEvents(); - page->setHtml("<html><body>" \ - "<textarea rows='5' cols='1' id='input5' value=''/>" \ - "</body></html>"); - evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input5'); inputEle.focus(); inputEle.select();"); - - // Enter Key without key text - QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - page->event(&keyEnter); - QList<QInputMethodEvent::Attribute> attribs; - - QInputMethodEvent eventText(QString(), attribs); - eventText.setCommitString("\n"); - page->event(&eventText); - - QInputMethodEvent eventText2(QString(), attribs); - eventText2.setCommitString("third line"); - page->event(&eventText2); - qApp->processEvents(); - - QString inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Enter Key with key text '\r' - evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyEnterWithCarriageReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\r"); - page->event(&keyEnterWithCarriageReturn); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Enter Key with key text '\n' - page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyEnterWithLineFeed(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n"); - page->event(&keyEnterWithLineFeed); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Enter Key with key text "\n\r" - page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyEnterWithLFCR(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n\r"); - page->event(&keyEnterWithLFCR); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Return Key without key text - page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyReturn(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); - page->event(&keyReturn); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // END - Newline test for textarea #endif } diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 1160e4580..151b82b61 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -94,6 +94,7 @@ private Q_SLOTS: void softwareInputPanel(); void hiddenText(); void emptyInputMethodEvent(); + void newlineInTextarea(); }; // This will be called before the first test function is executed. @@ -1248,5 +1249,104 @@ void tst_QWebEngineView::emptyInputMethodEvent() QCOMPARE(inputValue, QString("QtWebEngine")); } +void tst_QWebEngineView::newlineInTextarea() +{ + QWebEngineView view; + view.show(); + + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.page()->setHtml("<html><body>" + " <textarea rows='5' cols='1' id='input1'></textarea>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + // Enter Key without key text + QKeyEvent keyPressEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); + QKeyEvent keyReleaseEnter(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::sendEvent(view.focusProxy(), &keyPressEnter); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnter); + + QList<QInputMethodEvent::Attribute> attribs; + + QInputMethodEvent eventText(QString(), attribs); + eventText.setCommitString("\n"); + QApplication::sendEvent(view.focusProxy(), &eventText); + + QInputMethodEvent eventText2(QString(), attribs); + eventText2.setCommitString("third line"); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Enter Key with key text '\r' + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressEnterWithCarriageReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\r"); + QKeyEvent keyReleaseEnterWithCarriageReturn(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::sendEvent(view.focusProxy(), &keyPressEnterWithCarriageReturn); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnterWithCarriageReturn); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Enter Key with key text '\n' + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressEnterWithLineFeed(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n"); + QKeyEvent keyReleaseEnterWithLineFeed(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier, "\n"); + QApplication::sendEvent(view.focusProxy(), &keyPressEnterWithLineFeed); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnterWithLineFeed); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Enter Key with key text "\n\r" + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressEnterWithLFCR(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n\r"); + QKeyEvent keyReleaseEnterWithLFCR(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier, "\n\r"); + QApplication::sendEvent(view.focusProxy(), &keyPressEnterWithLFCR); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnterWithLFCR); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Return Key without key text + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); + QKeyEvent keyReleaseReturn(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::sendEvent(view.focusProxy(), &keyPressReturn); + QApplication::sendEvent(view.focusProxy(), &keyReleaseReturn); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); +} + QTEST_MAIN(tst_QWebEngineView) #include "tst_qwebengineview.moc" |