From 89f1f14c5e9a49f25345a65d81b3518d58ecb91a Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@qt.io>
Date: Tue, 22 Oct 2019 10:53:54 +0200
Subject: [PATCH] Extract QGuiShortcut

[ChangeLog][QtGui] Added QGuiShortcut and made the equivalent
existing classes in Qt Widgets derive from them. This provides
basic functionality for adding shortcut handling in QML.

Fixes: QTBUG-79638
Task-number: QTBUG-76493
Change-Id: I5bbd2c8f192660e93c4690b9f894643275090e4d
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
---
 src/gui/kernel/kernel.pri                     |   3 +
 src/gui/kernel/qguishortcut.cpp               | 354 ++++++++++++++++++
 src/gui/kernel/qguishortcut.h                 |  98 +++++
 src/gui/kernel/qguishortcut_p.h               |  92 +++++
 src/widgets/kernel/qshortcut.cpp              | 240 +-----------
 src/widgets/kernel/qshortcut.h                |  39 +-
 tests/auto/gui/kernel/kernel.pro              |   2 +
 .../gui/kernel/qguishortcut/qguishortcut.pro  |   4 +
 .../kernel/qguishortcut/tst_qguishortcut.cpp  |  82 ++++
 9 files changed, 659 insertions(+), 255 deletions(-)
 create mode 100644 src/gui/kernel/qguishortcut.cpp
 create mode 100644 src/gui/kernel/qguishortcut.h
 create mode 100644 src/gui/kernel/qguishortcut_p.h
 create mode 100644 tests/auto/gui/kernel/qguishortcut/qguishortcut.pro
 create mode 100644 tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp

diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 42bb81fa24..3784abdacc 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -169,10 +169,13 @@ qtConfig(opengl) {
 
 qtConfig(shortcut) {
     HEADERS += \
+            kernel/qguishortcut.h \
+            kernel/qguishortcut_p.h \
             kernel/qshortcutmap_p.h \
             kernel/qkeysequence.h \
             kernel/qkeysequence_p.h
     SOURCES += \
+            kernel/qguishortcut.cpp \
             kernel/qshortcutmap.cpp \
             kernel/qkeysequence.cpp
 }
diff --git a/src/gui/kernel/qguishortcut.cpp b/src/gui/kernel/qguishortcut.cpp
new file mode 100644
index 0000000000..add1dce12e
--- /dev/null
+++ b/src/gui/kernel/qguishortcut.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui 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 "qguishortcut.h"
+#include "qguishortcut_p.h"
+
+#include <qevent.h>
+#include <qguiapplication.h>
+#include <qwindow.h>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformmenu.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QAPP_CHECK(functionName) \
+    if (Q_UNLIKELY(!qApp)) {                                            \
+        qWarning("QGuiShortcut: Initialize QGuiApplication before calling '" functionName "'."); \
+        return; \
+    }
+
+/*!
+    \class QGuiShortcut
+    \brief The QGuiShortcut class is a base class for handling keyboard shortcuts.
+
+    \ingroup events
+    \inmodule QtGui
+    \since 6.0
+
+    The QGuiShortcut class is a base class for classes providing a way of
+    connecting keyboard shortcuts to Qt's \l{signals and slots} mechanism,
+    so that objects can be informed when a shortcut is executed. The shortcut
+    can be set up to contain all the key presses necessary to
+    describe a keyboard shortcut, including the states of modifier
+    keys such as \uicontrol Shift, \uicontrol Ctrl, and \uicontrol Alt.
+
+    \target mnemonic
+
+    \sa QShortcutEvent, QKeySequence, QAction
+*/
+
+/*!
+    \fn void QGuiShortcut::activated()
+
+    This signal is emitted when the user types the shortcut's key
+    sequence.
+
+    \sa activatedAmbiguously()
+*/
+
+/*!
+    \fn void QGuiShortcut::activatedAmbiguously()
+
+    When a key sequence is being typed at the keyboard, it is said to
+    be ambiguous as long as it matches the start of more than one
+    shortcut.
+
+    When a shortcut's key sequence is completed,
+    activatedAmbiguously() is emitted if the key sequence is still
+    ambiguous (i.e., it is the start of one or more other shortcuts).
+    The activated() signal is not emitted in this case.
+
+    \sa activated()
+*/
+
+static bool simpleContextMatcher(QObject *object, Qt::ShortcutContext context)
+{
+    auto guiShortcut = qobject_cast<QGuiShortcut *>(object);
+    if (QGuiApplication::applicationState() != Qt::ApplicationActive || guiShortcut == nullptr)
+        return false;
+    if (context == Qt::ApplicationShortcut)
+        return true;
+    auto focusWindow = QGuiApplication::focusWindow();
+    if (!focusWindow)
+        return false;
+    auto window = qobject_cast<const QWindow *>(guiShortcut->parent());
+    if (!window)
+        return false;
+    if (focusWindow == window && focusWindow->isTopLevel())
+        return context == Qt::WindowShortcut || context == Qt::WidgetWithChildrenShortcut;
+    return focusWindow->isAncestorOf(window, QWindow::ExcludeTransients);
+}
+
+QShortcutMap::ContextMatcher QGuiShortcutPrivate::contextMatcher() const
+{
+    return simpleContextMatcher;
+}
+
+void QGuiShortcutPrivate::redoGrab(QShortcutMap &map)
+{
+    Q_Q(QGuiShortcut);
+    if (Q_UNLIKELY(!parent)) {
+        qWarning("QGuiShortcut: No window parent defined");
+        return;
+    }
+
+    if (sc_id)
+        map.removeShortcut(sc_id, q);
+    if (sc_sequence.isEmpty())
+        return;
+    sc_id = map.addShortcut(q, sc_sequence, sc_context, contextMatcher());
+    if (!sc_enabled)
+        map.setShortcutEnabled(false, sc_id, q);
+    if (!sc_autorepeat)
+        map.setShortcutAutoRepeat(false, sc_id, q);
+}
+
+/*!
+    Constructs a QGuiShortcut object for the \a parent window. Since no
+    shortcut key sequence is specified, the shortcut will not emit any
+    signals.
+
+    \sa setKey()
+*/
+QGuiShortcut::QGuiShortcut(QWindow *parent)
+    : QGuiShortcut(*new QGuiShortcutPrivate, parent)
+{
+}
+
+/*!
+    Constructs a QGuiShortcut object for the \a parent window. The shortcut
+    operates on its parent, listening for \l{QShortcutEvent}s that
+    match the \a key sequence. Depending on the ambiguity of the
+    event, the shortcut will call the \a member function, or the \a
+    ambiguousMember function, if the key press was in the shortcut's
+    \a context.
+*/
+QGuiShortcut::QGuiShortcut(const QKeySequence &key, QWindow *parent,
+                           const char *member, const char *ambiguousMember,
+                           Qt::ShortcutContext context)
+    : QGuiShortcut(*new QGuiShortcutPrivate, key, parent, member, ambiguousMember, context)
+{
+}
+
+/*!
+    \internal
+*/
+QGuiShortcut::QGuiShortcut(QGuiShortcutPrivate &dd, QObject *parent)
+     : QObject(dd, parent)
+{
+    Q_ASSERT(parent != nullptr);
+}
+
+/*!
+    \internal
+*/
+QGuiShortcut::QGuiShortcut(QGuiShortcutPrivate &dd,
+                           const QKeySequence &key, QObject *parent,
+                           const char *member, const char *ambiguousMember,
+                           Qt::ShortcutContext context)
+    : QGuiShortcut(dd, parent)
+{
+    QAPP_CHECK("QGuiShortcut");
+
+    Q_D(QGuiShortcut);
+    d->sc_context = context;
+    d->sc_sequence = key;
+    d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
+    if (member)
+        connect(this, SIGNAL(activated()), parent, member);
+    if (ambiguousMember)
+        connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember);
+}
+
+/*!
+    Destroys the shortcut.
+*/
+QGuiShortcut::~QGuiShortcut()
+{
+    Q_D(QGuiShortcut);
+    if (qApp)
+        QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->sc_id, this);
+}
+
+/*!
+    \property QGuiShortcut::key
+    \brief the shortcut's key sequence
+
+    This is a key sequence with an optional combination of Shift, Ctrl,
+    and Alt. The key sequence may be supplied in a number of ways:
+
+    \snippet code/src_gui_kernel_qshortcut.cpp 1
+
+    By default, this property contains an empty key sequence.
+*/
+void QGuiShortcut::setKey(const QKeySequence &key)
+{
+    Q_D(QGuiShortcut);
+    if (d->sc_sequence == key)
+        return;
+    QAPP_CHECK("setKey");
+    d->sc_sequence = key;
+    d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
+}
+
+QKeySequence QGuiShortcut::key() const
+{
+    Q_D(const QGuiShortcut);
+    return d->sc_sequence;
+}
+
+/*!
+    \property QGuiShortcut::enabled
+    \brief whether the shortcut is enabled
+
+    An enabled shortcut emits the activated() or activatedAmbiguously()
+    signal when a QShortcutEvent occurs that matches the shortcut's
+    key() sequence.
+
+    If the application is in \c WhatsThis mode the shortcut will not emit
+    the signals, but will show the "What's This?" text instead.
+
+    By default, this property is \c true.
+
+    \sa whatsThis
+*/
+void QGuiShortcut::setEnabled(bool enable)
+{
+    Q_D(QGuiShortcut);
+    if (d->sc_enabled == enable)
+        return;
+    QAPP_CHECK("setEnabled");
+    d->sc_enabled = enable;
+    QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, d->sc_id, this);
+}
+
+bool QGuiShortcut::isEnabled() const
+{
+    Q_D(const QGuiShortcut);
+    return d->sc_enabled;
+}
+
+/*!
+    \property QGuiShortcut::context
+    \brief the context in which the shortcut is valid
+
+    A shortcut's context decides in which circumstances a shortcut is
+    allowed to be triggered. The normal context is Qt::WindowShortcut,
+    which allows the shortcut to trigger if the parent (the widget
+    containing the shortcut) is a subwidget of the active top-level
+    window.
+
+    By default, this property is set to Qt::WindowShortcut.
+*/
+void QGuiShortcut::setContext(Qt::ShortcutContext context)
+{
+    Q_D(QGuiShortcut);
+    if (d->sc_context == context)
+        return;
+    QAPP_CHECK("setContext");
+    d->sc_context = context;
+    d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
+}
+
+Qt::ShortcutContext QGuiShortcut::context() const
+{
+    Q_D(const QGuiShortcut);
+    return d->sc_context;
+}
+
+/*!
+    \property QGuiShortcut::autoRepeat
+    \brief whether the shortcut can auto repeat
+
+    If true, the shortcut will auto repeat when the keyboard shortcut
+    combination is held down, provided that keyboard auto repeat is
+    enabled on the system.
+    The default value is true.
+*/
+void QGuiShortcut::setAutoRepeat(bool on)
+{
+    Q_D(QGuiShortcut);
+    if (d->sc_autorepeat == on)
+        return;
+    QAPP_CHECK("setAutoRepeat");
+    d->sc_autorepeat = on;
+    QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, d->sc_id, this);
+}
+
+bool QGuiShortcut::autoRepeat() const
+{
+    Q_D(const QGuiShortcut);
+    return d->sc_autorepeat;
+}
+
+/*!
+    Returns the shortcut's ID.
+
+    \sa QShortcutEvent::shortcutId()
+*/
+int QGuiShortcut::id() const
+{
+    Q_D(const QGuiShortcut);
+    return d->sc_id;
+}
+
+/*!
+    \internal
+*/
+bool QGuiShortcut::event(QEvent *e)
+{
+    Q_D(QGuiShortcut);
+    if (d->sc_enabled && e->type() == QEvent::Shortcut) {
+        auto se = static_cast<QShortcutEvent *>(e);
+        if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence
+            && !d->handleWhatsThis()) {
+            if (se->isAmbiguous())
+                emit activatedAmbiguously();
+            else
+                emit activated();
+            return true;
+        }
+    }
+    return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qguishortcut.cpp"
diff --git a/src/gui/kernel/qguishortcut.h b/src/gui/kernel/qguishortcut.h
new file mode 100644
index 0000000000..fb64f10c84
--- /dev/null
+++ b/src/gui/kernel/qguishortcut.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui 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$
+**
+****************************************************************************/
+
+#ifndef QGUISHORTCUT_H
+#define QGUISHORTCUT_H
+
+#include <QtGui/qtguiglobal.h>
+#include <QtGui/qkeysequence.h>
+#include <QtCore/qobject.h>
+
+QT_REQUIRE_CONFIG(shortcut);
+
+QT_BEGIN_NAMESPACE
+
+class QGuiShortcutPrivate;
+class QWindow;
+
+class Q_GUI_EXPORT QGuiShortcut : public QObject
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QGuiShortcut)
+    Q_PROPERTY(QKeySequence key READ key WRITE setKey)
+    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
+    Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat)
+    Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext)
+public:
+    explicit QGuiShortcut(QWindow *parent);
+    explicit QGuiShortcut(const QKeySequence& key, QWindow *parent,
+                          const char *member = nullptr, const char *ambiguousMember = nullptr,
+                          Qt::ShortcutContext context = Qt::WindowShortcut);
+    ~QGuiShortcut();
+
+    void setKey(const QKeySequence& key);
+    QKeySequence key() const;
+
+    void setEnabled(bool enable);
+    bool isEnabled() const;
+
+    void setContext(Qt::ShortcutContext context);
+    Qt::ShortcutContext context() const;
+
+    void setAutoRepeat(bool on);
+    bool autoRepeat() const;
+
+    int id() const;
+
+Q_SIGNALS:
+    void activated();
+    void activatedAmbiguously();
+
+protected:
+    QGuiShortcut(QGuiShortcutPrivate &dd, QObject *parent);
+    QGuiShortcut(QGuiShortcutPrivate &dd, const QKeySequence& key, QObject *parent,
+                 const char *member, const char *ambiguousMember,
+                 Qt::ShortcutContext context);
+
+    bool event(QEvent *e) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGUISHORTCUT_H
diff --git a/src/gui/kernel/qguishortcut_p.h b/src/gui/kernel/qguishortcut_p.h
new file mode 100644
index 0000000000..420b02ef1a
--- /dev/null
+++ b/src/gui/kernel/qguishortcut_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui 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$
+**
+****************************************************************************/
+
+#ifndef QGUISHORTCUT_P_H
+#define QGUISHORTCUT_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include "qguishortcut.h"
+#include <QtGui/qkeysequence.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <private/qshortcutmap_p.h>
+
+
+
+QT_BEGIN_NAMESPACE
+
+class QShortcutMap;
+
+/*
+    \internal
+    Private data accessed through d-pointer.
+*/
+class Q_GUI_EXPORT QGuiShortcutPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QGuiShortcut)
+public:
+    QGuiShortcutPrivate() = default;
+
+    virtual QShortcutMap::ContextMatcher contextMatcher() const;
+    virtual bool handleWhatsThis() { return false; }
+
+    QKeySequence sc_sequence;
+    Qt::ShortcutContext sc_context = Qt::WindowShortcut;
+    bool sc_enabled = true;
+    bool sc_autorepeat = true;
+    int sc_id = 0;
+    void redoGrab(QShortcutMap &map);
+};
+
+QT_END_NAMESPACE
+
+#endif // QGUISHORTCUT_P_H
diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp
index be5708aea7..fe94f676df 100644
--- a/src/widgets/kernel/qshortcut.cpp
+++ b/src/widgets/kernel/qshortcut.cpp
@@ -52,6 +52,7 @@
 #endif
 #include <qapplication.h>
 #include <private/qapplication_p.h>
+#include "private/qguishortcut_p.h"
 #include <private/qshortcutmap_p.h>
 #if QT_CONFIG(action)
 #  include <private/qaction_p.h>
@@ -61,13 +62,6 @@
 
 QT_BEGIN_NAMESPACE
 
-#define QAPP_CHECK(functionName) \
-    if (Q_UNLIKELY(!qApp)) {                                            \
-        qWarning("QShortcut: Initialize QApplication before calling '" functionName "'."); \
-        return; \
-    }
-
-
 static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window);
 #if QT_CONFIG(graphicsview)
 static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window);
@@ -396,65 +390,30 @@ static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidge
     Returns the shortcut's parent widget.
 */
 
-/*!
-    \fn void QShortcut::activated()
-
-    This signal is emitted when the user types the shortcut's key
-    sequence.
-
-    \sa activatedAmbiguously()
-*/
-
-/*!
-    \fn void QShortcut::activatedAmbiguously()
-
-    When a key sequence is being typed at the keyboard, it is said to
-    be ambiguous as long as it matches the start of more than one
-    shortcut.
-
-    When a shortcut's key sequence is completed,
-    activatedAmbiguously() is emitted if the key sequence is still
-    ambiguous (i.e., it is the start of one or more other shortcuts).
-    The activated() signal is not emitted in this case.
-
-    \sa activated()
-*/
-
 /*
     \internal
     Private data accessed through d-pointer.
 */
-class QShortcutPrivate : public QObjectPrivate
+class QShortcutPrivate : public QGuiShortcutPrivate
 {
     Q_DECLARE_PUBLIC(QShortcut)
 public:
     QShortcutPrivate() = default;
-    QKeySequence sc_sequence;
-    Qt::ShortcutContext sc_context = Qt::WindowShortcut;
-    bool sc_enabled = true;
-    bool sc_autorepeat = true;
-    int sc_id = 0;
+
+    QShortcutMap::ContextMatcher contextMatcher() const override
+    { return qWidgetShortcutContextMatcher; }
+
+    bool handleWhatsThis() override;
+
     QString sc_whatsthis;
-    void redoGrab(QShortcutMap &map);
 };
 
-void QShortcutPrivate::redoGrab(QShortcutMap &map)
+bool QShortcutPrivate::handleWhatsThis()
 {
-    Q_Q(QShortcut);
-    if (Q_UNLIKELY(!parent)) {
-        qWarning("QShortcut: No widget parent defined");
-        return;
-    }
-
-    if (sc_id)
-        map.removeShortcut(sc_id, q);
-    if (sc_sequence.isEmpty())
-        return;
-    sc_id = map.addShortcut(q, sc_sequence, sc_context, qWidgetShortcutContextMatcher);
-    if (!sc_enabled)
-        map.setShortcutEnabled(false, sc_id, q);
-    if (!sc_autorepeat)
-        map.setShortcutAutoRepeat(false, sc_id, q);
+    const bool result = QWhatsThis::inWhatsThisMode();
+    if (result)
+        QWhatsThis::showText(QCursor::pos(), sc_whatsthis);
+    return result;
 }
 
 /*!
@@ -465,9 +424,8 @@ void QShortcutPrivate::redoGrab(QShortcutMap &map)
     \sa setKey()
 */
 QShortcut::QShortcut(QWidget *parent)
-    : QObject(*new QShortcutPrivate, parent)
+    : QGuiShortcut(*new QShortcutPrivate, parent)
 {
-    Q_ASSERT(parent != nullptr);
 }
 
 /*!
@@ -481,114 +439,8 @@ QShortcut::QShortcut(QWidget *parent)
 QShortcut::QShortcut(const QKeySequence &key, QWidget *parent,
                      const char *member, const char *ambiguousMember,
                      Qt::ShortcutContext context)
-    : QShortcut(parent)
+    : QGuiShortcut(*new QShortcutPrivate, key, parent, member, ambiguousMember, context)
 {
-    QAPP_CHECK("QShortcut");
-
-    Q_D(QShortcut);
-    d->sc_context = context;
-    d->sc_sequence = key;
-    d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
-    if (member)
-        connect(this, SIGNAL(activated()), parent, member);
-    if (ambiguousMember)
-        connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember);
-}
-
-/*!
-    Destroys the shortcut.
-*/
-QShortcut::~QShortcut()
-{
-    Q_D(QShortcut);
-    if (qApp)
-        QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->sc_id, this);
-}
-
-/*!
-    \property QShortcut::key
-    \brief the shortcut's key sequence
-
-    This is a key sequence with an optional combination of Shift, Ctrl,
-    and Alt. The key sequence may be supplied in a number of ways:
-
-    \snippet code/src_gui_kernel_qshortcut.cpp 1
-
-    By default, this property contains an empty key sequence.
-*/
-void QShortcut::setKey(const QKeySequence &key)
-{
-    Q_D(QShortcut);
-    if (d->sc_sequence == key)
-        return;
-    QAPP_CHECK("setKey");
-    d->sc_sequence = key;
-    d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
-}
-
-QKeySequence QShortcut::key() const
-{
-    Q_D(const QShortcut);
-    return d->sc_sequence;
-}
-
-/*!
-    \property QShortcut::enabled
-    \brief whether the shortcut is enabled
-
-    An enabled shortcut emits the activated() or activatedAmbiguously()
-    signal when a QShortcutEvent occurs that matches the shortcut's
-    key() sequence.
-
-    If the application is in \c WhatsThis mode the shortcut will not emit
-    the signals, but will show the "What's This?" text instead.
-
-    By default, this property is \c true.
-
-    \sa whatsThis
-*/
-void QShortcut::setEnabled(bool enable)
-{
-    Q_D(QShortcut);
-    if (d->sc_enabled == enable)
-        return;
-    QAPP_CHECK("setEnabled");
-    d->sc_enabled = enable;
-    QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, d->sc_id, this);
-}
-
-bool QShortcut::isEnabled() const
-{
-    Q_D(const QShortcut);
-    return d->sc_enabled;
-}
-
-/*!
-    \property QShortcut::context
-    \brief the context in which the shortcut is valid
-
-    A shortcut's context decides in which circumstances a shortcut is
-    allowed to be triggered. The normal context is Qt::WindowShortcut,
-    which allows the shortcut to trigger if the parent (the widget
-    containing the shortcut) is a subwidget of the active top-level
-    window.
-
-    By default, this property is set to Qt::WindowShortcut.
-*/
-void QShortcut::setContext(Qt::ShortcutContext context)
-{
-    Q_D(QShortcut);
-    if(d->sc_context == context)
-        return;
-    QAPP_CHECK("setContext");
-    d->sc_context = context;
-    d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
-}
-
-Qt::ShortcutContext QShortcut::context() const
-{
-    Q_D(const QShortcut);
-    return d->sc_context;
 }
 
 /*!
@@ -618,66 +470,8 @@ QString QShortcut::whatsThis() const
 }
 
 /*!
-    \property QShortcut::autoRepeat
-    \brief whether the shortcut can auto repeat
-    \since 4.2
-
-    If true, the shortcut will auto repeat when the keyboard shortcut
-    combination is held down, provided that keyboard auto repeat is
-    enabled on the system.
-    The default value is true.
+    Destroys the shortcut.
 */
-void QShortcut::setAutoRepeat(bool on)
-{
-    Q_D(QShortcut);
-    if (d->sc_autorepeat == on)
-        return;
-    QAPP_CHECK("setAutoRepeat");
-    d->sc_autorepeat = on;
-    QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, d->sc_id, this);
-}
-
-bool QShortcut::autoRepeat() const
-{
-    Q_D(const QShortcut);
-    return d->sc_autorepeat;
-}
-
-/*!
-    Returns the shortcut's ID.
-
-    \sa QShortcutEvent::shortcutId()
-*/
-int QShortcut::id() const
-{
-    Q_D(const QShortcut);
-    return d->sc_id;
-}
-
-/*!
-    \internal
-*/
-bool QShortcut::event(QEvent *e)
-{
-    Q_D(QShortcut);
-    if (d->sc_enabled && e->type() == QEvent::Shortcut) {
-        auto se = static_cast<QShortcutEvent *>(e);
-        if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence){
-#if QT_CONFIG(whatsthis)
-            if (QWhatsThis::inWhatsThisMode()) {
-                QWhatsThis::showText(QCursor::pos(), d->sc_whatsthis);
-            } else
-#endif
-            if (se->isAmbiguous())
-                emit activatedAmbiguously();
-            else
-                emit activated();
-            return true;
-        }
-    }
-    return QObject::event(e);
-}
+QShortcut::~QShortcut() = default;
 
 QT_END_NAMESPACE
-
-#include "moc_qshortcut.cpp"
diff --git a/src/widgets/kernel/qshortcut.h b/src/widgets/kernel/qshortcut.h
index 6334788bce..6ac9a37fe3 100644
--- a/src/widgets/kernel/qshortcut.h
+++ b/src/widgets/kernel/qshortcut.h
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the QtWidgets module of the Qt Toolkit.
@@ -42,55 +42,30 @@
 
 #include <QtWidgets/qtwidgetsglobal.h>
 #include <QtWidgets/qwidget.h>
-#include <QtGui/qkeysequence.h>
+#include <QtGui/qguishortcut.h>
 
 QT_REQUIRE_CONFIG(shortcut);
 
 QT_BEGIN_NAMESPACE
 
 class QShortcutPrivate;
-class Q_WIDGETS_EXPORT QShortcut : public QObject
+class Q_WIDGETS_EXPORT QShortcut : public QGuiShortcut
 {
     Q_OBJECT
-    Q_DECLARE_PRIVATE(QShortcut)
-    Q_PROPERTY(QKeySequence key READ key WRITE setKey)
     Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis)
-    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
-    Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat)
-    Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext)
+    Q_DECLARE_PRIVATE(QShortcut)
 public:
     explicit QShortcut(QWidget *parent);
-    QShortcut(const QKeySequence& key, QWidget *parent,
-              const char *member = nullptr, const char *ambiguousMember = nullptr,
-              Qt::ShortcutContext context = Qt::WindowShortcut);
+    explicit QShortcut(const QKeySequence& key, QWidget *parent,
+                       const char *member = nullptr, const char *ambiguousMember = nullptr,
+                       Qt::ShortcutContext context = Qt::WindowShortcut);
     ~QShortcut();
 
-    void setKey(const QKeySequence& key);
-    QKeySequence key() const;
-
-    void setEnabled(bool enable);
-    bool isEnabled() const;
-
-    void setContext(Qt::ShortcutContext context);
-    Qt::ShortcutContext context() const;
-
     void setWhatsThis(const QString &text);
     QString whatsThis() const;
 
-    void setAutoRepeat(bool on);
-    bool autoRepeat() const;
-
-    int id() const;
-
     inline QWidget *parentWidget() const
     { return static_cast<QWidget *>(QObject::parent()); }
-
-Q_SIGNALS:
-    void activated();
-    void activatedAmbiguously();
-
-protected:
-    bool event(QEvent *e) override;
 };
 
 QT_END_NAMESPACE
diff --git a/tests/auto/gui/kernel/kernel.pro b/tests/auto/gui/kernel/kernel.pro
index 134aca72f1..106e9050b8 100644
--- a/tests/auto/gui/kernel/kernel.pro
+++ b/tests/auto/gui/kernel/kernel.pro
@@ -11,6 +11,7 @@ SUBDIRS=\
    qguieventdispatcher \
    qguieventloop \
    qguimetatype \
+   qguishortcut \
    qguitimer \
    qguivariant \
    qhighdpiscaling \
@@ -33,6 +34,7 @@ win32:!winrt:qtHaveModule(network): SUBDIRS += noqteventloop
 
 !qtConfig(shortcut): SUBDIRS -= \
    qkeysequence \
+   qguishortcut \
    qguimetatype \
    qguivariant
 
diff --git a/tests/auto/gui/kernel/qguishortcut/qguishortcut.pro b/tests/auto/gui/kernel/qguishortcut/qguishortcut.pro
new file mode 100644
index 0000000000..1417dee213
--- /dev/null
+++ b/tests/auto/gui/kernel/qguishortcut/qguishortcut.pro
@@ -0,0 +1,4 @@
+CONFIG += testcase
+TARGET = tst_qguishortcut
+QT += testlib
+SOURCES += tst_qguishortcut.cpp
diff --git a/tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp b/tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp
new file mode 100644
index 0000000000..bc3fb9862d
--- /dev/null
+++ b/tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite 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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qguishortcut.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qrasterwindow.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qwindow.h>
+
+class tst_QGuiShortcut : public QObject
+{
+    Q_OBJECT
+public:
+
+private slots:
+    void trigger();
+};
+
+class ColoredWindow : public QRasterWindow {
+public:
+    ColoredWindow(QColor c) : m_color(c) {}
+
+protected:
+    void paintEvent(QPaintEvent *event) override;
+
+private:
+    const QColor m_color;
+};
+
+void ColoredWindow::paintEvent(QPaintEvent *)
+{
+    QPainter p(this);
+    p.fillRect(QRect(QPoint(), size()), m_color);
+}
+
+static void sendKey(QWindow *target, Qt::Key k, char c, Qt::KeyboardModifiers modifiers)
+{
+    QTest::sendKeyEvent(QTest::Press, target, k, c, modifiers);
+    QTest::sendKeyEvent(QTest::Release, target, k, c, modifiers);
+}
+
+void tst_QGuiShortcut::trigger()
+{
+    ColoredWindow w(Qt::yellow);
+    w.setTitle(QTest::currentTestFunction());
+    w.resize(QGuiApplication::primaryScreen()->size() / 4);
+    new QGuiShortcut(Qt::CTRL + Qt::Key_Q, &w, SLOT(close()));
+    w.show();
+    QVERIFY(QTest::qWaitForWindowExposed(&w));
+    sendKey(&w, Qt::Key_Q, 'q', Qt::ControlModifier);
+    QTRY_VERIFY(!w.isVisible());
+}
+
+QTEST_MAIN(tst_QGuiShortcut)
+#include "tst_qguishortcut.moc"