From 64a5f315206fac2316e0b4a5a65a5d1f66b1a219 Mon Sep 17 00:00:00 2001 From: Peter Varga <pvarga@inf.u-szeged.hu> Date: Tue, 12 Sep 2017 15:48:45 +0200 Subject: [PATCH] Disable IME on password input Task-number: QTBUG-62433 Change-Id: Icdc3355ca9d1ec4fb25d512c56c19aca94ae8928 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> --- src/core/render_widget_host_view_qt.cpp | 20 +++++++++++--- src/core/render_widget_host_view_qt.h | 2 ++ .../render_widget_host_view_qt_delegate.h | 2 +- ...der_widget_host_view_qt_delegate_quick.cpp | 10 ++++--- ...ender_widget_host_view_qt_delegate_quick.h | 3 ++- ...widget_host_view_qt_delegate_quickwindow.h | 2 +- ...er_widget_host_view_qt_delegate_widget.cpp | 9 ++++--- ...nder_widget_host_view_qt_delegate_widget.h | 3 ++- .../qwebengineview/tst_qwebengineview.cpp | 27 ++++++++++++++++--- 9 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 136371a91..655871c9c 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -77,6 +77,9 @@ #include "ui/base/cursor/cursors_aura.h" #endif +#include <private/qguiapplication_p.h> +#include <qpa/qplatforminputcontext.h> +#include <qpa/qplatformintegration.h> #include <QEvent> #include <QFocusEvent> #include <QGuiApplication> @@ -292,6 +295,9 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget if (GetTextInputManager()) GetTextInputManager()->AddObserver(this); + + const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); + m_imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); } RenderWidgetHostViewQt::~RenderWidgetHostViewQt() @@ -735,7 +741,7 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana Q_UNUSED(did_update_state); ui::TextInputType type = getTextInputType(); - m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE); + 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(); @@ -973,8 +979,16 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) { switch (query) { - case Qt::ImEnabled: - return QVariant(getTextInputType() != ui::TEXT_INPUT_TYPE_NONE); + case Qt::ImEnabled: { + ui::TextInputType type = getTextInputType(); + bool editorVisible = type != ui::TEXT_INPUT_TYPE_NONE; + // IME manager should disable composition on input fields with ImhHiddenText hint if supported + if (m_imeHasHiddenTextCapability) + return QVariant(editorVisible); + + bool passwordInput = type == ui::TEXT_INPUT_TYPE_PASSWORD; + return QVariant(editorVisible && !passwordInput); + } case Qt::ImFont: // TODO: Implement this return QVariant(); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 63efad87e..0db5df862 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -270,6 +270,8 @@ private: uint m_cursorPosition; bool m_emptyPreviousSelection; QString m_surroundingText; + + bool m_imeHasHiddenTextCapability; }; } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 7461e7608..a126410ed 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -106,7 +106,7 @@ public: virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; virtual void move(const QPoint &) = 0; - virtual void inputMethodStateChanged(bool editorVisible) = 0; + virtual void inputMethodStateChanged(bool editorVisible, bool passwordInput) = 0; virtual void setInputMethodHints(Qt::InputMethodHints hints) = 0; virtual void setClearColor(const QColor &color) = 0; }; 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 e9abec02e..cde742c39 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -54,6 +54,7 @@ namespace QtWebEngineCore { RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup) : m_client(client) , m_isPopup(isPopup) + , m_isPasswordInput(false) , m_initialized(false) { setFlag(ItemHasContents); @@ -207,16 +208,17 @@ void RenderWidgetHostViewQtDelegateQuick::resize(int width, int height) setSize(QSizeF(width, height)); } -void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVisible) +void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVisible, bool passwordInput) { - setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible); + setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible && !passwordInput); if (parentItem()) - parentItem()->setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible); + parentItem()->setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible && !passwordInput); - if (qApp->inputMethod()->isVisible() != editorVisible) { + if (qApp->inputMethod()->isVisible() != editorVisible || m_isPasswordInput != passwordInput) { qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); qApp->inputMethod()->setVisible(editorVisible); + m_isPasswordInput = passwordInput; } } 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 7a08e915b..d93fd539a 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -73,7 +73,7 @@ public: virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint&) Q_DECL_OVERRIDE { } - virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; + virtual void inputMethodStateChanged(bool editorVisible, bool isPasswordInput) Q_DECL_OVERRIDE; virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE { } // The QtQuick view doesn't have a backbuffer of its own and doesn't need this virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } @@ -104,6 +104,7 @@ private: RenderWidgetHostViewQtDelegateClient *m_client; QList<QMetaObject::Connection> m_windowConnections; bool m_isPopup; + bool m_isPasswordInput; bool m_initialized; QPoint m_lastGlobalPos; }; diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index 057b91c75..6244ee6ce 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -76,7 +76,7 @@ public: virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; - virtual void inputMethodStateChanged(bool) Q_DECL_OVERRIDE {} + virtual void inputMethodStateChanged(bool, bool) Q_DECL_OVERRIDE {} virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE { } virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } 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 4de425c5b..69e1c3038 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -108,6 +108,7 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende , m_client(client) , m_rootItem(new RenderWidgetHostViewQuickItem(client)) , m_isPopup(false) + , m_isPasswordInput(false) { setFocusPolicy(Qt::StrongFocus); @@ -340,12 +341,14 @@ void RenderWidgetHostViewQtDelegateWidget::move(const QPoint &screenPos) QQuickWidget::move(screenPos); } -void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVisible) +void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVisible, bool passwordInput) { - if (qApp->inputMethod()->isVisible() == editorVisible) + if (qApp->inputMethod()->isVisible() == editorVisible && m_isPasswordInput == passwordInput) return; - QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, editorVisible); + QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, editorVisible && !passwordInput); + m_isPasswordInput = passwordInput; + qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); qApp->inputMethod()->setVisible(editorVisible); } 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 fb33c55c7..f3e9da2cc 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -74,7 +74,7 @@ public: virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; - virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; + virtual void inputMethodStateChanged(bool editorVisible, bool passwordInput) Q_DECL_OVERRIDE; virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE; virtual void setClearColor(const QColor &color) Q_DECL_OVERRIDE; @@ -94,6 +94,7 @@ 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/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 6f0c8f164..f46590bdf 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -364,6 +364,9 @@ void tst_QWebEngineView::microFocusCoordinates() void tst_QWebEngineView::focusInputTypes() { + const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); + bool imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); + QWebEngineView webView; webView.show(); QTest::qWaitForWindowExposed(&webView); @@ -372,19 +375,27 @@ void tst_QWebEngineView::focusInputTypes() webView.load(QUrl("qrc:///resources/input_types.html")); QVERIFY(loadFinishedSpy.wait()); + auto inputMethodQuery = [&webView](Qt::InputMethodQuery query) { + QInputMethodQueryEvent event(query); + QApplication::sendEvent(webView.focusProxy(), &event); + return event.value(query); + }; + // 'text' field QPoint textInputCenter = elementCenter(webView.page(), "textInput"); QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'password' field QPoint passwordInputCenter = elementCenter(webView.page(), "passwordInput"); QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); - QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability); // 'tel' field QPoint telInputCenter = elementCenter(webView.page(), "telInput"); @@ -392,6 +403,7 @@ void tst_QWebEngineView::focusInputTypes() QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("telInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDialableCharactersOnly); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'number' field QPoint numberInputCenter = elementCenter(webView.page(), "numberInput"); @@ -399,6 +411,7 @@ void tst_QWebEngineView::focusInputTypes() QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("numberInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhFormattedNumbersOnly); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'email' field QPoint emailInputCenter = elementCenter(webView.page(), "emailInput"); @@ -406,6 +419,7 @@ void tst_QWebEngineView::focusInputTypes() QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("emailInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhEmailCharactersOnly); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'url' field QPoint urlInputCenter = elementCenter(webView.page(), "urlInput"); @@ -413,24 +427,28 @@ void tst_QWebEngineView::focusInputTypes() QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("urlInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase)); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'password' field QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); - QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability); // 'text' type QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'password' field QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); - QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability); // 'text area' field QPoint textAreaCenter = elementCenter(webView.page(), "textArea"); @@ -438,6 +456,7 @@ void tst_QWebEngineView::focusInputTypes() QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textArea")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhMultiLine | Qt::ImhPreferLowercase)); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); } class KeyEventRecordingWidget : public QWidget { @@ -1885,7 +1904,7 @@ void tst_QWebEngineView::hiddenText() QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("password1")); - QVERIFY(view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QVERIFY(!view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); QVERIFY(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText); QPoint textInputCenter = elementCenter(view.page(), "input1"); -- GitLab