summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/core_gyp_generator.pro1
-rw-r--r--src/core/native_web_keyboard_event_qt.cpp97
-rw-r--r--src/core/qtwebengine_extras.gypi3
-rw-r--r--src/core/render_widget_host_view_qt.cpp9
-rw-r--r--src/core/web_contents_adapter_client.h2
-rw-r--r--src/core/web_contents_delegate_qt.cpp7
-rw-r--r--src/core/web_contents_delegate_qt.h18
-rw-r--r--src/core/web_event_factory.cpp2
-rw-r--r--src/webengine/api/qquickwebengineview.cpp7
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h1
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp6
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h1
-rw-r--r--tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml95
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp44
14 files changed, 284 insertions, 9 deletions
diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro
index ae2422957..2ec2816c1 100644
--- a/src/core/core_gyp_generator.pro
+++ b/src/core/core_gyp_generator.pro
@@ -54,6 +54,7 @@ SOURCES = \
javascript_dialog_controller.cpp \
javascript_dialog_manager_qt.cpp \
media_capture_devices_dispatcher.cpp \
+ native_web_keyboard_event_qt.cpp \
network_delegate_qt.cpp \
ozone_platform_eglfs.cpp \
process_main.cpp \
diff --git a/src/core/native_web_keyboard_event_qt.cpp b/src/core/native_web_keyboard_event_qt.cpp
new file mode 100644
index 000000000..072b4dd9d
--- /dev/null
+++ b/src/core/native_web_keyboard_event_qt.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/native_web_keyboard_event.h"
+#include <QKeyEvent>
+
+namespace {
+
+// We need to copy |os_event| in NativeWebKeyboardEvent because it is
+// queued in RenderWidgetHost and may be passed and used
+// RenderViewHostDelegate::HandledKeybardEvent after the original aura
+// event is destroyed.
+gfx::NativeEvent CopyEvent(gfx::NativeEvent event)
+{
+ return event ? reinterpret_cast<gfx::NativeEvent>(new QKeyEvent(*reinterpret_cast<QKeyEvent*>(event))) : 0;
+}
+
+void DestroyEvent(gfx::NativeEvent event)
+{
+ delete reinterpret_cast<QKeyEvent*>(event);
+}
+
+} // namespace
+
+using blink::WebKeyboardEvent;
+
+namespace content {
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent()
+ : os_event(0),
+ skip_in_browser(false)
+{
+}
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event)
+ : os_event(CopyEvent(native_event)),
+ skip_in_browser(false)
+{
+}
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& other)
+ : WebKeyboardEvent(other),
+ os_event(CopyEvent(other.os_event)),
+ skip_in_browser(other.skip_in_browser)
+{
+}
+
+NativeWebKeyboardEvent& NativeWebKeyboardEvent::operator=(const NativeWebKeyboardEvent& other) {
+ WebKeyboardEvent::operator=(other);
+ DestroyEvent(os_event);
+ os_event = CopyEvent(other.os_event);
+ skip_in_browser = other.skip_in_browser;
+ return *this;
+}
+
+NativeWebKeyboardEvent::~NativeWebKeyboardEvent() {
+ DestroyEvent(os_event);
+}
+
+} // namespace content
diff --git a/src/core/qtwebengine_extras.gypi b/src/core/qtwebengine_extras.gypi
index 0592df73b..b0e9bc697 100644
--- a/src/core/qtwebengine_extras.gypi
+++ b/src/core/qtwebengine_extras.gypi
@@ -27,6 +27,9 @@
['exclude', 'browser/web_contents/web_contents_view_mac\\.(mm|h)$'],
['exclude', 'browser/web_contents/web_contents_view_win\\.(cc|h)$'],
['exclude', 'browser/renderer_host/gtk_im_context_wrapper\\.cc$'],
+ ['exclude', 'browser/renderer_host/native_web_keyboard_event_android.cc$'],
+ ['exclude', 'browser/renderer_host/native_web_keyboard_event_aura.cc$'],
+ ['exclude', 'browser/renderer_host/native_web_keyboard_event_mac.mm$'],
['exclude', 'browser/renderer_host/pepper/pepper_truetype_font_list_pango\\.cc$'],
['exclude', 'browser/renderer_host/render_widget_host_view_android\\.(cc|h)$'],
['exclude', 'browser/renderer_host/render_widget_host_view_aura\\.(cc|h)$'],
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index bf4d5bf37..3741d8876 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -880,10 +880,17 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev)
UnlockMouse();
content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev);
- m_host->ForwardKeyboardEvent(webEvent);
if (webEvent.type == blink::WebInputEvent::RawKeyDown && !ev->text().isEmpty()) {
+ // 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);
}
}
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index b6d1ef5bb..26d7a03ea 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -46,6 +46,7 @@
#include <QStringList>
#include <QUrl>
+QT_FORWARD_DECLARE_CLASS(QKeyEvent)
QT_FORWARD_DECLARE_CLASS(QVariant)
QT_FORWARD_DECLARE_CLASS(CertificateErrorController)
@@ -154,6 +155,7 @@ public:
virtual void loadVisuallyCommitted() = 0;
virtual void loadFinished(bool success, const QUrl &url, int errorCode = 0, const QString &errorDescription = QString()) = 0;
virtual void focusContainer() = 0;
+ virtual void unhandledKeyEvent(QKeyEvent *event) = 0;
virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry) = 0;
virtual void close() = 0;
virtual bool contextMenuRequested(const WebEngineContextMenuData&) = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index d24b8a2cd..50aafd55e 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -131,6 +131,13 @@ void WebContentsDelegateQt::LoadProgressChanged(content::WebContents* source, do
m_viewClient->loadProgressChanged(qRound(progress * 100));
}
+void WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const content::NativeWebKeyboardEvent &event)
+{
+ Q_ASSERT(!event.skip_in_browser);
+ if (event.os_event)
+ m_viewClient->unhandledKeyEvent(reinterpret_cast<QKeyEvent *>(event.os_event));
+}
+
void WebContentsDelegateQt::DidStartProvisionalLoadForFrame(content::RenderFrameHost* render_frame_host, const GURL& validated_url, bool is_error_page, bool is_iframe_srcdoc)
{
if (is_error_page) {
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index cb006106e..f3b231798 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -68,17 +68,13 @@ public:
void setLastSearchedString(const QString &s) { m_lastSearchedString = s; }
int lastReceivedFindReply() const { return m_lastReceivedFindReply; }
+ // WebContentsDelegate overrides
virtual content::WebContents *OpenURLFromTab(content::WebContents *source, const content::OpenURLParams &params) Q_DECL_OVERRIDE;
virtual void NavigationStateChanged(const content::WebContents* source, content::InvalidateTypes changed_flags) Q_DECL_OVERRIDE;
virtual void AddNewContents(content::WebContents* source, content::WebContents* new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture, bool* was_blocked) Q_DECL_OVERRIDE;
virtual void CloseContents(content::WebContents *source) Q_DECL_OVERRIDE;
virtual void LoadProgressChanged(content::WebContents* source, double progress) Q_DECL_OVERRIDE;
- virtual void DidStartProvisionalLoadForFrame(content::RenderFrameHost* render_frame_host, const GURL& validated_url, bool is_error_page, bool is_iframe_srcdoc) Q_DECL_OVERRIDE;
- virtual void DidCommitProvisionalLoadForFrame(content::RenderFrameHost* render_frame_host, const GURL& url, ui::PageTransition transition_type) Q_DECL_OVERRIDE;
- virtual void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) Q_DECL_OVERRIDE;
- virtual void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) Q_DECL_OVERRIDE;
- virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) Q_DECL_OVERRIDE;
- virtual void DidUpdateFaviconURL(const std::vector<content::FaviconURL>& candidates) Q_DECL_OVERRIDE;
+ virtual void HandleKeyboardEvent(content::WebContents *source, const content::NativeWebKeyboardEvent &event) Q_DECL_OVERRIDE;
virtual content::JavaScriptDialogManager *GetJavaScriptDialogManager() Q_DECL_OVERRIDE;
virtual void ToggleFullscreenModeForTab(content::WebContents* web_contents, bool enter_fullscreen) Q_DECL_OVERRIDE;
virtual bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const Q_DECL_OVERRIDE;
@@ -87,9 +83,17 @@ public:
virtual void FindReply(content::WebContents *source, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) Q_DECL_OVERRIDE;
virtual void RequestMediaAccessPermission(content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) Q_DECL_OVERRIDE;
virtual void UpdateTargetURL(content::WebContents* source, const GURL& url) Q_DECL_OVERRIDE;
- virtual void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) Q_DECL_OVERRIDE;
virtual void RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) Q_DECL_OVERRIDE;
+ // WebContentsObserver overrides
+ virtual void DidStartProvisionalLoadForFrame(content::RenderFrameHost *render_frame_host, const GURL &validated_url, bool is_error_page, bool is_iframe_srcdoc) Q_DECL_OVERRIDE;
+ virtual void DidCommitProvisionalLoadForFrame(content::RenderFrameHost *render_frame_host, const GURL &url, ui::PageTransition transition_type) Q_DECL_OVERRIDE;
+ virtual void DidFailProvisionalLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url, int error_code, const base::string16 &error_description) Q_DECL_OVERRIDE;
+ virtual void DidFailLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url, int error_code, const base::string16 &error_description) Q_DECL_OVERRIDE;
+ virtual void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) Q_DECL_OVERRIDE;
+ virtual void DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) Q_DECL_OVERRIDE;
+ virtual void DidNavigateAnyFrame(content::RenderFrameHost *render_frame_host, const content::LoadCommittedDetails &details, const content::FrameNavigateParams &params) Q_DECL_OVERRIDE;
+
void overrideWebPreferences(content::WebContents *, content::WebPreferences*);
void allowCertificateError(const QSharedPointer<CertificateErrorController> &) ;
void requestGeolocationPermission(const GURL &requestingFrameOrigin, const base::Callback<void (bool)> &resultCallback);
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index 6f9422c8e..eacb59011 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -661,7 +661,7 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub
content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev)
{
- content::NativeWebKeyboardEvent webKitEvent;
+ content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev));
webKitEvent.timeStampSeconds = currentTimeForEvent(ev);
webKitEvent.modifiers = modifiersForEvent(ev);
webKitEvent.type = webEventTypeForEvent(ev);
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index f6dbc18ff..02d30af61 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -354,6 +354,13 @@ void QQuickWebEngineViewPrivate::focusContainer()
q->forceActiveFocus();
}
+void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event)
+{
+ Q_Q(QQuickWebEngineView);
+ if (q->parentItem())
+ q->window()->sendEvent(q->parentItem(), event);
+}
+
void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &)
{
Q_Q(QQuickWebEngineView);
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 1c1334ee6..28c8ff44e 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -155,6 +155,7 @@ public:
virtual void loadVisuallyCommitted() Q_DECL_OVERRIDE;
virtual void loadFinished(bool success, const QUrl &url, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE;
virtual void focusContainer() Q_DECL_OVERRIDE;
+ virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &) Q_DECL_OVERRIDE;
virtual void close() Q_DECL_OVERRIDE;
virtual void requestFullScreen(bool) Q_DECL_OVERRIDE;
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 32c467c08..aceac91e3 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -271,6 +271,12 @@ void QWebEnginePagePrivate::focusContainer()
view->setFocus();
}
+void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event)
+{
+ if (view && view->parentWidget())
+ QGuiApplication::sendEvent(view->parentWidget(), event);
+}
+
void QWebEnginePagePrivate::adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry)
{
Q_Q(QWebEnginePage);
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 93b94bfa5..6c6520414 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -120,6 +120,7 @@ public:
virtual void loadVisuallyCommitted() Q_DECL_OVERRIDE { }
virtual void loadFinished(bool success, const QUrl &url, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE;
virtual void focusContainer() Q_DECL_OVERRIDE;
+ virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) Q_DECL_OVERRIDE;
virtual void close() Q_DECL_OVERRIDE;
virtual bool contextMenuRequested(const WebEngineContextMenuData &data) Q_DECL_OVERRIDE;
diff --git a/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml
new file mode 100644
index 000000000..8d5fd5375
--- /dev/null
+++ b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Quick Controls 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+import QtWebEngine 1.0
+
+Item {
+ id: parentItem
+ width: 400
+ height: 300
+
+ property var pressEvents: []
+ property var releaseEvents: []
+ Keys.onPressed: pressEvents.push(event.key)
+ Keys.onReleased: releaseEvents.push(event.key)
+
+ TestWebEngineView {
+ id: webEngineView
+ anchors.fill: parent
+ focus: true
+ }
+ TestCase {
+ name: "WebEngineViewUnhandledKeyEventPropagation"
+
+ when: false
+ Timer {
+ running: parent.windowShown
+ repeat: false
+ interval: 1
+ onTriggered: parent.when = true
+ }
+
+ function test_keyboardModifierMapping() {
+ webEngineView.loadHtml("<input type='text'/>")
+ webEngineView.waitForLoadSucceeded()
+ webEngineView.runJavaScript("document.body.firstChild.focus()")
+
+ keyPress(Qt.Key_A)
+ keyRelease(Qt.Key_A)
+ keyPress(Qt.Key_Left)
+ keyRelease(Qt.Key_Left)
+ keyPress(Qt.Key_Left)
+ keyRelease(Qt.Key_Left)
+
+ for (var i = 0; i < 20 && parentItem.releaseEvents.length < 3; i++)
+ wait(100)
+
+ compare(parentItem.pressEvents.length, 1)
+ compare(parentItem.pressEvents[0], Qt.Key_Left)
+ compare(parentItem.releaseEvents.length, 3)
+ compare(parentItem.releaseEvents[0], Qt.Key_A)
+ compare(parentItem.releaseEvents[1], Qt.Key_Left)
+ compare(parentItem.releaseEvents[2], Qt.Key_Left)
+ }
+ }
+}
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 3893397cd..83f65f9d0 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -50,6 +50,7 @@ private Q_SLOTS:
void reusePage();
void microFocusCoordinates();
void focusInputTypes();
+ void unhandledKeyEventPropagation();
void horizontalScrollbarTest();
void crashTests();
@@ -321,6 +322,49 @@ void tst_QWebEngineView::focusInputTypes()
#endif
}
+class KeyEventRecordingWidget : public QWidget {
+public:
+ QList<QKeyEvent> pressEvents;
+ QList<QKeyEvent> releaseEvents;
+ void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE { pressEvents << *e; }
+ void keyReleaseEvent(QKeyEvent *e) Q_DECL_OVERRIDE { releaseEvents << *e; }
+};
+
+void tst_QWebEngineView::unhandledKeyEventPropagation()
+{
+ KeyEventRecordingWidget parentWidget;
+ QWebEngineView webView(&parentWidget);
+ parentWidget.show();
+ QTest::qWaitForWindowExposed(&webView);
+
+ QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
+ webView.setHtml("<input type='text'/>");
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ evaluateJavaScriptSync(webView.page(), "document.body.firstChild.focus()");
+
+ QTest::sendKeyEvent(QTest::Press, parentWidget.windowHandle(), Qt::Key_A, 'a', Qt::NoModifier);
+ QTest::sendKeyEvent(QTest::Release, parentWidget.windowHandle(), Qt::Key_A, 'a', Qt::NoModifier);
+ QTest::sendKeyEvent(QTest::Press, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier);
+ QTest::sendKeyEvent(QTest::Release, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier);
+ QTest::sendKeyEvent(QTest::Press, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier);
+ QTest::sendKeyEvent(QTest::Release, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier);
+
+ // All this happens asychronously, wait for the last release event to know when we're done.
+ for (int i = 0; i < 20 && parentWidget.releaseEvents.size() < 3; ++i)
+ QTest::qWait(100);
+
+ // The page will consume the 'a' and the first left key presses, the second left won't be
+ // used since the cursor will already be at the left end of the text input.
+ // Key releases will all come back unconsumed.
+ QCOMPARE(parentWidget.pressEvents.size(), 1);
+ QCOMPARE(parentWidget.pressEvents[0].key(), (int)Qt::Key_Left);
+ QCOMPARE(parentWidget.releaseEvents.size(), 3);
+ QCOMPARE(parentWidget.releaseEvents[0].key(), (int)Qt::Key_A);
+ QCOMPARE(parentWidget.releaseEvents[1].key(), (int)Qt::Key_Left);
+ QCOMPARE(parentWidget.releaseEvents[2].key(), (int)Qt::Key_Left);
+}
+
void tst_QWebEngineView::horizontalScrollbarTest()
{
#if !defined(QWEBENGINEPAGE_SCROLL)