From e0bd650cb7f8c8fd3014541b4c49104906e0e139 Mon Sep 17 00:00:00 2001
From: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com>
Date: Mon, 20 Jun 2016 17:14:35 +0200
Subject: [PATCH] Override short-cuts to common editor commands

To ensure Chromium is given a chance to handle editor commands,
we must override these short-cuts.

On OS X we must also perform the action afterwards as these are not
handled internally by the Blink Editor.

The patch solves copy/paste in flash plugins and copy/paste on OS X
when no application short-cuts have been defined. The handling of
short-cut override events is based on how it was handled in Qt WebKit

Task-number: QTBUG-54221
Change-Id: I748671c7bfa5662aae16c6a4b9bbe5e2bce1b907
Reviewed-by: Alexandru Croitor <alexandru.croitor@theqtcompany.com>
---
 src/webengine/api/qquickwebengineview.cpp     | 33 +++++++++++++++++
 src/webengine/api/qquickwebengineview_p_p.h   |  2 ++
 ...der_widget_host_view_qt_delegate_quick.cpp | 12 +++++++
 ...ender_widget_host_view_qt_delegate_quick.h |  1 +
 src/webenginewidgets/api/qwebenginepage.cpp   | 36 +++++++++++++++++++
 src/webenginewidgets/api/qwebenginepage_p.h   |  2 ++
 ...er_widget_host_view_qt_delegate_widget.cpp |  7 ++++
 7 files changed, 93 insertions(+)

diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 357f95bc4..6b3614fc5 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -86,6 +86,27 @@
 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)
 {
@@ -489,6 +510,18 @@ 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())
         q->window()->sendEvent(q->parentItem(), event);
 }
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 2a6c2c879..aab86bc3a 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -68,6 +68,8 @@ class QQmlComponent;
 class QQmlContext;
 class QQuickWebEngineSettings;
 
+QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event);
+
 #ifdef ENABLE_QML_TESTSUPPORT_API
 class QQuickWebEngineTestSupport;
 #endif
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 cd8fc54b9..b10ca8bdb 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -207,6 +207,18 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis
 
 }
 
+bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event)
+{
+    if (event->type() == QEvent::ShortcutOverride) {
+        if (editorActionForKeyEvent(static_cast<QKeyEvent*>(event)) != QQuickWebEngineView::NoWebAction) {
+            event->accept();
+            return true;
+        }
+    }
+
+    return QQuickItem::event(event);
+}
+
 void RenderWidgetHostViewQtDelegateQuick::focusInEvent(QFocusEvent *event)
 {
     m_client->forwardEvent(event);
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h
index 7c44da9b9..dc0e481db 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h
@@ -74,6 +74,7 @@ public:
     virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { }
 
 protected:
+    virtual bool event(QEvent *event) Q_DECL_OVERRIDE;
     virtual void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
     virtual void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
     virtual void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 0279c9343..45177d8d8 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -77,6 +77,8 @@
 #include <QStyle>
 #include <QUrl>
 
+#include <private/qguiapplication_p.h>
+
 QT_BEGIN_NAMESPACE
 
 using namespace QtWebEngineCore;
@@ -96,6 +98,27 @@ static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::Wind
     }
 }
 
+QWebEnginePage::WebAction editorActionForKeyEvent(QKeyEvent* event)
+{
+    static struct {
+        QKeySequence::StandardKey standardKey;
+        QWebEnginePage::WebAction action;
+    } editorActions[] = {
+        { QKeySequence::Cut, QWebEnginePage::Cut },
+        { QKeySequence::Copy, QWebEnginePage::Copy },
+        { QKeySequence::Paste, QWebEnginePage::Paste },
+        { QKeySequence::Undo, QWebEnginePage::Undo },
+        { QKeySequence::Redo, QWebEnginePage::Redo },
+        { QKeySequence::SelectAll, QWebEnginePage::SelectAll },
+        { QKeySequence::UnknownKey, QWebEnginePage::NoWebAction }
+    };
+    for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
+        if (event == editorActions[i].standardKey)
+            return editorActions[i].action;
+
+    return QWebEnginePage::NoWebAction;
+}
+
 QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile)
     : adapter(new WebContentsAdapter)
     , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this)))
@@ -226,6 +249,19 @@ 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/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 7b16ed667..d0023d7bb 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -67,6 +67,8 @@ class QWebEngineProfile;
 class QWebEngineSettings;
 class QWebEngineView;
 
+QWebEnginePage::WebAction editorActionForKeyEvent(QKeyEvent* event);
+
 class QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient
 {
 public:
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 78840085f..2937c94b7 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -323,6 +323,13 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event)
         }
     }
 
+    if (event->type() == QEvent::ShortcutOverride) {
+        if (editorActionForKeyEvent(static_cast<QKeyEvent*>(event)) != QWebEnginePage::NoWebAction) {
+            event->accept();
+            return true;
+        }
+    }
+
     if (event->type() == QEvent::MouseButtonDblClick) {
         // QWidget keeps the Qt4 behavior where the DblClick event would replace the Press event.
         // QtQuick is different by sending both the Press and DblClick events for the second press
-- 
GitLab