diff options
| author | Peter Varga <pvarga@inf.u-szeged.hu> | 2025-10-31 09:02:01 +0100 |
|---|---|---|
| committer | Peter Varga <pvarga@inf.u-szeged.hu> | 2025-11-06 10:08:32 +0100 |
| commit | 2ebb596b43346c5bf93fc9a460e241a812313c0e (patch) | |
| tree | 50423531353ab099d57f93ddfa838dc81c320fe7 | |
| parent | 88a3ad6ffcb2c374f80cf48b73469a5110560617 (diff) | |
Add HTML inputmode global attribute support
[ChangeLog][QtWebEngineCore] Added HTML inputmode global attribute
support
Fixes: QTBUG-141573
Change-Id: I40bdbb39b89fc9dc1a5d7a76a6210ec8c2f48372
Reviewed-by: Moss Heim <moss.heim@qt.io>
| -rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 114 | ||||
| -rw-r--r-- | src/core/render_widget_host_view_qt.h | 6 | ||||
| -rw-r--r-- | src/core/render_widget_host_view_qt_delegate_client.cpp | 26 | ||||
| -rw-r--r-- | src/core/touch_selection_controller_client_qt.cpp | 7 | ||||
| -rw-r--r-- | src/core/type_conversion.cpp | 36 | ||||
| -rw-r--r-- | src/core/type_conversion.h | 3 | ||||
| -rw-r--r-- | tests/auto/widgets/qwebengineview/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tests/auto/widgets/qwebengineview/resources/input_modes.html | 32 | ||||
| -rw-r--r-- | tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp | 84 |
9 files changed, 236 insertions, 73 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 83cfd1a83..7ca0e621a 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -73,6 +73,15 @@ enum ImStateFlags { AllFlags = TextInputStateUpdated | TextSelectionUpdated | TextSelectionBoundsUpdated }; +static inline bool isEditableField(content::TextInputManager *text_input_manager) +{ + if (!text_input_manager) + return false; + + const auto *state = text_input_manager->GetTextInputState(); + return state ? state->type != ui::TEXT_INPUT_TYPE_NONE : false; +} + static inline ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) { ui::LatencyInfo latency_info; // The latency number should only be added if the timestamp is valid. @@ -196,8 +205,8 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt() QObject::disconnect(m_adapterClientDestroyedConnection); - if (text_input_manager_) - text_input_manager_->RemoveObserver(this); + if (GetTextInputManager()) + GetTextInputManager()->RemoveObserver(this); if (host()->delegate()) m_touchSelectionControllerClient->resetControls(); @@ -666,19 +675,18 @@ gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow() void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view, bool did_update_state) { - Q_UNUSED(text_input_manager); Q_UNUSED(updated_view); Q_UNUSED(did_update_state); - const ui::mojom::TextInputState *state = text_input_manager_->GetTextInputState(); + const ui::mojom::TextInputState *state = text_input_manager->GetTextInputState(); if (!state) { // Do not reset input method state here because an editable node might be still focused and // this would hide the virtual keyboard if a child of the focused node is removed. return; } - ui::TextInputType type = getTextInputType(); - m_delegate->setInputMethodHints(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); + m_delegate->setInputMethodHints(inputMethodHints()); + QString surroundingText = toQt(state->value); // Remove IME composition text from the surrounding text if (state->composition.has_value()) @@ -693,7 +701,8 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana } else { delegateClient()->setCursorPosition(state->selection.start()); } - m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE, type == ui::TEXT_INPUT_TYPE_PASSWORD); + m_delegate->inputMethodStateChanged(state->type != ui::TEXT_INPUT_TYPE_NONE, + state->type == ui::TEXT_INPUT_TYPE_PASSWORD); } if (m_imState & ImStateFlags::TextInputStateUpdated) { @@ -714,19 +723,18 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana void RenderWidgetHostViewQt::OnSelectionBoundsChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) { - Q_UNUSED(text_input_manager); Q_UNUSED(updated_view); m_imState |= ImStateFlags::TextSelectionBoundsUpdated; if (m_imState == ImStateFlags::AllFlags - || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { + || (m_imState == ImStateFlags::TextSelectionFlags + && !isEditableField(text_input_manager))) { delegateClient()->selectionChanged(); } } void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) { - Q_UNUSED(text_input_manager); Q_UNUSED(updated_view); // We obtain the TextSelection from focused RWH which is obtained from the @@ -739,7 +747,8 @@ void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *t #if BUILDFLAG(IS_OZONE) if (ui::Clipboard::IsSupportedClipboardBuffer(ui::ClipboardBuffer::kSelection)) { - const content::TextInputManager::TextSelection *selection = GetTextInputManager()->GetTextSelection(focused_view); + const content::TextInputManager::TextSelection *selection = + text_input_manager->GetTextSelection(focused_view); if (selection->selected_text().length() && selection->user_initiated()) { // Set the ClipboardBuffer::kSelection to the ui::Clipboard. ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kSelection); @@ -750,7 +759,8 @@ void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *t m_imState |= ImStateFlags::TextSelectionUpdated; if (m_imState == ImStateFlags::AllFlags - || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { + || (m_imState == ImStateFlags::TextSelectionFlags + && !isEditableField(text_input_manager))) { delegateClient()->selectionChanged(); } } @@ -858,6 +868,78 @@ void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEve host()->delegate()->GetInputEventRouter()->RouteTouchEvent(this, &touchEvent, CreateLatencyInfo(touchEvent)); } +Qt::InputMethodHints RenderWidgetHostViewQt::inputMethodHints() const +{ + const Qt::InputMethodHints kBaseHints = + Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu; + + const auto *state = getTextInputState(); + ui::TextInputType type = state ? state->type : ui::TEXT_INPUT_TYPE_NONE; + ui::TextInputMode mode = state ? state->mode : ui::TEXT_INPUT_MODE_NONE; + + auto inputTypeToHints = [](ui::TextInputType type) -> Qt::InputMethodHints { + switch (type) { + case ui::TEXT_INPUT_TYPE_TEXT: + return Qt::ImhPreferLowercase; + case ui::TEXT_INPUT_TYPE_PASSWORD: + return Qt::ImhSensitiveData | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText; + case ui::TEXT_INPUT_TYPE_SEARCH: + return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_TYPE_EMAIL: + return Qt::ImhEmailCharactersOnly; + case ui::TEXT_INPUT_TYPE_NUMBER: + return Qt::ImhFormattedNumbersOnly; + case ui::TEXT_INPUT_TYPE_TELEPHONE: + return Qt::ImhDialableCharactersOnly; + case ui::TEXT_INPUT_TYPE_URL: + return Qt::ImhUrlCharactersOnly | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_TYPE_DATE_TIME: + case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: + return Qt::ImhDate | Qt::ImhTime; + case ui::TEXT_INPUT_TYPE_DATE: + case ui::TEXT_INPUT_TYPE_MONTH: + case ui::TEXT_INPUT_TYPE_WEEK: + return Qt::ImhDate; + case ui::TEXT_INPUT_TYPE_TIME: + return Qt::ImhTime; + case ui::TEXT_INPUT_TYPE_TEXT_AREA: + case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: + return Qt::ImhMultiLine | Qt::ImhPreferLowercase; + case ui::TEXT_INPUT_TYPE_NONE: + // Hide virtual keyboard, + // handled by RenderWidgetHostViewQtDelegateClient::inputMethodQuery(). + return Qt::ImhNone; + case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: + case ui::TEXT_INPUT_TYPE_NULL: + return Qt::ImhNone; + } + }; + + switch (mode) { + case ui::TEXT_INPUT_MODE_DEFAULT: + // No explicit inputmode, fall back to <input> type. + return kBaseHints | inputTypeToHints(type); + case ui::TEXT_INPUT_MODE_NONE: + // Hide virtual keyboard, + // handled by RenderWidgetHostViewQtDelegateClient::inputMethodQuery(). + return kBaseHints; + case ui::TEXT_INPUT_MODE_TEXT: + return kBaseHints | Qt::ImhPreferLowercase; + case ui::TEXT_INPUT_MODE_TEL: + return kBaseHints | Qt::ImhDialableCharactersOnly; + case ui::TEXT_INPUT_MODE_URL: + return kBaseHints | Qt::ImhUrlCharactersOnly | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_MODE_EMAIL: + return kBaseHints | Qt::ImhEmailCharactersOnly; + case ui::TEXT_INPUT_MODE_NUMERIC: + return kBaseHints | Qt::ImhDigitsOnly; + case ui::TEXT_INPUT_MODE_DECIMAL: + return kBaseHints | Qt::ImhFormattedNumbersOnly; + case ui::TEXT_INPUT_MODE_SEARCH: + return kBaseHints | Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; + } +} + bool RenderWidgetHostViewQt::isPopup() const { return widget_type_ == content::WidgetType::kPopup; @@ -951,14 +1033,6 @@ blink::mojom::FrameWidgetInputHandler *RenderWidgetHostViewQt::getFrameWidgetInp return focused_widget->GetFrameWidgetInputHandler(); } -ui::TextInputType RenderWidgetHostViewQt::getTextInputType() const -{ - if (text_input_manager_ && text_input_manager_->GetTextInputState()) - return text_input_manager_->GetTextInputState()->type; - - return ui::TEXT_INPUT_TYPE_NONE; -} - viz::SurfaceId RenderWidgetHostViewQt::GetCurrentSurfaceId() const { return m_delegatedFrameHost->GetCurrentSurfaceId(); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index ba387e056..948103173 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -171,6 +171,11 @@ public: void handleWheelEvent(QWheelEvent *); void processMotionEvent(const ui::MotionEvent &motionEvent); void resetInputManagerState() { m_imState = 0; } + const ui::mojom::TextInputState *getTextInputState() const + { + return text_input_manager_ ? text_input_manager_->GetTextInputState() : nullptr; + } + Qt::InputMethodHints inputMethodHints() const; // Called from WebContentsAdapter. gfx::SizeF lastContentsSize() const { return m_lastContentsSize; } @@ -179,7 +184,6 @@ public: ui::TouchSelectionController *getTouchSelectionController() const { return m_touchSelectionController.get(); } TouchSelectionControllerClientQt *getTouchSelectionControllerClient() const { return m_touchSelectionControllerClient.get(); } blink::mojom::FrameWidgetInputHandler *getFrameWidgetInputHandler(); - ui::TextInputType getTextInputType() const; void synchronizeVisualProperties( const std::optional<viz::LocalSurfaceId> &childSurfaceId); diff --git a/src/core/render_widget_host_view_qt_delegate_client.cpp b/src/core/render_widget_host_view_qt_delegate_client.cpp index 62e2e5bd0..c62e77df7 100644 --- a/src/core/render_widget_host_view_qt_delegate_client.cpp +++ b/src/core/render_widget_host_view_qt_delegate_client.cpp @@ -356,7 +356,11 @@ QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQ { switch (query) { case Qt::ImEnabled: - return QVariant(m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_NONE); + if (const auto *state = m_rwhv->getTextInputState()) { + return QVariant(state->mode != ui::TEXT_INPUT_MODE_NONE + && state->type != ui::TEXT_INPUT_TYPE_NONE); + } + return QVariant(false); case Qt::ImFont: // TODO: Implement this return QVariant(); @@ -388,8 +392,7 @@ QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQ // TODO: Implement this return QVariant(); // No limit. case Qt::ImHints: - return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText - | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); + return static_cast<int>(m_rwhv->inputMethodHints()); default: return QVariant(); } @@ -920,10 +923,12 @@ void RenderWidgetHostViewQtDelegateClient::clearPreviousTouchMotionState() void RenderWidgetHostViewQtDelegateClient::selectionChanged() { m_rwhv->resetInputManagerState(); - ui::TextInputType type = m_rwhv->getTextInputType(); - content::TextInputManager *text_input_manager = m_rwhv->GetTextInputManager(); - // Handle text selection out of an input field + const content::TextInputManager *manager = m_rwhv->GetTextInputManager(); + const ui::mojom::TextInputState *state = m_rwhv->getTextInputState(); + ui::TextInputType type = state ? state->type : ui::TEXT_INPUT_TYPE_NONE; + + // Handle text selection out of an editable field if (type == ui::TEXT_INPUT_TYPE_NONE) { if (m_rwhv->GetSelectedText().empty() && m_emptyPreviousSelection) return; @@ -943,8 +948,8 @@ void RenderWidgetHostViewQtDelegateClient::selectionChanged() // RenderWidgetHostViewQt::OnUpdateTextInputStateCalled() does not update the cursor // position 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(); + Q_ASSERT(state); + m_cursorPosition = state->selection.start(); m_rwhv->delegate()->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); @@ -959,8 +964,7 @@ void RenderWidgetHostViewQtDelegateClient::selectionChanged() return; } - const content::TextInputManager::TextSelection *selection = - text_input_manager->GetTextSelection(); + const content::TextInputManager::TextSelection *selection = manager->GetTextSelection(); if (!selection) return; @@ -970,7 +974,7 @@ void RenderWidgetHostViewQtDelegateClient::selectionChanged() int newAnchorPositionWithinSelection = 0; int newCursorPositionWithinSelection = 0; - if (text_input_manager->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { + if (manager->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { newAnchorPositionWithinSelection = selection->range().GetMax() - selection->offset(); newCursorPositionWithinSelection = selection->range().GetMin() - selection->offset(); } else { diff --git a/src/core/touch_selection_controller_client_qt.cpp b/src/core/touch_selection_controller_client_qt.cpp index 9a2596a0b..2b023e915 100644 --- a/src/core/touch_selection_controller_client_qt.cpp +++ b/src/core/touch_selection_controller_client_qt.cpp @@ -87,8 +87,11 @@ void TouchSelectionControllerClientQt::onScrollEnd() bool TouchSelectionControllerClientQt::IsCommandIdEnabled(int command_id) const { - bool editable = m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_NONE; - bool readable = m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD; + const ui::mojom::TextInputState *state = m_rwhv->getTextInputState(); + ui::TextInputType type = state ? state->type : ui::TEXT_INPUT_TYPE_NONE; + + bool editable = type != ui::TEXT_INPUT_TYPE_NONE; + bool readable = type != ui::TEXT_INPUT_TYPE_PASSWORD; bool hasSelection = !m_rwhv->GetSelectedText().empty(); switch (command_id) { diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index b7d724f84..b40bb99e5 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -292,40 +292,4 @@ QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate) return chain; } -Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType) -{ - switch (inputType) { - case ui::TEXT_INPUT_TYPE_TEXT: - return Qt::ImhPreferLowercase; - case ui::TEXT_INPUT_TYPE_SEARCH: - return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; - case ui::TEXT_INPUT_TYPE_PASSWORD: - return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase - | Qt::ImhHiddenText; - case ui::TEXT_INPUT_TYPE_EMAIL: - return Qt::ImhEmailCharactersOnly; - case ui::TEXT_INPUT_TYPE_NUMBER: - return Qt::ImhFormattedNumbersOnly; - case ui::TEXT_INPUT_TYPE_TELEPHONE: - return Qt::ImhDialableCharactersOnly; - case ui::TEXT_INPUT_TYPE_URL: - return Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase; - case ui::TEXT_INPUT_TYPE_DATE_TIME: - case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: - case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: - return Qt::ImhDate | Qt::ImhTime; - case ui::TEXT_INPUT_TYPE_DATE: - case ui::TEXT_INPUT_TYPE_MONTH: - case ui::TEXT_INPUT_TYPE_WEEK: - return Qt::ImhDate; - case ui::TEXT_INPUT_TYPE_TIME: - return Qt::ImhTime; - case ui::TEXT_INPUT_TYPE_TEXT_AREA: - case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: - return Qt::ImhMultiLine | Qt::ImhPreferLowercase; - default: - return Qt::ImhNone; - } -} - } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 705c74fa3..af75c9ff5 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -21,7 +21,6 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPixelRef.h" -#include "ui/base/ime/text_input_type.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" @@ -263,8 +262,6 @@ inline QStringList fromVector(const std::vector<std::u16string> &vector) QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate); -Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType); - } // namespace QtWebEngineCore #endif // TYPE_CONVERSION_H diff --git a/tests/auto/widgets/qwebengineview/CMakeLists.txt b/tests/auto/widgets/qwebengineview/CMakeLists.txt index 9583184d0..75e78afcc 100644 --- a/tests/auto/widgets/qwebengineview/CMakeLists.txt +++ b/tests/auto/widgets/qwebengineview/CMakeLists.txt @@ -20,6 +20,7 @@ set(tst_qwebengineview_resource_files "resources/frame_a.html" "resources/image2.png" "resources/index.html" + "resources/input_modes.html" "resources/input_types.html" "resources/keyboardEvents.html" "resources/scrolltest_page.html" diff --git a/tests/auto/widgets/qwebengineview/resources/input_modes.html b/tests/auto/widgets/qwebengineview/resources/input_modes.html new file mode 100644 index 000000000..857bea8b1 --- /dev/null +++ b/tests/auto/widgets/qwebengineview/resources/input_modes.html @@ -0,0 +1,32 @@ +<html> +<head><style> +input { + position: relative; + left: 10px; + width: 100px; + height: 50px; + margin: 10px 0; + font-size: 16px; + padding: 5px; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + display: block; +} +</style></head> + +<body> +<input inputmode="none" id="noneMode"> + +<input inputmode="text" id="textMode"> +<input inputmode="tel" id="telMode"> +<input inputmode="url" id="urlMode"> +<input inputmode="email" id="emailMode"> +<input inputmode="numeric" id="numericMode"> +<input inputmode="decimal" id="decimalMode"> +<input inputmode="search" id="searchMode"> + +<input type="text" inputmode="numeric" id="override"> +</body> + +</html> diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 32548df61..bf92dbe4e 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -55,6 +55,8 @@ #include <QtCore/qregularexpression.h> #include <QtTest/private/qemulationdetector_p.h> +using namespace Qt::StringLiterals; + #define VERIFY_INPUTMETHOD_HINTS(actual, expect) \ QVERIFY(actual == (expect | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu)); @@ -114,6 +116,7 @@ private Q_SLOTS: void setLoadedPage(); void microFocusCoordinates(); void focusInputTypes(); + void inputModes(); void unhandledKeyEventPropagation(); void horizontalScrollbarTest(); @@ -713,6 +716,87 @@ void tst_QWebEngineView::focusInputTypes() QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); } +void tst_QWebEngineView::inputModes() +{ + QWebEngineView webView; + webView.resize(200, 600); + webView.show(); + QVERIFY(QTest::qWaitForWindowExposed(&webView)); + + QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool))); + webView.load(QUrl(u"qrc:///resources/input_modes.html"_s)); + QVERIFY(loadFinishedSpy.wait()); + + auto inputMethodQuery = [&webView](Qt::InputMethodQuery query) { + QInputMethodQueryEvent event(query); + QApplication::sendEvent(webView.focusProxy(), &event); + return event.value(query); + }; + + // inputmode=none + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"noneMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"noneMode"_s); + // Should not trigger the virtual keyboard. + QTRY_VERIFY(!inputMethodQuery(Qt::ImEnabled).toBool()); + + // inputmode=text + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"textMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"textMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); + + // inputmode=tel + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"telMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"telMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), + Qt::ImhDialableCharactersOnly); + + // inputmode=url + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"urlMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"urlMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), + Qt::ImhUrlCharactersOnly | Qt::ImhNoAutoUppercase); + + // inputmode=email + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"emailMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"emailMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhEmailCharactersOnly); + + // inputmode=numeric + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"numericMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"numericMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDigitsOnly); + + // inputmode=decimal + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"decimalMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"decimalMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhFormattedNumbersOnly); + + // inputmode=search + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"searchMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"searchMode"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), + Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase); + + // inputmode=none + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"noneMode"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"noneMode"_s); + // Should hide the virtual keyboard. + QTRY_VERIFY(!inputMethodQuery(Qt::ImEnabled).toBool()); + + // inputmode=numeric overrides <input type="text"> + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, elementCenter(webView.page(), u"override"_s)); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), u"document.activeElement.id"_s).toString(), u"override"_s); + QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDigitsOnly); +} + class KeyEventRecordingWidget : public QWidget { public: ~KeyEventRecordingWidget() { qDeleteAll(pressEvents); qDeleteAll(releaseEvents); } |
