summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/render_widget_host_view_qt.cpp114
-rw-r--r--src/core/render_widget_host_view_qt.h6
-rw-r--r--src/core/render_widget_host_view_qt_delegate_client.cpp26
-rw-r--r--src/core/touch_selection_controller_client_qt.cpp7
-rw-r--r--src/core/type_conversion.cpp36
-rw-r--r--src/core/type_conversion.h3
-rw-r--r--tests/auto/widgets/qwebengineview/CMakeLists.txt1
-rw-r--r--tests/auto/widgets/qwebengineview/resources/input_modes.html32
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp84
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); }