Skip to content

Commit

Permalink
Send ShortcutOverride event when receiving a non-spontaneous key press
Browse files Browse the repository at this point in the history
When a key press is received which is not spontaneous then it needs to
be manually sent as a shortcut override event to ensure that any
matching shortcut is triggered first. This enables emulation/playback
of recorded events to still have the same effect.

[ChangeLog][QtWidgets] Sending a key press event with sendEvent() now
sends a ShortCutOverride event first to the widget to trigger any
shortcuts set first.

Task-number: QTBUG-48325
Change-Id: Iafcc2cdb1773bffe89edaeb0abc44cd5a51088e6
Reviewed-by: Richard Moe Gustavsen <[email protected]>
  • Loading branch information
AndyShawQt committed Apr 20, 2018
1 parent 941db4e commit 7c53289
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/widgets/kernel/qapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ QT_BEGIN_NAMESPACE
}

Q_CORE_EXPORT void qt_call_post_routines();
Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1);

QApplicationPrivate *QApplicationPrivate::self = 0;

Expand Down Expand Up @@ -3068,8 +3069,19 @@ bool QApplication::notify(QObject *receiver, QEvent *e)

switch (e->type()) {
case QEvent::KeyPress: {
int key = static_cast<QKeyEvent*>(e)->key();
qt_in_tab_key_event = (key == Qt::Key_Backtab
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e);
const int key = keyEvent->key();
// When a key press is received which is not spontaneous then it needs to
// be manually sent as a shortcut override event to ensure that any
// matching shortcut is triggered first. This enables emulation/playback
// of recorded events to still have the same effect.
if (!e->spontaneous() && receiver->isWidgetType()) {
if (qt_sendShortcutOverrideEvent(qobject_cast<QWidget *>(receiver), keyEvent->timestamp(),
key, keyEvent->modifiers(), keyEvent->text(),
keyEvent->isAutoRepeat(), keyEvent->count()))
return true;
}
qt_in_tab_key_event = (key == Qt::Key_Backtab
|| key == Qt::Key_Tab
|| key == Qt::Key_Left
|| key == Qt::Key_Up
Expand Down
37 changes: 37 additions & 0 deletions tests/auto/widgets/kernel/qaction/tst_qaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ private slots:
void keysequence(); // QTBUG-53381
void disableShortcutsWithBlockedWidgets_data();
void disableShortcutsWithBlockedWidgets();
void shortcutFromKeyEvent(); // QTBUG-48325

private:
int m_lastEventType;
Expand Down Expand Up @@ -509,5 +510,41 @@ void tst_QAction::disableShortcutsWithBlockedWidgets()
QCOMPARE(spy.count(), 0);
}

class ShortcutOverrideWidget : public QWidget
{
public:
ShortcutOverrideWidget(QWidget *parent = 0) : QWidget(parent), shortcutOverrideCount(0) {}
int shortcutOverrideCount;
protected:
bool event(QEvent *e)
{
if (e->type() == QEvent::ShortcutOverride)
++shortcutOverrideCount;
return QWidget::event(e);
}
};

// Test that a key press event sent with sendEvent() still gets handled as a possible
// ShortcutOverride event first before passing it on as a normal KeyEvent.
void tst_QAction::shortcutFromKeyEvent()
{
ShortcutOverrideWidget testWidget;
QAction action;
action.setShortcut(Qt::Key_1);
testWidget.addAction(&action);
testWidget.show();
QSignalSpy spy(&action, &QAction::triggered);
QVERIFY(spy.isValid());
QVERIFY(QTest::qWaitForWindowActive(&testWidget));
QCOMPARE(testWidget.shortcutOverrideCount, 0);

// Don't use the QTest::keyPress approach as this will take the
// shortcut route for us
QKeyEvent e(QEvent::KeyPress, Qt::Key_1, Qt::NoModifier);
QApplication::sendEvent(&testWidget, &e);
QCOMPARE(spy.count(), 1);
QCOMPARE(testWidget.shortcutOverrideCount, 1);
}

QTEST_MAIN(tst_QAction)
#include "tst_qaction.moc"

0 comments on commit 7c53289

Please sign in to comment.