QGuiApplication: fix handling of spontaneous events' modifiers

QtQuickTest synthetized events can have modifiers, but those modifiers
were not accessible globally, from QGuiApplication::keyboardModifiers
for instance.
eg. calling QML's TestCase::mouseClick with modifiers triggering a call
to QGuiApplication::keyboardModifiers did not give the expected result.

QtTest synthesised events can also have modifiers and those were
correctly handled by QApplication to set modifiers globally.

This fix moves the handling code from QApplication::notify to
QGuiApplicationPrivate::maybeSimulateModifiers and calls this function
from QGuiApplication::notify too.

The definite fix would be to do as suggested in the comment attached to
the moved code:
> Qt Test should not call qapp->notify(), but rather route the events
> through the proper QPA interface. This is required to properly
> generate all other events such as enter/leave etc.

Pick-to: 5.15 5.12
Change-Id: I734e5bbc82232b13828b1a1f82e06ee8eb695417
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Nicolas Guichard 2020-07-24 14:07:00 +02:00
parent 35d90cb898
commit 4b1ffab8ad
3 changed files with 58 additions and 53 deletions

View File

@ -1876,6 +1876,60 @@ int QGuiApplication::exec()
return QCoreApplication::exec();
}
void QGuiApplicationPrivate::captureGlobalModifierState(QEvent *e)
{
if (e->spontaneous()) {
// Capture the current mouse and keyboard states. Doing so here is
// required in order to support Qt Test synthesized events. Real mouse
// and keyboard state updates from the platform plugin are managed by
// QGuiApplicationPrivate::process(Mouse|Wheel|Key|Touch|Tablet)Event();
// ### FIXME: Qt Test should not call qapp->notify(), but rather route
// the events through the proper QPA interface. This is required to
// properly generate all other events such as enter/leave etc.
switch (e->type()) {
case QEvent::MouseButtonPress: {
QMouseEvent *me = static_cast<QMouseEvent *>(e);
QGuiApplicationPrivate::modifier_buttons = me->modifiers();
QGuiApplicationPrivate::mouse_buttons |= me->button();
break;
}
case QEvent::MouseButtonDblClick: {
QMouseEvent *me = static_cast<QMouseEvent *>(e);
QGuiApplicationPrivate::modifier_buttons = me->modifiers();
QGuiApplicationPrivate::mouse_buttons |= me->button();
break;
}
case QEvent::MouseButtonRelease: {
QMouseEvent *me = static_cast<QMouseEvent *>(e);
QGuiApplicationPrivate::modifier_buttons = me->modifiers();
QGuiApplicationPrivate::mouse_buttons &= ~me->button();
break;
}
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::MouseMove:
#if QT_CONFIG(wheelevent)
case QEvent::Wheel:
#endif
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
#if QT_CONFIG(tabletevent)
case QEvent::TabletMove:
case QEvent::TabletPress:
case QEvent::TabletRelease:
#endif
{
QInputEvent *ie = static_cast<QInputEvent *>(e);
QGuiApplicationPrivate::modifier_buttons = ie->modifiers();
break;
}
default:
break;
}
}
}
/*! \reimp
*/
bool QGuiApplication::notify(QObject *object, QEvent *event)
@ -1885,6 +1939,8 @@ bool QGuiApplication::notify(QObject *object, QEvent *event)
return true; // Platform plugin ate the event
}
QGuiApplicationPrivate::captureGlobalModifierState(event);
return QCoreApplication::notify(object, event);
}

View File

@ -109,6 +109,7 @@ public:
bool shouldQuitInternal(const QWindowList &processedWindows);
virtual bool tryCloseAllWindows();
static void captureGlobalModifierState(QEvent *e);
static Qt::KeyboardModifiers modifier_buttons;
static Qt::MouseButtons mouse_buttons;

View File

@ -2715,59 +2715,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
return true; // Platform plugin ate the event
}
if(e->spontaneous()) {
// Capture the current mouse and keyboard states. Doing so here is
// required in order to support Qt Test synthesized events. Real mouse
// and keyboard state updates from the platform plugin are managed by
// QGuiApplicationPrivate::process(Mouse|Wheel|Key|Touch|Tablet)Event();
// ### FIXME: Qt Test should not call qapp->notify(), but rather route
// the events through the proper QPA interface. This is required to
// properly generate all other events such as enter/leave etc.
switch (e->type()) {
case QEvent::MouseButtonPress:
{
QMouseEvent *me = static_cast<QMouseEvent*>(e);
QApplicationPrivate::modifier_buttons = me->modifiers();
QApplicationPrivate::mouse_buttons |= me->button();
break;
}
case QEvent::MouseButtonDblClick:
{
QMouseEvent *me = static_cast<QMouseEvent*>(e);
QApplicationPrivate::modifier_buttons = me->modifiers();
QApplicationPrivate::mouse_buttons |= me->button();
break;
}
case QEvent::MouseButtonRelease:
{
QMouseEvent *me = static_cast<QMouseEvent*>(e);
QApplicationPrivate::modifier_buttons = me->modifiers();
QApplicationPrivate::mouse_buttons &= ~me->button();
break;
}
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::MouseMove:
#if QT_CONFIG(wheelevent)
case QEvent::Wheel:
#endif
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
#if QT_CONFIG(tabletevent)
case QEvent::TabletMove:
case QEvent::TabletPress:
case QEvent::TabletRelease:
#endif
{
QInputEvent *ie = static_cast<QInputEvent*>(e);
QApplicationPrivate::modifier_buttons = ie->modifiers();
break;
}
default:
break;
}
}
QGuiApplicationPrivate::captureGlobalModifierState(e);
#ifndef QT_NO_GESTURES
// walk through parents and check for gestures