From ef1d61a3516182b0a39330b5ac5988f92c82bc4f Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Tue, 3 Oct 2017 13:14:58 +0200 Subject: Pass editor shortcuts to Chromium by ForwardKeyboardEventWithCommands Moreover, extend the list of supported editor shortcuts and stabilize the corresponding auto test. Task-number: QTBUG-54692 Task-number: QTBUG-54812 Task-number: QTBUG-54221 Task-number: QTBUG-59053 Change-Id: I4dd8230519639ea6e3340992dbb54a609ecfcd91 Reviewed-by: Alexandru Croitor --- src/core/core_chromium.pri | 1 - src/core/render_widget_host_view_qt.cpp | 102 +++++++++++++++++++ src/core/render_widget_host_view_qt.h | 2 + src/core/render_widget_host_view_qt_delegate.cpp | 113 --------------------- src/core/render_widget_host_view_qt_delegate.h | 2 - src/core/web_event_factory.cpp | 80 +++++++++++++++ src/core/web_event_factory.h | 1 + src/webengine/api/qquickwebengineview.cpp | 33 ------ .../render_widget_host_view_qt_delegate_quick.cpp | 2 +- src/webenginewidgets/api/qwebenginepage.cpp | 13 --- .../render_widget_host_view_qt_delegate_widget.cpp | 7 +- tests/auto/widgets/qwebengineview/BLACKLIST | 3 - .../widgets/qwebengineview/tst_qwebengineview.cpp | 34 ++++--- 13 files changed, 208 insertions(+), 185 deletions(-) delete mode 100644 src/core/render_widget_host_view_qt_delegate.cpp diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index 71f74f51a..8e24645f0 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -79,7 +79,6 @@ SOURCES = \ qrc_protocol_handler_qt.cpp \ render_view_observer_host_qt.cpp \ render_widget_host_view_qt.cpp \ - render_widget_host_view_qt_delegate.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/render_frame_observer_qt.cpp \ renderer/render_view_observer_qt.cpp \ diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index a45383946..0f071f89e 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -73,6 +73,7 @@ #include "ui/events/event.h" #include "ui/events/gesture_detection/gesture_provider_config_helper.h" #include "ui/events/gesture_detection/motion_event.h" +#include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/size_conversions.h" #if defined(USE_AURA) @@ -97,6 +98,9 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +#include +#endif #include namespace QtWebEngineCore { @@ -184,6 +188,59 @@ static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, const return lhs.state() < rhs.state(); } +static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + return QInputControl::isCommonTextEditShortcut(ke); +#else + if (ke->modifiers() == Qt::NoModifier + || ke->modifiers() == Qt::ShiftModifier + || ke->modifiers() == Qt::KeypadModifier) { + if (ke->key() < Qt::Key_Escape) { + return true; + } else { + switch (ke->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + case Qt::Key_Delete: + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_Backspace: + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_Tab: + return true; + default: + break; + } + } + } else if (ke->matches(QKeySequence::Copy) + || ke->matches(QKeySequence::Paste) + || ke->matches(QKeySequence::Cut) + || ke->matches(QKeySequence::Redo) + || ke->matches(QKeySequence::Undo) + || ke->matches(QKeySequence::MoveToNextWord) + || ke->matches(QKeySequence::MoveToPreviousWord) + || ke->matches(QKeySequence::MoveToStartOfDocument) + || ke->matches(QKeySequence::MoveToEndOfDocument) + || ke->matches(QKeySequence::SelectNextWord) + || ke->matches(QKeySequence::SelectPreviousWord) + || ke->matches(QKeySequence::SelectStartOfLine) + || ke->matches(QKeySequence::SelectEndOfLine) + || ke->matches(QKeySequence::SelectStartOfBlock) + || ke->matches(QKeySequence::SelectEndOfBlock) + || ke->matches(QKeySequence::SelectStartOfDocument) + || ke->matches(QKeySequence::SelectEndOfDocument) + || ke->matches(QKeySequence::SelectAll) + ) { + return true; + } + return false; +#endif +} + static uint32_t s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: @@ -933,6 +990,41 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) Q_ASSERT(m_host->GetView()); switch (event->type()) { + case QEvent::ShortcutOverride: { + QKeyEvent *keyEvent = static_cast(event); + + auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { +#ifdef Q_OS_MACOS + // Try triggering a registered shortcut + if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(keyEvent)) + return false; + + // The following shortcuts are handled out of input field too but + // disabled on macOS to let the blinking menu handling to the + // embedder application (see kKeyboardCodeKeyDownEntries in + // third_party/WebKit/Source/core/editing/EditingBehavior.cpp). + // Let them pass on macOS to generate the corresponding edit command. + return keyEvent->matches(QKeySequence::Copy) + || keyEvent->matches(QKeySequence::Paste) + || keyEvent->matches(QKeySequence::Cut) + || keyEvent->matches(QKeySequence::SelectAll); +#else + return false; +#endif + }; + + if (!inputMethodQuery(Qt::ImEnabled).toBool() && !acceptKeyOutOfInputField(keyEvent)) + return false; + + Q_ASSERT(m_editCommand.empty()); + if (WebEventFactory::getEditCommand(keyEvent, &m_editCommand) + || isCommonTextEditShortcut(keyEvent)) { + event->accept(); + return true; + } + + return false; + } case QEvent::MouseButtonPress: Focus(); // Fall through. case QEvent::MouseButtonRelease: @@ -1162,6 +1254,16 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) } content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); + if (webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && !m_editCommand.empty()) { + ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); + content::EditCommands commands; + commands.emplace_back(m_editCommand, ""); + m_editCommand.clear(); + m_host->ForwardKeyboardEventWithCommands(webEvent, latency, &commands, nullptr); + return; + } + bool keyDownTextInsertion = webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && webEvent.text[0]; webEvent.skip_in_browser = keyDownTextInsertion; m_host->ForwardKeyboardEvent(webEvent); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 4b7f9094e..8a7665007 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -274,6 +274,8 @@ private: bool m_wheelAckPending; QList m_pendingWheelEvents; + + std::string m_editCommand; }; } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate.cpp b/src/core/render_widget_host_view_qt_delegate.cpp deleted file mode 100644 index a86900433..000000000 --- a/src/core/render_widget_host_view_qt_delegate.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "render_widget_host_view_qt_delegate.h" - -#include -#include - -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) -#include -#endif - -static bool isCommonTextEditShortcut(const QKeyEvent *ke) -{ -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - return QInputControl::isCommonTextEditShortcut(ke); -#else - if (ke->modifiers() == Qt::NoModifier - || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - return true; - } else { - switch (ke->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Tab: - return true; - default: - break; - } - } - } else if (ke->matches(QKeySequence::Copy) - || ke->matches(QKeySequence::Paste) - || ke->matches(QKeySequence::Cut) - || ke->matches(QKeySequence::Redo) - || ke->matches(QKeySequence::Undo) - || ke->matches(QKeySequence::MoveToNextWord) - || ke->matches(QKeySequence::MoveToPreviousWord) - || ke->matches(QKeySequence::MoveToStartOfDocument) - || ke->matches(QKeySequence::MoveToEndOfDocument) - || ke->matches(QKeySequence::SelectNextWord) - || ke->matches(QKeySequence::SelectPreviousWord) - || ke->matches(QKeySequence::SelectStartOfLine) - || ke->matches(QKeySequence::SelectEndOfLine) - || ke->matches(QKeySequence::SelectStartOfBlock) - || ke->matches(QKeySequence::SelectEndOfBlock) - || ke->matches(QKeySequence::SelectStartOfDocument) - || ke->matches(QKeySequence::SelectEndOfDocument) - || ke->matches(QKeySequence::SelectAll) - ) { - return true; - } - return false; -#endif -} - -namespace QtWebEngineCore { - -bool RenderWidgetHostViewQtDelegateClient::handleShortcutOverrideEvent(QKeyEvent *event) -{ - if (inputMethodQuery(Qt::ImEnabled).toBool() && isCommonTextEditShortcut(event)) { - event->accept(); - return true; - } - return false; -} - -} // 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 a126410ed..bcd0f49f7 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -48,7 +48,6 @@ QT_BEGIN_NAMESPACE class QCursor; class QEvent; -class QKeyEvent; class QPainter; class QSGLayer; class QSGNode; @@ -79,7 +78,6 @@ public: virtual void windowChanged() = 0; virtual bool forwardEvent(QEvent *) = 0; virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) = 0; - virtual bool handleShortcutOverrideEvent(QKeyEvent *event); }; class QWEBENGINE_EXPORT RenderWidgetHostViewQtDelegate { diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index c31de19a2..8c997335c 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -1328,3 +1328,83 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e return webKitEvent; } + +bool WebEventFactory::getEditCommand(QKeyEvent *event, std::string *editCommand) +{ + // Assign Qt standard key bindings to blink editor commands. Editor command names + // come from chromium/third_party/WebKit/Source/editing/commands/EditorCommandNames.h + static struct { + QKeySequence::StandardKey standardKey; + std::string name; + } editCommands[] = { + { QKeySequence::Delete, "Delete" }, + { QKeySequence::Cut, "Cut" }, + { QKeySequence::Copy, "Copy" }, + { QKeySequence::Paste, "Paste" }, + { QKeySequence::Undo, "Undo" }, + { QKeySequence::Redo, "Redo" }, + { QKeySequence::SelectAll, "SelectAll" }, + { QKeySequence::Bold, "Bold" }, + { QKeySequence::Italic, "Italic" }, + { QKeySequence::Underline, "Underline" }, + + { QKeySequence::MoveToNextChar, "MoveRight" }, + { QKeySequence::MoveToPreviousChar, "MoveLeft" }, + { QKeySequence::MoveToNextWord, "MoveWordForward" }, + { QKeySequence::MoveToPreviousWord, "MoveWordBackward" }, + { QKeySequence::MoveToNextLine, "MoveDown" }, + { QKeySequence::MoveToPreviousLine, "MoveUp" }, + { QKeySequence::MoveToNextPage, "MovePageDown" }, + { QKeySequence::MoveToPreviousPage, "MovePageUp" }, + { QKeySequence::MoveToStartOfLine, "MoveToBeginningOfLine" }, + { QKeySequence::MoveToEndOfLine, "MoveToEndOfLine" }, + { QKeySequence::MoveToStartOfBlock, "MoveToBeginningOfParagraph" }, + { QKeySequence::MoveToEndOfBlock, "MoveToEndOfParagraph" }, + { QKeySequence::MoveToStartOfDocument, "MoveToBeginningOfDocument" }, + { QKeySequence::MoveToEndOfDocument, "MoveToEndOfDocument" }, + + { QKeySequence::SelectNextChar, "MoveRightAndModifySelection" }, + { QKeySequence::SelectPreviousChar, "MoveLeftAndModifySelection" }, + { QKeySequence::SelectNextWord, "MoveWordForwardAndModifySelection" }, + { QKeySequence::SelectPreviousWord, "MoveWordBackwardAndModifySelection" }, + { QKeySequence::SelectNextLine, "MoveDownAndModifySelection" }, + { QKeySequence::SelectPreviousLine, "MoveUpAndModifySelection" }, + { QKeySequence::SelectNextPage, "MovePageDownAndModifySelection" }, + { QKeySequence::SelectPreviousPage, "MovePageUpAndModifySelection" }, + { QKeySequence::SelectStartOfLine, "MoveToBeginningOfLineAndModifySelection" }, + { QKeySequence::SelectEndOfLine, "MoveToEndOfLineAndModifySelection" }, + { QKeySequence::SelectStartOfBlock, "MoveToBeginningOfParagraphAndModifySelection" }, + { QKeySequence::SelectEndOfBlock, "MoveToEndOfParagraphAndModifySelection" }, + { QKeySequence::SelectStartOfDocument, "MoveToBeginningOfDocumentAndModifySelection" }, + { QKeySequence::SelectEndOfDocument, "MoveToEndOfDocumentAndModifySelection" }, + + { QKeySequence::DeleteStartOfWord, "DeleteWordBackward" }, + { QKeySequence::DeleteEndOfWord, "DeleteWordForward" }, + { QKeySequence::DeleteEndOfLine, "DeleteToEndOfLine" }, + { QKeySequence::Deselect, "Unselect" }, + { QKeySequence::Backspace, "BackwardDelete" }, + + { QKeySequence::UnknownKey, "" } + }; + + for (int i = 0; editCommands[i].standardKey != QKeySequence::UnknownKey; ++i) { + if (event == editCommands[i].standardKey) { + *editCommand = editCommands[i].name; + return true; + } + } + +#ifdef Q_OS_MACOS + Qt::KeyboardModifier cmdKey = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? + Qt::MetaModifier : + Qt::ControlModifier; + if ((event->modifiers() & ~Qt::ShiftModifier) == cmdKey) { + if (event->key() == Qt::Key_Backspace) { + *editCommand = "DeleteToBeginningOfLine"; + return true; + } + } +#endif + + return false; +} diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h index 5758af848..f4ce417cd 100644 --- a/src/core/web_event_factory.h +++ b/src/core/web_event_factory.h @@ -70,6 +70,7 @@ public: static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale); static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale); static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*); + static bool getEditCommand(QKeyEvent *event, std::string *editCommand); }; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 3da21fde5..f5d3646d8 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -94,27 +94,6 @@ QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; -QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event) -{ - static struct { - QKeySequence::StandardKey standardKey; - QQuickWebEngineView::WebAction action; - } editorActions[] = { - { QKeySequence::Cut, QQuickWebEngineView::Cut }, - { QKeySequence::Copy, QQuickWebEngineView::Copy }, - { QKeySequence::Paste, QQuickWebEngineView::Paste }, - { QKeySequence::Undo, QQuickWebEngineView::Undo }, - { QKeySequence::Redo, QQuickWebEngineView::Redo }, - { QKeySequence::SelectAll, QQuickWebEngineView::SelectAll }, - { QKeySequence::UnknownKey, QQuickWebEngineView::NoWebAction } - }; - for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i) - if (event == editorActions[i].standardKey) - return editorActions[i].action; - - return QQuickWebEngineView::NoWebAction; -} - #ifndef QT_NO_ACCESSIBILITY static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object) { @@ -578,18 +557,6 @@ void QQuickWebEngineViewPrivate::focusContainer() void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event) { Q_Q(QQuickWebEngineView); -#ifdef Q_OS_OSX - if (event->type() == QEvent::KeyPress) { - QQuickWebEngineView::WebAction action = editorActionForKeyEvent(event); - if (action != QQuickWebEngineView::NoWebAction) { - // Try triggering a registered short-cut - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event)) - return; - q->triggerWebAction(action); - return; - } - } -#endif if (q->parentItem()) QCoreApplication::sendEvent(q->parentItem(), event); } 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 cde742c39..0e06ddbce 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -225,7 +225,7 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) { if (event->type() == QEvent::ShortcutOverride) - return m_client->handleShortcutOverrideEvent(static_cast(event)); + return m_client->forwardEvent(event); #ifndef QT_NO_GESTURES if (event->type() == QEvent::NativeGesture) diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 76c705c6e..c048a49f4 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -375,19 +375,6 @@ void QWebEnginePagePrivate::focusContainer() void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) { -#ifdef Q_OS_OSX - Q_Q(QWebEnginePage); - if (event->type() == QEvent::KeyPress) { - QWebEnginePage::WebAction action = editorActionForKeyEvent(event); - if (action != QWebEnginePage::NoWebAction) { - // Try triggering a registered short-cut - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event)) - return; - q->triggerAction(action); - return; - } - } -#endif if (view && view->parentWidget()) QGuiApplication::sendEvent(view->parentWidget(), event); } 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 69e1c3038..8dd5c158b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -67,7 +67,8 @@ protected: bool event(QEvent *event) override { if (event->type() == QEvent::ShortcutOverride) - return m_client->handleShortcutOverrideEvent(static_cast(event)); + return m_client->forwardEvent(event); + return QQuickItem::event(event); } void focusInEvent(QFocusEvent *event) override @@ -448,10 +449,6 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) case QEvent::FocusOut: // We forward focus events later, once they have made it to the m_rootItem. return QQuickWidget::event(event); - case QEvent::ShortcutOverride: - if (m_client->handleShortcutOverrideEvent(static_cast(event))) - return true; - break; case QEvent::DragEnter: case QEvent::DragLeave: case QEvent::DragMove: diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST index a2ecd05b7..0a909d0f6 100644 --- a/tests/auto/widgets/qwebengineview/BLACKLIST +++ b/tests/auto/widgets/qwebengineview/BLACKLIST @@ -1,5 +1,2 @@ [doNotSendMouseKeyboardEventsWhenDisabled] windows - -[inputFieldOverridesShortcuts] -osx diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index f46d9f455..c3c8f9b28 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -1487,7 +1487,7 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() view.addAction(action); QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); - view.setHtml(QString("" + view.setHtml(QString("" "" "" "")); @@ -1498,7 +1498,7 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() auto inputFieldValue = [&view] () -> QString { return evaluateJavaScriptSync(view.page(), - "input1.value").toString(); + "document.getElementById('input1').value").toString(); }; // The input form is not focused. The action is triggered on pressing Shift+Delete. @@ -1515,10 +1515,13 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() QCOMPARE(inputFieldValue(), QString("x")); // The input form is focused. The action is not triggered, and the form's text changed. - evaluateJavaScriptSync(view.page(), "input1.focus();"); + evaluateJavaScriptSync(view.page(), "document.getElementById('input1').focus();"); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); actionTriggered = false; QTest::keyClick(view.windowHandle(), Qt::Key_Y); QTRY_COMPARE(inputFieldValue(), QString("yx")); + QTest::keyClick(view.windowHandle(), Qt::Key_X); + QTRY_COMPARE(inputFieldValue(), QString("yxx")); QVERIFY(!actionTriggered); // The input form is focused. Make sure we don't override all short cuts. @@ -1526,10 +1529,20 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() action->setShortcut(Qt::CTRL + Qt::Key_1); QTest::keyClick(view.windowHandle(), Qt::Key_1, Qt::ControlModifier); QTRY_VERIFY(actionTriggered); - QCOMPARE(inputFieldValue(), QString("yx")); + QCOMPARE(inputFieldValue(), QString("yxx")); + + // The input form is focused. The following shortcuts are not overridden + // thus handled by Qt WebEngine. Make sure the subsequent shortcuts with text + // character don't cause assert due to an unconsumed editor command. + QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier); + QTest::keyClick(view.windowHandle(), Qt::Key_C, Qt::ControlModifier); + QTest::keyClick(view.windowHandle(), Qt::Key_V, Qt::ControlModifier); + QTest::keyClick(view.windowHandle(), Qt::Key_V, Qt::ControlModifier); + QTRY_COMPARE(inputFieldValue(), QString("yxxyxx")); // Remove focus from the input field. A QKeySequence::Copy action must be triggerable. evaluateJavaScriptSync(view.page(), "document.getElementById('btn1').focus();"); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("btn1")); action->setShortcut(QKeySequence::Copy); actionTriggered = false; QTest::keyClick(view.windowHandle(), Qt::Key_C, Qt::ControlModifier); @@ -1824,13 +1837,8 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QVERIFY(!view.hasSelection()); QVERIFY(view.page()->selectedText().isEmpty()); - // Workaround for macOS: press ctrl+a without key text - QKeyEvent keyPressCtrlA(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier); - QKeyEvent keyReleaseCtrlA(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier); - // Select text by ctrl+a - QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA); - QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA); + QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 1); QVERIFY(view.hasSelection()); @@ -1860,8 +1868,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); // Select the whole page by ctrl+a - QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA); - QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA); + QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 1); QVERIFY(view.hasSelection()); @@ -1877,8 +1884,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QVERIFY(view.page()->selectedText().isEmpty()); // Select the content of the input field by ctrl+a - QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA); - QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA); + QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 3); QVERIFY(view.hasSelection()); -- cgit v1.2.3