diff --git a/tests/auto/quick/qmltests/data/keyboardEvents.html b/tests/auto/quick/qmltests/data/keyboardEvents.html
new file mode 100644
index 0000000000000000000000000000000000000000..d536d849fe5d9f15b4bb50e44ab5e4c26bc5b727
--- /dev/null
+++ b/tests/auto/quick/qmltests/data/keyboardEvents.html
@@ -0,0 +1,98 @@
+<html>
+<head>
+    <style>
+        div {
+            width: 300px;
+            margin-bottom: 10px;
+        }
+
+        #div_container {
+            display: inline-block;
+        }
+
+        #div_container div {
+            width: 100px;
+            height: 100px;
+            border: 2px solid black;
+            padding: 10px;
+            margin: 0 10px 0 10px;
+            float: left;
+        }
+
+        #div_container div:focus {
+            border: 2px solid red;
+        }
+
+        #form_container span {
+            display: block;
+            padding-bottom: 10px;
+        }
+
+        #form_container label {
+            float: left;
+            text-align: right;
+            width: 50px;
+            margin-right: 20px;
+        }
+    </style>
+</head>
+
+<body onload="document.getElementById('first_div').focus()">
+    <div id="div_container">
+        <div id="first_div" tabindex="0">First</div>
+        <div id="second_div" tabindex="0">Second</div>
+    </div>
+
+    <div id="form_container">
+        <form><fieldset>
+            <legend>Form</legend>
+
+            <span>
+                <label for="text_input">text</label>
+                <input id="text_input" type="text" />
+            </span>
+
+            <span>
+                <input id="radio1" type="radio" name="radio">radio1</input>
+                <input id="radio2" type="radio" name="radio">radio2</input>
+            </span>
+
+            <span>
+                <input id="checkbox1" type="checkbox" name="checkbox1" checked="true">checkbox1</input>
+                <input id="checkbox2" type="checkbox" name="checkbox2" checked="true">checkbox2</input>
+            </span>
+
+            <span>
+                <label for="number_input">number</label>
+                <input id="number_input" type="number" min="0" max="10" value="5" />
+            </span>
+
+            <span>
+                <label for="range_input">range</label>
+                <input id="range_input" type="range" min="0" max="10" value="5" />
+            </span>
+
+            <span>
+                <label for="search_input">search</label>
+                <input id="search_input" type="search" value="test" />
+            </span>
+
+            <input id="submit_button" type="submit" value="Submit" />
+        </fieldset></form>
+    </div>
+
+    <div>
+        <select id="combobox">
+            <option value="a">a</option>
+            <option value="b">b</option>
+            <option value="c">c</option>
+        </select>
+    </div>
+
+    <div>
+        <a id="first_hyperlink" href="">First</a>
+        <br />
+        <a id="second_hyperlink" href="">Second</a>
+    </div>
+</body>
+</html>
diff --git a/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml b/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml
new file mode 100644
index 0000000000000000000000000000000000000000..7007a85ac1a4b776241227f75abd6b07fcd26051
--- /dev/null
+++ b/tests/auto/quick/qmltests/data/tst_keyboardEvents.qml
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+import QtWebEngine 1.4
+
+TestWebEngineView {
+    id: webEngineView
+    width: 350
+    height: 480
+
+    TestCase {
+        name: "WebEngineViewKeyboardEvents"
+        when: windowShown
+
+        function getActiveElementId() {
+            var activeElementId;
+            runJavaScript("document.activeElement.id", function(result) {
+                activeElementId = result;
+            });
+            tryVerify(function() { return activeElementId != undefined });
+            return activeElementId;
+        }
+
+        function verifyElementHasFocus(element) {
+            tryVerify(function() { return getActiveElementId() == element; }, 5000,
+                "Element \"" + element + "\" has focus");
+
+        }
+
+        function setFocusToElement(element) {
+            runJavaScript("document.getElementById('" + element + "').focus()");
+            verifyElementHasFocus(element);
+        }
+
+        function isElementChecked(element) {
+            var elementChecked;
+            runJavaScript("document.getElementById('" + element + "').checked", function(result) {
+                elementChecked = result;
+            });
+            tryVerify(function() { return elementChecked != undefined; });
+            return elementChecked;
+        }
+
+        function verifyElementChecked(element, expected) {
+            tryVerify(function() { return expected == isElementChecked(element); }, 5000,
+                "Element \"" + element + "\" is " + (expected ? "" : "not") + " checked");
+        }
+
+        function getElementValue(element) {
+            var elementValue;
+            runJavaScript("document.getElementById('" + element + "').value", function(result) {
+                elementValue = result;
+            });
+            tryVerify(function() { return elementValue != undefined; });
+            return elementValue;
+        }
+
+        function compareElementValue(element, expected) {
+            tryVerify(function() { return expected == getElementValue(element); }, 5000,
+                "Value of element \"" + element + "\" is \"" + expected + "\"");
+        }
+
+        function test_keyboardEvents() {
+            webEngineView.url = Qt.resolvedUrl("keyboardEvents.html");
+            verify(webEngineView.waitForLoadSucceeded());
+
+            var elements = [
+                        "first_div", "second_div",
+                        "text_input", "radio1", "checkbox1", "checkbox2",
+                        "number_input", "range_input", "search_input",
+                        "submit_button", "combobox", "first_hyperlink", "second_hyperlink"
+                    ];
+
+            // Iterate over the elements of the test page with the Tab key. This tests whether any
+            // element blocks the in-page navigation by Tab.
+            for (var i = 0; i < elements.length; ++i) {
+                verifyElementHasFocus(elements[i])
+                keyPress(Qt.Key_Tab);
+            }
+
+            // Move back to the radio buttons with the Shift+Tab key combination
+            for (var i = 0; i < 10; ++i)
+                keyPress(Qt.Key_Tab, Qt.ShiftModifier);
+            verifyElementHasFocus("radio2");
+
+            // Test the Space key by checking a radio button
+            verifyElementChecked("radio2", false);
+            keyClick(Qt.Key_Space);
+            verifyElementChecked("radio2", true);
+
+            // Test the Left key by switching the radio button
+            verifyElementChecked("radio1", false);
+            keyPress(Qt.Key_Left);
+            verifyElementHasFocus("radio1");
+            verifyElementChecked("radio1", true);
+
+            // Test the Space key by unchecking a checkbox
+            setFocusToElement("checkbox1");
+            verifyElementChecked("checkbox1", true);
+            keyClick(Qt.Key_Space);
+            verifyElementChecked("checkbox1", false);
+
+            // Test the Up and Down keys by changing the value of a spinbox
+            setFocusToElement("number_input");
+            compareElementValue("number_input", 5);
+            keyPress(Qt.Key_Up);
+            compareElementValue("number_input", 6);
+            keyPress(Qt.Key_Down);
+            compareElementValue("number_input", 5);
+
+            // Test the Left, Right, Home, PageUp, End and PageDown keys by changing the value of a slider
+            setFocusToElement("range_input");
+            compareElementValue("range_input", 5);
+            keyPress(Qt.Key_Left);
+            compareElementValue("range_input", 4);
+            keyPress(Qt.Key_Right);
+            compareElementValue("range_input", 5);
+            keyPress(Qt.Key_Home);
+            compareElementValue("range_input", 0);
+            keyPress(Qt.Key_PageUp);
+            compareElementValue("range_input", 1);
+            keyPress(Qt.Key_End);
+            compareElementValue("range_input", 10);
+            keyPress(Qt.Key_PageDown);
+            compareElementValue("range_input", 9);
+
+            // Test the Escape key by removing the content of a search field
+            setFocusToElement("search_input");
+            compareElementValue("search_input", "test");
+            keyPress(Qt.Key_Escape);
+            compareElementValue("search_input", "");
+
+            // Test the alpha keys by changing the values in a combobox
+            setFocusToElement("combobox");
+            compareElementValue("combobox", "a");
+            keyPress(Qt.Key_B);
+            compareElementValue("combobox", "b");
+            // Must wait with the second key press to simulate selection of another element
+            wait(1000);
+            keyPress(Qt.Key_C);
+            compareElementValue("combobox", "c");
+
+            // Test the Enter key by loading a page with a hyperlink
+            setFocusToElement("first_hyperlink");
+            keyPress(Qt.Key_Enter);
+            verify(webEngineView.waitForLoadSucceeded());
+        }
+    }
+}
diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro
index 726519db2aa95efb995707067ea52c3e7f2b5f27..4d4268324a5ea3be9a95c4b806cee275ac768ac7 100644
--- a/tests/auto/quick/qmltests/qmltests.pro
+++ b/tests/auto/quick/qmltests/qmltests.pro
@@ -39,6 +39,7 @@ OTHER_FILES += \
     $$PWD/data/test3.html \
     $$PWD/data/test4.html \
     $$PWD/data/keyboardModifierMapping.html \
+    $$PWD/data/keyboardEvents.html \
     $$PWD/data/titleupdate.js \
     $$PWD/data/tst_desktopBehaviorLoadHtml.qml \
     $$PWD/data/tst_download.qml \
@@ -70,6 +71,7 @@ OTHER_FILES += \
     $$PWD/data/tst_webchannel.qml \
     $$PWD/data/tst_settings.qml \
     $$PWD/data/tst_keyboardModifierMapping.qml \
+    $$PWD/data/tst_keyboardEvents.qml \
     $$PWD/data/icons/favicon.png \
     $$PWD/data/icons/gray128.png \
     $$PWD/data/icons/gray16.png \
diff --git a/tests/auto/widgets/qwebengineview/resources/keyboardEvents.html b/tests/auto/widgets/qwebengineview/resources/keyboardEvents.html
new file mode 100644
index 0000000000000000000000000000000000000000..d536d849fe5d9f15b4bb50e44ab5e4c26bc5b727
--- /dev/null
+++ b/tests/auto/widgets/qwebengineview/resources/keyboardEvents.html
@@ -0,0 +1,98 @@
+<html>
+<head>
+    <style>
+        div {
+            width: 300px;
+            margin-bottom: 10px;
+        }
+
+        #div_container {
+            display: inline-block;
+        }
+
+        #div_container div {
+            width: 100px;
+            height: 100px;
+            border: 2px solid black;
+            padding: 10px;
+            margin: 0 10px 0 10px;
+            float: left;
+        }
+
+        #div_container div:focus {
+            border: 2px solid red;
+        }
+
+        #form_container span {
+            display: block;
+            padding-bottom: 10px;
+        }
+
+        #form_container label {
+            float: left;
+            text-align: right;
+            width: 50px;
+            margin-right: 20px;
+        }
+    </style>
+</head>
+
+<body onload="document.getElementById('first_div').focus()">
+    <div id="div_container">
+        <div id="first_div" tabindex="0">First</div>
+        <div id="second_div" tabindex="0">Second</div>
+    </div>
+
+    <div id="form_container">
+        <form><fieldset>
+            <legend>Form</legend>
+
+            <span>
+                <label for="text_input">text</label>
+                <input id="text_input" type="text" />
+            </span>
+
+            <span>
+                <input id="radio1" type="radio" name="radio">radio1</input>
+                <input id="radio2" type="radio" name="radio">radio2</input>
+            </span>
+
+            <span>
+                <input id="checkbox1" type="checkbox" name="checkbox1" checked="true">checkbox1</input>
+                <input id="checkbox2" type="checkbox" name="checkbox2" checked="true">checkbox2</input>
+            </span>
+
+            <span>
+                <label for="number_input">number</label>
+                <input id="number_input" type="number" min="0" max="10" value="5" />
+            </span>
+
+            <span>
+                <label for="range_input">range</label>
+                <input id="range_input" type="range" min="0" max="10" value="5" />
+            </span>
+
+            <span>
+                <label for="search_input">search</label>
+                <input id="search_input" type="search" value="test" />
+            </span>
+
+            <input id="submit_button" type="submit" value="Submit" />
+        </fieldset></form>
+    </div>
+
+    <div>
+        <select id="combobox">
+            <option value="a">a</option>
+            <option value="b">b</option>
+            <option value="c">c</option>
+        </select>
+    </div>
+
+    <div>
+        <a id="first_hyperlink" href="">First</a>
+        <br />
+        <a id="second_hyperlink" href="">Second</a>
+    </div>
+</body>
+</html>
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 156c56933608b2f4cd11b81903a941c34dd1c67c..9966ad9ee65ae4d5d50ea1b7001cd08a886791de 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -82,6 +82,7 @@ private Q_SLOTS:
     void changeLocale();
     void inputMethodsTextFormat_data();
     void inputMethodsTextFormat();
+    void keyboardEvents();
 };
 
 // This will be called before the first test function is executed.
@@ -924,5 +925,94 @@ void tst_QWebEngineView::inputMethodsTextFormat()
     QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), string);
 }
 
+void tst_QWebEngineView::keyboardEvents()
+{
+    QWebEngineView view;
+    view.show();
+    QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+    view.load(QUrl("qrc:///resources/keyboardEvents.html"));
+    QVERIFY(loadFinishedSpy.wait());
+
+    QStringList elements;
+    elements << "first_div" << "second_div";
+    elements << "text_input" << "radio1" << "checkbox1" << "checkbox2";
+    elements << "number_input" << "range_input" << "search_input";
+    elements << "submit_button" << "combobox" << "first_hyperlink" << "second_hyperlink";
+
+    // Iterate over the elements of the test page with the Tab key. This tests whether any
+    // element blocks the in-page navigation by Tab.
+    for (const QString &elementId : elements) {
+        QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), elementId);
+        QTest::keyPress(view.focusProxy(), Qt::Key_Tab);
+    }
+
+    // Move back to the radio buttons with the Shift+Tab key combination
+    for (int i = 0; i < 10; ++i)
+        QTest::keyPress(view.focusProxy(), Qt::Key_Tab, Qt::ShiftModifier);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("radio2"));
+
+    // Test the Space key by checking a radio button
+    QVERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('radio2').checked").toBool());
+    QTest::keyClick(view.focusProxy(), Qt::Key_Space);
+    QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('radio2').checked").toBool());
+
+    // Test the Left key by switching the radio button
+    QVERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('radio1').checked").toBool());
+    QTest::keyPress(view.focusProxy(), Qt::Key_Left);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("radio1"));
+    QVERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('radio2').checked").toBool());
+    QVERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('radio1').checked").toBool());
+
+    // Test the Space key by unchecking a checkbox
+    evaluateJavaScriptSync(view.page(), "document.getElementById('checkbox1').focus()");
+    QVERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('checkbox1').checked").toBool());
+    QTest::keyClick(view.focusProxy(), Qt::Key_Space);
+    QTRY_VERIFY(!evaluateJavaScriptSync(view.page(), "document.getElementById('checkbox1').checked").toBool());
+
+    // Test the Up and Down keys by changing the value of a spinbox
+    evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').focus()");
+    QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').value").toInt(), 5);
+    QTest::keyPress(view.focusProxy(), Qt::Key_Up);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').value").toInt(), 6);
+    QTest::keyPress(view.focusProxy(), Qt::Key_Down);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('number_input').value").toInt(), 5);
+
+    // Test the Left, Right, Home, PageUp, End and PageDown keys by changing the value of a slider
+    evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').focus()");
+    QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("5"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_Left);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("4"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_Right);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("5"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_Home);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("0"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_PageUp);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("1"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_End);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("10"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_PageDown);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('range_input').value").toString(), QStringLiteral("9"));
+
+    // Test the Escape key by removing the content of a search field
+    evaluateJavaScriptSync(view.page(), "document.getElementById('search_input').focus()");
+    QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('search_input').value").toString(), QStringLiteral("test"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_Escape);
+    QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('search_input').value").toString().isEmpty());
+
+    // Test the alpha keys by changing the values in a combobox
+    evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').focus()");
+    QCOMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').value").toString(), QStringLiteral("a"));
+    QTest::keyPress(view.focusProxy(), Qt::Key_B);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').value").toString(), QStringLiteral("b"));
+    // Must wait with the second key press to simulate selection of another element
+    QTest::keyPress(view.focusProxy(), Qt::Key_C, Qt::NoModifier, 1000);
+    QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('combobox').value").toString(), QStringLiteral("c"));
+
+    // Test the Enter key by loading a page with a hyperlink
+    evaluateJavaScriptSync(view.page(), "document.getElementById('first_hyperlink').focus()");
+    QTest::keyPress(view.focusProxy(), Qt::Key_Enter);
+    QVERIFY(loadFinishedSpy.wait());
+}
+
 QTEST_MAIN(tst_QWebEngineView)
 #include "tst_qwebengineview.moc"
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
index b32b533c21ae1e2a0d14c82516f1210f42d30786..4809bbebfff4dcd83fa6f9e18b220864793db1a4 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc
@@ -5,5 +5,6 @@
         <file>resources/input_types.html</file>
         <file>resources/scrolltest_page.html</file>
         <file>resources/basic_printing_page.html</file>
+        <file>resources/keyboardEvents.html</file>
     </qresource>
 </RCC>