qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,39 @@
# QTBUG-22775
[testDragWindow]
osx
[testMouseEnter]
osx
[testChildDialogInFrontOfModalParent]
osx
[testChildWindowInFrontOfStaysOnTopParentWindow]
osx
[testMouseMoveLocation]
osx
[testMouseLeftDoubleClick]
osx
[stressTestMouseLeftDoubleClick]
osx
[testMouseDragInside]
osx
[testMouseDragOutside]
osx
[testMouseDragToNonClientArea]
osx
macos ci
# The following key tests fail after switching to synchronous
# expose events, and we don't know why yet. QTBUG-62042
[testKeyPressOnToplevel]
osx
[testModifierShift]
osx
[testModifierAlt]
osx
[testModifierCtrl]
osx
# QTQAINFRA-1292
[testPushButtonPressRelease]
macos ci
# QTQAINFRA-1292
[testModifierCtrlWithDontSwapCtrlAndMeta]
macos ci

View File

@ -0,0 +1,23 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT APPLE)
return()
endif()
#####################################################################
## tst_macnativeevents Test:
#####################################################################
qt_internal_add_test(tst_macnativeevents
SOURCES
expectedeventlist.cpp expectedeventlist.h
nativeeventlist.cpp nativeeventlist.h
qnativeevents.cpp qnativeevents.h
qnativeevents_mac.cpp
tst_macnativeevents.cpp
LIBRARIES
${FWAppKit}
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,176 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "expectedeventlist.h"
#include <QDebug>
#include <QCoreApplication>
#include <QAbstractEventDispatcher>
#include <QTest>
ExpectedEventList::ExpectedEventList(QObject *target)
: QObject(target), eventCount(0)
{
target->installEventFilter(this);
debug = qgetenv("NATIVEDEBUG").toInt();
if (debug > 0)
qDebug() << "Debug level sat to:" << debug;
}
ExpectedEventList::~ExpectedEventList()
{
qDeleteAll(eventList);
}
void ExpectedEventList::append(QEvent *e)
{
eventList.append(e);
++eventCount;
}
void ExpectedEventList::timerEvent(QTimerEvent *)
{
timer.stop();
QAbstractEventDispatcher::instance()->interrupt();
}
bool ExpectedEventList::waitForAllEvents(int maxEventWaitTime)
{
if (eventList.isEmpty())
return true;
int eventCount = eventList.size();
timer.start(maxEventWaitTime, this);
while (timer.isActive()) {
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
if (eventList.isEmpty())
return true;
if (eventCount < eventList.size()){
eventCount = eventList.size();
timer.start(maxEventWaitTime, this);
}
}
int eventListNr = eventCount - eventList.size() + 1;
qWarning() << "Stopped waiting for expected event nr" << eventListNr;
return false;
}
void ExpectedEventList::compareMouseEvents(QEvent *received, QEvent *expected)
{
QMouseEvent *e1 = static_cast<QMouseEvent *>(received);
QMouseEvent *e2 = static_cast<QMouseEvent *>(expected);
// Do a manual check first to be able to write more sensible
// debug output if we know we're going to fail:
if (e1->pos() == e2->pos()
&& (e1->globalPos() == e2->globalPos())
&& (e1->button() == e2->button())
&& (e1->buttons() == e2->buttons())
&& (e1->modifiers() == e2->modifiers())) {
if (debug > 0)
qDebug() << " Received (OK):" << e1 << e1->globalPos();
return; // equal
}
// INVARIANT: The two events are not equal. So we fail. Depending
// on whether debug mode is no or not, we let QTest fail. Otherwise
// we let the test continue for debugging puposes.
int eventListNr = eventCount - eventList.size();
if (debug == 0) {
qWarning() << "Expected event" << eventListNr << "differs from received event:";
QCOMPARE(e1->pos(), e2->pos());
QCOMPARE(e1->globalPos(), e2->globalPos());
QCOMPARE(e1->button(), e2->button());
QCOMPARE(e1->buttons(), e2->buttons());
QCOMPARE(e1->modifiers(), e2->modifiers());
} else {
qWarning() << "*** FAIL *** : Expected event" << eventListNr << "differs from received event:";
qWarning() << "Received:" << e1 << e1->globalPos();
qWarning() << "Expected:" << e2 << e2->globalPos();
}
}
void ExpectedEventList::compareKeyEvents(QEvent *received, QEvent *expected)
{
QKeyEvent *e1 = static_cast<QKeyEvent *>(received);
QKeyEvent *e2 = static_cast<QKeyEvent *>(expected);
// Do a manual check first to be able to write more sensible
// debug output if we know we're going to fail:
if (e1->key() == e2->key()
&& (e1->modifiers() == e2->modifiers())
&& (e1->count() == e2->count())
&& (e1->isAutoRepeat() == e2->isAutoRepeat())) {
if (debug > 0)
qDebug() << " Received (OK):" << e1 << QKeySequence(e1->key()).toString(QKeySequence::NativeText);
return; // equal
}
// INVARIANT: The two events are not equal. So we fail. Depending
// on whether debug mode is no or not, we let QTest fail. Otherwise
// we let the test continue for debugging puposes.
int eventListNr = eventCount - eventList.size();
if (debug == 0) {
qWarning() << "Expected event" << eventListNr << "differs from received event:";
QCOMPARE(e1->key(), e2->key());
QCOMPARE(e1->modifiers(), e2->modifiers());
QCOMPARE(e1->count(), e2->count());
QCOMPARE(e1->isAutoRepeat(), e2->isAutoRepeat());
} else {
qWarning() << "*** FAIL *** : Expected event" << eventListNr << "differs from received event:";
qWarning() << "Received:" << e1 << QKeySequence(e1->key()).toString(QKeySequence::NativeText);
qWarning() << "Expected:" << e2 << QKeySequence(e2->key()).toString(QKeySequence::NativeText);
}
}
bool ExpectedEventList::eventFilter(QObject *, QEvent *received)
{
if (debug > 1)
qDebug() << received;
if (eventList.isEmpty())
return false;
bool eat = false;
QEvent *expected = eventList.first();
if (expected->type() == received->type()) {
eventList.removeFirst();
switch (received->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseMove:
case QEvent::MouseButtonDblClick:
case QEvent::NonClientAreaMouseButtonPress:
case QEvent::NonClientAreaMouseButtonRelease:
case QEvent::NonClientAreaMouseButtonDblClick:
case QEvent::NonClientAreaMouseMove: {
compareMouseEvents(received, expected);
eat = true;
break;
}
case QEvent::KeyPress:
case QEvent::KeyRelease: {
compareKeyEvents(received, expected);
eat = true;
break;
}
case QEvent::Resize: {
break;
}
case QEvent::WindowActivate: {
break;
}
case QEvent::WindowDeactivate: {
break;
}
default:
break;
}
if (eventList.isEmpty())
QAbstractEventDispatcher::instance()->interrupt();
}
return eat;
}

View File

@ -0,0 +1,33 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef EVENTFILTER
#define EVENTFILTER
#include <QWidget>
#include <QList>
#include <QEvent>
#include <QBasicTimer>
class ExpectedEventList : public QObject
{
QList<QEvent *> eventList;
QBasicTimer timer;
int debug;
int eventCount;
void timerEvent(QTimerEvent *);
public:
ExpectedEventList(QObject *target);
~ExpectedEventList();
void append(QEvent *e);
bool waitForAllEvents(int timeoutPerEvent = 2000);
bool eventFilter(QObject *obj, QEvent *event);
private:
void compareMouseEvents(QEvent *event1, QEvent *event2);
void compareKeyEvents(QEvent *event1, QEvent *event2);
};
#endif

View File

@ -0,0 +1,76 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "nativeeventlist.h"
NativeEventList::NativeEventList(int defaultWaitMs)
: playbackMultiplier(1.0)
, currIndex(-1)
, wait(false)
, defaultWaitMs(defaultWaitMs)
{
debug = qgetenv("NATIVEDEBUG").toInt();
QString multiplier = qgetenv("NATIVEDEBUGSPEED");
if (!multiplier.isEmpty())
setTimeMultiplier(multiplier.toFloat());
}
NativeEventList::~NativeEventList()
{
for (int i=0; i<eventList.size(); i++)
delete eventList.takeAt(i).second;
}
void NativeEventList::sendNextEvent()
{
QNativeEvent *e = eventList.at(currIndex).second;
if (e) {
if (debug > 0)
qDebug() << "Sending:" << *e;
QNativeInput::sendNativeEvent(*e);
}
waitNextEvent();
}
void NativeEventList::waitNextEvent()
{
if (++currIndex >= eventList.size()){
emit done();
stop();
return;
}
int interval = eventList.at(currIndex).first;
QTimer::singleShot(interval * playbackMultiplier, this, SLOT(sendNextEvent()));
}
void NativeEventList::append(QNativeEvent *event)
{
eventList.append(QPair<int, QNativeEvent *>(defaultWaitMs, event));
}
void NativeEventList::append(int waitMs, QNativeEvent *event)
{
eventList.append(QPair<int, QNativeEvent *>(waitMs, event));
}
void NativeEventList::play(Playback playback)
{
waitNextEvent();
wait = (playback == WaitUntilFinished);
while (wait)
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
void NativeEventList::stop()
{
wait = false;
QAbstractEventDispatcher::instance()->interrupt();
}
void NativeEventList::setTimeMultiplier(float multiplier)
{
playbackMultiplier = multiplier;
}

View File

@ -0,0 +1,44 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef Q_NATIVE_PLAYBACK
#define Q_NATIVE_PLAYBACK
#include <QtCore>
#include "qnativeevents.h"
class NativeEventList : public QObject
{
Q_OBJECT;
public:
enum Playback {ReturnImmediately, WaitUntilFinished};
NativeEventList(int defaultWaitMs = 20);
~NativeEventList();
void append(QNativeEvent *event);
void append(int waitMs, QNativeEvent *event = nullptr);
void play(Playback playback = WaitUntilFinished);
void stop();
void setTimeMultiplier(float multiplier);
signals:
void done();
private slots:
void sendNextEvent();
private:
void waitNextEvent();
QList<QPair<int, QNativeEvent *> > eventList;
float playbackMultiplier;
int currIndex;
bool wait;
int defaultWaitMs;
int debug;
};
#endif

View File

@ -0,0 +1,340 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qnativeevents.h"
QNativeInput::QNativeInput(bool subscribe)
{
if (subscribe)
subscribeForNativeEvents();
}
QNativeInput::~QNativeInput()
{
unsubscribeForNativeEvents();
}
void QNativeInput::notify(QNativeEvent *event)
{
nativeEvent(event);
}
void QNativeInput::nativeEvent(QNativeEvent *event)
{
switch (event->id()){
case QNativeMouseButtonEvent::eventId:{
QNativeMouseButtonEvent *e = static_cast<QNativeMouseButtonEvent *>(event);
(e->clickCount > 0) ? nativeMousePressEvent(e) : nativeMouseReleaseEvent(e);
break; }
case QNativeMouseMoveEvent::eventId:
nativeMouseMoveEvent(static_cast<QNativeMouseMoveEvent *>(event));
break;
case QNativeMouseDragEvent::eventId:
nativeMouseDragEvent(static_cast<QNativeMouseDragEvent *>(event));
break;
case QNativeMouseWheelEvent::eventId:
nativeMouseWheelEvent(static_cast<QNativeMouseWheelEvent *>(event));
break;
case QNativeKeyEvent::eventId:{
QNativeKeyEvent *e = static_cast<QNativeKeyEvent *>(event);
e->press ? nativeKeyPressEvent(e) : nativeKeyReleaseEvent(e);
break; }
case QNativeModifierEvent::eventId:
nativeModifierEvent(static_cast<QNativeModifierEvent *>(event));
break;
default:
break;
}
}
Qt::Native::Status QNativeInput::sendNativeEvent(const QNativeEvent &event)
{
switch (event.id()){
case QNativeMouseMoveEvent::eventId:
return sendNativeMouseMoveEvent(static_cast<const QNativeMouseMoveEvent &>(event));
case QNativeMouseButtonEvent::eventId:
return sendNativeMouseButtonEvent(static_cast<const QNativeMouseButtonEvent &>(event));
case QNativeMouseDragEvent::eventId:
return sendNativeMouseDragEvent(static_cast<const QNativeMouseDragEvent &>(event));
case QNativeMouseWheelEvent::eventId:
return sendNativeMouseWheelEvent(static_cast<const QNativeMouseWheelEvent &>(event));
case QNativeKeyEvent::eventId:
return sendNativeKeyEvent(static_cast<const QNativeKeyEvent &>(event));
case QNativeModifierEvent::eventId:
return sendNativeModifierEvent(static_cast<const QNativeModifierEvent &>(event));
case QNativeEvent::eventId:
qWarning() << "Warning: Cannot send a pure native event. Use a sub class.";
default:
return Qt::Native::Failure;
}
}
QNativeEvent::QNativeEvent(Qt::KeyboardModifiers modifiers)
: modifiers(modifiers){}
QNativeMouseEvent::QNativeMouseEvent(QPoint pos, Qt::KeyboardModifiers modifiers)
: QNativeEvent(modifiers), globalPos(pos){}
QNativeMouseMoveEvent::QNativeMouseMoveEvent(QPoint pos, Qt::KeyboardModifiers modifiers)
: QNativeMouseEvent(pos, modifiers){}
QNativeMouseButtonEvent::QNativeMouseButtonEvent(QPoint globalPos, Qt::MouseButton button, int clickCount, Qt::KeyboardModifiers modifiers)
: QNativeMouseEvent(globalPos, modifiers), button(button), clickCount(clickCount){}
QNativeMouseDragEvent::QNativeMouseDragEvent(QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)
: QNativeMouseButtonEvent(globalPos, button, true, modifiers){}
QNativeMouseWheelEvent::QNativeMouseWheelEvent(QPoint globalPos, int delta, Qt::KeyboardModifiers modifiers)
: QNativeMouseEvent(globalPos, modifiers), delta(delta){}
QNativeKeyEvent::QNativeKeyEvent(int nativeKeyCode, bool press, Qt::KeyboardModifiers modifiers)
: QNativeEvent(modifiers), nativeKeyCode(nativeKeyCode), press(press), character(QChar()){}
QNativeModifierEvent::QNativeModifierEvent(Qt::KeyboardModifiers modifiers, int nativeKeyCode)
: QNativeEvent(modifiers), nativeKeyCode(nativeKeyCode){}
QNativeKeyEvent::QNativeKeyEvent(int nativeKeyCode, bool press, QChar character, Qt::KeyboardModifiers modifiers)
: QNativeEvent(modifiers), nativeKeyCode(nativeKeyCode), press(press), character(character){}
static QString getButtonAsString(const QNativeMouseButtonEvent *e)
{
switch (e->button){
case Qt::LeftButton:
return "button = LeftButton";
break;
case Qt::RightButton:
return "button = RightButton";
break;
case Qt::MiddleButton:
return "button = MiddleButton";
break;
default:
return "button = Other";
break;
}
}
static QString getModifiersAsString(const QNativeEvent *e)
{
if (e->modifiers == 0)
return "modifiers = none";
QString tmp = "modifiers = ";
if (e->modifiers.testFlag(Qt::ShiftModifier))
tmp += "Shift";
if (e->modifiers.testFlag(Qt::ControlModifier))
tmp += "Control";
if (e->modifiers.testFlag(Qt::AltModifier))
tmp += "Alt";
if (e->modifiers.testFlag(Qt::MetaModifier))
tmp += "Meta";
return tmp;
}
static QString getPosAsString(QPoint pos)
{
return QString("QPoint(%1, %2)").arg(pos.x()).arg(pos.y());
}
static QString getBoolAsString(bool b)
{
return b ? QString("true") : QString("false");
}
QString QNativeMouseMoveEvent::toString() const
{
return QString("QNativeMouseMoveEvent(globalPos = %1 %2)").arg(getPosAsString(globalPos))
.arg(getModifiersAsString(this));
}
QString QNativeMouseButtonEvent::toString() const
{
return QString("QNativeMouseButtonEvent(globalPos = %1, %2, clickCount = %3, %4)").arg(getPosAsString(globalPos))
.arg(getButtonAsString(this)).arg(clickCount).arg(getModifiersAsString(this));
}
QString QNativeMouseDragEvent::toString() const
{
return QString("QNativeMouseDragEvent(globalPos = %1, %2, clickCount = %3, %4)").arg(getPosAsString(globalPos))
.arg(getButtonAsString(this)).arg(clickCount).arg(getModifiersAsString(this));
}
QString QNativeMouseWheelEvent::toString() const
{
return QString("QNativeMouseWheelEvent(globalPos = %1, delta = %2, %3)").arg(getPosAsString(globalPos))
.arg(delta).arg(getModifiersAsString(this));
}
QString QNativeKeyEvent::toString() const
{
return QString("QNativeKeyEvent(press = %1, native key code = %2, character = %3, %4)").arg(getBoolAsString(press))
.arg(nativeKeyCode).arg(character.isPrint() ? character : QString("<no char>"))
.arg(getModifiersAsString(this));
}
QString QNativeModifierEvent::toString() const
{
return QString("QNativeModifierEvent(%1, native key code = %2)").arg(getModifiersAsString(this))
.arg(nativeKeyCode);
}
QDebug operator<<(QDebug d, QNativeEvent *e)
{
Q_UNUSED(e);
return d << e->toString();
}
QDebug operator<<(QDebug d, const QNativeEvent &e)
{
Q_UNUSED(e);
return d << e.toString();
}
QTextStream &operator<<(QTextStream &s, QNativeEvent *e)
{
return s << e->eventId << ' ' << e->modifiers << " QNativeEvent";
}
QTextStream &operator<<(QTextStream &s, QNativeMouseEvent *e)
{
return s << e->eventId << ' ' << e->globalPos.x() << ' ' << e->globalPos.y() << ' ' << e->modifiers << ' ' << e->toString();
}
QTextStream &operator<<(QTextStream &s, QNativeMouseMoveEvent *e)
{
return s << e->eventId << ' ' << e->globalPos.x() << ' ' << e->globalPos.y() << ' ' << e->modifiers << ' ' << e->toString();
}
QTextStream &operator<<(QTextStream &s, QNativeMouseButtonEvent *e)
{
return s << e->eventId << ' ' << e->globalPos.x() << ' ' << e->globalPos.y() << ' ' << e->button
<< ' ' << e->clickCount << ' ' << e->modifiers << ' ' << e->toString();
}
QTextStream &operator<<(QTextStream &s, QNativeMouseDragEvent *e)
{
return s << e->eventId << ' ' << e->globalPos.x() << ' ' << e->globalPos.y() << ' ' << e->button << ' ' << e->clickCount
<< ' ' << e->modifiers << ' ' << e->toString();
}
QTextStream &operator<<(QTextStream &s, QNativeMouseWheelEvent *e)
{
return s << e->eventId << ' ' << e->globalPos.x() << ' ' << e->globalPos.y() << ' ' << e->delta
<< ' ' << e->modifiers << ' ' << e->toString();
}
QTextStream &operator<<(QTextStream &s, QNativeKeyEvent *e)
{
return s << e->eventId << ' ' << e->press << ' ' << e->nativeKeyCode << ' ' << e->character
<< ' ' << e->modifiers << ' ' << e->toString();
}
QTextStream &operator<<(QTextStream &s, QNativeModifierEvent *e)
{
return s << e->eventId << ' ' << e->modifiers << ' ' << e->nativeKeyCode << ' ' << e->toString();
}
QTextStream &operator>>(QTextStream &s, QNativeMouseMoveEvent *e)
{
// Skip reading eventId.
QString humanReadable;
int x, y, modifiers;
s >> x >> y >> modifiers >> humanReadable;
e->globalPos.setX(x);
e->globalPos.setY(y);
e->modifiers = Qt::KeyboardModifiers(modifiers);
return s;
}
QTextStream &operator>>(QTextStream &s, QNativeMouseButtonEvent *e)
{
// Skip reading eventId.
QString humanReadable;
int x, y, button, clickCount, modifiers;
s >> x >> y >> button >> clickCount >> modifiers >> humanReadable;
e->globalPos.setX(x);
e->globalPos.setY(y);
e->clickCount = clickCount;
e->modifiers = Qt::KeyboardModifiers(modifiers);
switch (button){
case 1:
e->button = Qt::LeftButton;
break;
case 2:
e->button = Qt::RightButton;
break;
case 3:
e->button = Qt::MiddleButton;
break;
default:
e->button = Qt::NoButton;
break;
}
return s;
}
QTextStream &operator>>(QTextStream &s, QNativeMouseDragEvent *e)
{
// Skip reading eventId.
QString humanReadable;
int x, y, button, clickCount, modifiers;
s >> x >> y >> button >> clickCount >> modifiers >> humanReadable;
e->globalPos.setX(x);
e->globalPos.setY(y);
e->clickCount = clickCount;
e->modifiers = Qt::KeyboardModifiers(modifiers);
switch (button){
case 1:
e->button = Qt::LeftButton;
break;
case 2:
e->button = Qt::RightButton;
break;
case 3:
e->button = Qt::MiddleButton;
break;
default:
e->button = Qt::NoButton;
break;
}
return s;
}
QTextStream &operator>>(QTextStream &s, QNativeMouseWheelEvent *e)
{
// Skip reading eventId.
QString humanReadable;
int x, y, modifiers;
s >> x >> y >> e->delta >> modifiers >> humanReadable;
e->globalPos.setX(x);
e->globalPos.setY(y);
e->modifiers = Qt::KeyboardModifiers(modifiers);
return s;
}
QTextStream &operator>>(QTextStream &s, QNativeKeyEvent *e)
{
// Skip reading eventId.
QString humanReadable;
int press, modifiers;
QString character;
s >> press >> e->nativeKeyCode >> character >> modifiers >> humanReadable;
e->press = bool(press);
e->character = character[0];
e->modifiers = Qt::KeyboardModifiers(modifiers);
return s;
}
QTextStream &operator>>(QTextStream &s, QNativeModifierEvent *e)
{
// Skip reading eventId.
QString humanReadable;
int modifiers;
s >> modifiers >> e->nativeKeyCode >> humanReadable;
e->modifiers = Qt::KeyboardModifiers(modifiers);
return s;
}

View File

@ -0,0 +1,192 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef Q_NATIVE_INPUT
#define Q_NATIVE_INPUT
#include <QtCore>
QT_BEGIN_NAMESPACE
namespace Qt {
namespace Native {
enum Status {Success, Failure};
}}
QT_END_NAMESPACE
// ----------------------------------------------------------------------------
// Declare a set of native events that can be used to communicate with
// client applications in an platform independent way
// ----------------------------------------------------------------------------
class QNativeEvent
{
public:
static const int eventId = 1;
QNativeEvent(Qt::KeyboardModifiers modifiers = Qt::NoModifier);
virtual ~QNativeEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const = 0;
Qt::KeyboardModifiers modifiers; // Yields for mouse events too.
};
class QNativeMouseEvent : public QNativeEvent {
public:
static const int eventId = 2;
QNativeMouseEvent() {}
QNativeMouseEvent(QPoint globalPos, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
virtual ~QNativeMouseEvent() {}
virtual int id() const { return eventId; }
QPoint globalPos;
};
class QNativeMouseMoveEvent : public QNativeMouseEvent {
public:
static const int eventId = 4;
QNativeMouseMoveEvent() {}
QNativeMouseMoveEvent(QPoint globalPos, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
virtual ~QNativeMouseMoveEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const;
};
class QNativeMouseButtonEvent : public QNativeMouseEvent {
public:
static const int eventId = 8;
QNativeMouseButtonEvent() {}
QNativeMouseButtonEvent(QPoint globalPos, Qt::MouseButton button, int clickCount, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
virtual ~QNativeMouseButtonEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const;
Qt::MouseButton button;
int clickCount;
};
class QNativeMouseDragEvent : public QNativeMouseButtonEvent {
public:
static const int eventId = 16;
QNativeMouseDragEvent() {}
QNativeMouseDragEvent(QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
virtual ~QNativeMouseDragEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const;
};
class QNativeMouseWheelEvent : public QNativeMouseEvent {
public:
static const int eventId = 32;
QNativeMouseWheelEvent() {}
QNativeMouseWheelEvent(QPoint globalPos, int delta, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
virtual ~QNativeMouseWheelEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const;
int delta;
};
class QNativeKeyEvent : public QNativeEvent {
public:
static const int eventId = 64;
QNativeKeyEvent() {}
QNativeKeyEvent(int nativeKeyCode, bool press, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
QNativeKeyEvent(int nativeKeyCode, bool press, QChar character, Qt::KeyboardModifiers modifiers);
virtual ~QNativeKeyEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const;
int nativeKeyCode;
bool press;
QChar character;
// Some Qt to Native mappings:
static int Key_A;
static int Key_B;
static int Key_C;
static int Key_1;
static int Key_Backspace;
static int Key_Enter;
static int Key_Del;
};
class QNativeModifierEvent : public QNativeEvent {
public:
static const int eventId = 128;
QNativeModifierEvent(Qt::KeyboardModifiers modifiers = Qt::NoModifier, int nativeKeyCode = 0);
virtual ~QNativeModifierEvent() {}
virtual int id() const { return eventId; }
virtual QString toString() const;
int nativeKeyCode;
};
// ----------------------------------------------------------------------------
// Declare a set of related output / input functions for convenience:
// ----------------------------------------------------------------------------
QDebug operator<<(QDebug d, QNativeEvent *e);
QDebug operator<<(QDebug d, const QNativeEvent &e);
QTextStream &operator<<(QTextStream &s, QNativeEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeMouseEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeMouseMoveEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeMouseButtonEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeMouseDragEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeMouseWheelEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeKeyEvent *e);
QTextStream &operator<<(QTextStream &s, QNativeModifierEvent *e);
QTextStream &operator>>(QTextStream &s, QNativeMouseMoveEvent *e);
QTextStream &operator>>(QTextStream &s, QNativeMouseButtonEvent *e);
QTextStream &operator>>(QTextStream &s, QNativeMouseDragEvent *e);
QTextStream &operator>>(QTextStream &s, QNativeMouseWheelEvent *e);
QTextStream &operator>>(QTextStream &s, QNativeKeyEvent *e);
QTextStream &operator>>(QTextStream &s, QNativeModifierEvent *e);
// ----------------------------------------------------------------------------
// Declare the main class that is supposed to be sub-classed by components
// that are to receive native events
// ----------------------------------------------------------------------------
class QNativeInput
{
public:
QNativeInput(bool subscribe = true);
virtual ~QNativeInput();
// Callback methods. Should be implemented by interested sub-classes:
void notify(QNativeEvent *event);
virtual void nativeEvent(QNativeEvent *event);
virtual void nativeMousePressEvent(QNativeMouseButtonEvent *) {}
virtual void nativeMouseReleaseEvent(QNativeMouseButtonEvent *) {}
virtual void nativeMouseMoveEvent(QNativeMouseMoveEvent *) {}
virtual void nativeMouseDragEvent(QNativeMouseDragEvent *) {}
virtual void nativeMouseWheelEvent(QNativeMouseWheelEvent *) {}
virtual void nativeKeyPressEvent(QNativeKeyEvent *) {}
virtual void nativeKeyReleaseEvent(QNativeKeyEvent *) {}
virtual void nativeModifierEvent(QNativeModifierEvent *) {}
// The following methods will differ in implementation from OS to OS:
static Qt::Native::Status sendNativeMouseButtonEvent(const QNativeMouseButtonEvent &event);
static Qt::Native::Status sendNativeMouseMoveEvent(const QNativeMouseMoveEvent &event);
static Qt::Native::Status sendNativeMouseDragEvent(const QNativeMouseDragEvent &event);
static Qt::Native::Status sendNativeMouseWheelEvent(const QNativeMouseWheelEvent &event);
static Qt::Native::Status sendNativeKeyEvent(const QNativeKeyEvent &event);
static Qt::Native::Status sendNativeModifierEvent(const QNativeModifierEvent &event);
// sendNativeEvent will NOT differ from OS to OS.
static Qt::Native::Status sendNativeEvent(const QNativeEvent &event);
// The following methods will differ in implementation from OS to OS:
Qt::Native::Status subscribeForNativeEvents();
Qt::Native::Status unsubscribeForNativeEvents();
};
#endif // Q_NATIVE_INPUT

View File

@ -0,0 +1,327 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qnativeevents.h"
#include <CoreGraphics/CoreGraphics.h>
#include <QtCore>
// ************************************************************
// Quartz
// ************************************************************
static Qt::KeyboardModifiers getModifiersFromQuartzEvent(CGEventRef inEvent)
{
Qt::KeyboardModifiers m;
CGEventFlags flags = CGEventGetFlags(inEvent);
if (flags & kCGEventFlagMaskShift || flags & kCGEventFlagMaskAlphaShift)
m |= Qt::ShiftModifier;
if (flags & kCGEventFlagMaskControl)
m |= Qt::ControlModifier;
if (flags & kCGEventFlagMaskAlternate)
m |= Qt::AltModifier;
if (flags & kCGEventFlagMaskCommand)
m |= Qt::MetaModifier;
return m;
}
static void setModifiersFromQNativeEvent(CGEventRef inEvent, const QNativeEvent &event)
{
CGEventFlags flags = CGEventFlags(0);
if (event.modifiers.testFlag(Qt::ShiftModifier))
flags = CGEventFlags(flags | kCGEventFlagMaskShift);
if (event.modifiers.testFlag(Qt::ControlModifier))
flags = CGEventFlags(flags | kCGEventFlagMaskControl);
if (event.modifiers.testFlag(Qt::AltModifier))
flags = CGEventFlags(flags | kCGEventFlagMaskAlternate);
if (event.modifiers.testFlag(Qt::MetaModifier))
flags = CGEventFlags(flags | kCGEventFlagMaskCommand);
CGEventSetFlags(inEvent, flags);
}
static QPoint getMouseLocationFromQuartzEvent(CGEventRef inEvent)
{
CGPoint pos = CGEventGetLocation(inEvent);
QPoint tmp;
tmp.setX(pos.x);
tmp.setY(pos.y);
return tmp;
}
static QChar getCharFromQuartzEvent(CGEventRef inEvent)
{
UniCharCount count = 0;
UniChar c;
CGEventKeyboardGetUnicodeString(inEvent, 1, &count, &c);
return QChar(c);
}
static CGEventRef EventHandler_Quartz(CGEventTapProxy proxy, CGEventType type, CGEventRef inEvent, void *refCon)
{
Q_UNUSED(proxy);
QNativeInput *nativeInput = static_cast<QNativeInput *>(refCon);
switch (type){
case kCGEventKeyDown:{
QNativeKeyEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
e.character = getCharFromQuartzEvent(inEvent);
e.press = true;
nativeInput->notify(&e);
break;
}
case kCGEventKeyUp:{
QNativeKeyEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
e.character = getCharFromQuartzEvent(inEvent);
e.press = false;
nativeInput->notify(&e);
break;
}
case kCGEventLeftMouseDown:{
QNativeMouseButtonEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
e.button = Qt::LeftButton;
nativeInput->notify(&e);
break;
}
case kCGEventLeftMouseUp:{
QNativeMouseButtonEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
e.clickCount = 0;
e.button = Qt::LeftButton;
nativeInput->notify(&e);
break;
}
case kCGEventRightMouseDown:{
QNativeMouseButtonEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
e.button = Qt::RightButton;
nativeInput->notify(&e);
break;
}
case kCGEventRightMouseUp:{
QNativeMouseButtonEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
e.clickCount = 0;
e.button = Qt::RightButton;
nativeInput->notify(&e);
break;
}
case kCGEventMouseMoved:{
QNativeMouseMoveEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
nativeInput->notify(&e);
break;
}
case kCGEventLeftMouseDragged:{
QNativeMouseDragEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
e.button = Qt::LeftButton;
nativeInput->notify(&e);
break;
}
case kCGEventScrollWheel:{
QNativeMouseWheelEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.delta = CGEventGetIntegerValueField(inEvent, kCGScrollWheelEventDeltaAxis1);
e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
nativeInput->notify(&e);
break;
}
case kCGEventFlagsChanged:{
QNativeModifierEvent e;
e.modifiers = getModifiersFromQuartzEvent(inEvent);
e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
nativeInput->notify(&e);
break;
}
}
return inEvent;
}
Qt::Native::Status insertEventHandler_Quartz(QNativeInput *nativeInput)
{
uid_t uid = geteuid();
if (uid != 0)
qWarning("MacNativeEvents: You must be root to listen for key events!");
CFMachPortRef port = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
CFRunLoopSourceRef eventSrc = CFMachPortCreateRunLoopSource(NULL, port, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), eventSrc, kCFRunLoopCommonModes);
return Qt::Native::Success;
}
Qt::Native::Status removeEventHandler_Quartz()
{
return Qt::Native::Success; // ToDo:
}
Qt::Native::Status sendNativeKeyEvent_Quartz(const QNativeKeyEvent &event)
{
CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press);
setModifiersFromQNativeEvent(e, event);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
return Qt::Native::Success;
}
Qt::Native::Status sendNativeMouseMoveEvent_Quartz(const QNativeMouseMoveEvent &event)
{
CGPoint pos;
pos.x = event.globalPos.x();
pos.y = event.globalPos.y();
CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft /* ignored */);
setModifiersFromQNativeEvent(e, event);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
return Qt::Native::Success;
}
Qt::Native::Status sendNativeMouseButtonEvent_Quartz(const QNativeMouseButtonEvent &event)
{
CGPoint pos;
pos.x = event.globalPos.x();
pos.y = event.globalPos.y();
CGEventType type = kCGEventNull;
if (event.button == Qt::LeftButton)
type = (event.clickCount > 0) ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
else if (event.button == Qt::RightButton)
type = (event.clickCount > 0) ? kCGEventRightMouseDown : kCGEventRightMouseUp;
else
type = (event.clickCount > 0) ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
// The mouseButton argument to CGEventCreateMouseEvent() is ignored unless the type
// is kCGEventOtherSomething, so defaulting to kCGMouseButtonLeft is fine.
CGMouseButton mouseButton = (type == kCGEventOtherMouseDown || type == kCGEventOtherMouseUp) ?
kCGMouseButtonCenter : kCGMouseButtonLeft;
CGEventRef e = CGEventCreateMouseEvent(0, type, pos, mouseButton);
setModifiersFromQNativeEvent(e, event);
CGEventSetIntegerValueField(e, kCGMouseEventClickState, event.clickCount);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
return Qt::Native::Success;
}
Qt::Native::Status sendNativeMouseDragEvent_Quartz(const QNativeMouseDragEvent &event)
{
CGPoint pos;
pos.x = event.globalPos.x();
pos.y = event.globalPos.y();
CGEventType type = kCGEventNull;
if (event.button == Qt::LeftButton)
type = kCGEventLeftMouseDragged;
else if (event.button == Qt::RightButton)
type = kCGEventRightMouseDragged;
else
type = kCGEventOtherMouseDragged;
// The mouseButton argument to CGEventCreateMouseEvent() is ignored unless the type
// is kCGEventOtherSomething, so defaulting to kCGMouseButtonLeft is fine.
CGMouseButton mouseButton = type == kCGEventOtherMouseDragged ? kCGMouseButtonCenter : kCGMouseButtonLeft;
CGEventRef e = CGEventCreateMouseEvent(0, type, pos, mouseButton);
setModifiersFromQNativeEvent(e, event);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
return Qt::Native::Success;
}
Qt::Native::Status sendNativeMouseWheelEvent_Quartz(const QNativeMouseWheelEvent &event)
{
CGPoint pos;
pos.x = event.globalPos.x();
pos.y = event.globalPos.y();
CGEventRef e = CGEventCreateScrollWheelEvent(0, kCGScrollEventUnitPixel, 1, 0);
CGEventSetIntegerValueField(e, kCGScrollWheelEventDeltaAxis1, event.delta);
CGEventSetLocation(e, pos);
setModifiersFromQNativeEvent(e, event);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
return Qt::Native::Success;
}
Qt::Native::Status sendNativeModifierEvent_Quartz(const QNativeModifierEvent &event)
{
CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, 0);
CGEventSetType(e, kCGEventFlagsChanged);
setModifiersFromQNativeEvent(e, event);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
return Qt::Native::Success;
}
// ************************************************************
// QNativeInput methods:
// ************************************************************
Qt::Native::Status QNativeInput::sendNativeMouseButtonEvent(const QNativeMouseButtonEvent &event)
{
return sendNativeMouseButtonEvent_Quartz(event);
}
Qt::Native::Status QNativeInput::sendNativeMouseMoveEvent(const QNativeMouseMoveEvent &event)
{
return sendNativeMouseMoveEvent_Quartz(event);
}
Qt::Native::Status QNativeInput::sendNativeMouseDragEvent(const QNativeMouseDragEvent &event)
{
return sendNativeMouseDragEvent_Quartz(event);
}
Qt::Native::Status QNativeInput::sendNativeMouseWheelEvent(const QNativeMouseWheelEvent &event)
{
return sendNativeMouseWheelEvent_Quartz(event);
}
Qt::Native::Status QNativeInput::sendNativeKeyEvent(const QNativeKeyEvent &event)
{
return sendNativeKeyEvent_Quartz(event);
}
Qt::Native::Status QNativeInput::sendNativeModifierEvent(const QNativeModifierEvent &event)
{
return sendNativeModifierEvent_Quartz(event);
}
Qt::Native::Status QNativeInput::subscribeForNativeEvents()
{
return insertEventHandler_Quartz(this);
}
Qt::Native::Status QNativeInput::unsubscribeForNativeEvents()
{
return removeEventHandler_Quartz();
}
// Some Qt to Mac mappings:
int QNativeKeyEvent::Key_A = 0;
int QNativeKeyEvent::Key_B = 11;
int QNativeKeyEvent::Key_C = 8;
int QNativeKeyEvent::Key_1 = 18;
int QNativeKeyEvent::Key_Backspace = 51;
int QNativeKeyEvent::Key_Enter = 36;
int QNativeKeyEvent::Key_Del = 117;

View File

@ -0,0 +1,490 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QApplication>
#include <QWidget>
#include <QDialog>
#include <QPushButton>
#include <QTest>
#include "qnativeevents.h"
#include "nativeeventlist.h"
#include "expectedeventlist.h"
QT_USE_NAMESPACE
// Unicode code points for the glyphs associated with these keys
// Defined by Carbon headers but not anywhere in Cocoa
static const int kControlUnicode = 0x2303;
static const int kCommandUnicode = 0x2318;
class tst_MacNativeEvents : public QObject
{
Q_OBJECT
private slots:
void testMouseMoveLocation();
void testPushButtonPressRelease();
void testMouseLeftDoubleClick();
void stressTestMouseLeftDoubleClick();
void testMouseDragInside();
void testMouseDragOutside();
void testMouseDragToNonClientArea();
void testDragWindow();
void testMouseEnter();
void testChildDialogInFrontOfModalParent();
// void testChildWindowInFrontOfParentWindow();
// void testChildToolWindowInFrontOfChildNormalWindow();
void testChildWindowInFrontOfStaysOnTopParentWindow();
void testKeyPressOnToplevel();
void testModifierShift();
void testModifierAlt();
void testModifierCtrl();
void testModifierCtrlWithDontSwapCtrlAndMeta();
};
void tst_MacNativeEvents::testMouseMoveLocation()
{
QWidget w;
w.setMouseTracking(true);
w.show();
QPoint p = w.geometry().center();
NativeEventList native;
native.append(new QNativeMouseMoveEvent(p, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(p), p, Qt::NoButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testPushButtonPressRelease()
{
// Check that a native mouse press and release generates the
// same qevents on a pushbutton:
QPushButton w("click me");
w.show();
QPoint p = w.geometry().center();
NativeEventList native;
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testMouseLeftDoubleClick()
{
// Check that a native double click makes
// the test widget receive a press-release-click-release:
QWidget w;
w.show();
QPoint p = w.geometry().center();
NativeEventList native;
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 2, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonDblClick, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::stressTestMouseLeftDoubleClick()
{
// Check that multiple, fast, double clicks makes
// the test widget receive correct click events
QWidget w;
w.show();
QPoint p = w.geometry().center();
NativeEventList native;
ExpectedEventList expected(&w);
for (int i=0; i<10; ++i){
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 2, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonDblClick, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
}
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testMouseDragInside()
{
// Check that a mouse drag inside a widget
// will cause press-move-release events to be delivered
QWidget w;
w.show();
QPoint p1 = w.geometry().center();
QPoint p2 = p1 - QPoint(10, 0);
QPoint p3 = p1 - QPoint(20, 0);
QPoint p4 = p1 - QPoint(30, 0);
NativeEventList native;
native.append(new QNativeMouseButtonEvent(p1, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(p2, Qt::LeftButton, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(p3, Qt::LeftButton, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(p4, Qt::LeftButton, 0, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p1), p1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(p2), p2, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(p3), p3, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p4), p4, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testMouseDragOutside()
{
// Check that if we drag the mouse from inside the
// widget, and release it outside, we still get mouse move
// and release events when the mouse is outside the widget.
QWidget w;
w.show();
QPoint inside1 = w.geometry().center();
QPoint inside2 = inside1 - QPoint(10, 0);
QPoint outside1 = w.geometry().topLeft() - QPoint(50, 0);
QPoint outside2 = outside1 - QPoint(10, 0);
NativeEventList native;
native.append(new QNativeMouseButtonEvent(inside1, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(inside2, Qt::LeftButton, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(outside1, Qt::LeftButton, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(outside2, Qt::LeftButton, 0, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(inside1), inside1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(inside2), inside2, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(outside1), outside1, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(outside2), outside2, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testMouseDragToNonClientArea()
{
// Check that if we drag the mouse from inside the
// widget, and release it on the title bar, we still get mouse move
// and release events when the mouse is on the title bar
QWidget w;
w.show();
QPoint inside1 = w.geometry().center();
QPoint inside2 = inside1 - QPoint(10, 0);
QPoint titlebar1 = w.geometry().topLeft() - QPoint(-100, 10);
QPoint titlebar2 = titlebar1 - QPoint(10, 0);
NativeEventList native;
native.append(new QNativeMouseButtonEvent(inside1, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(inside2, Qt::LeftButton, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(titlebar1, Qt::LeftButton, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(titlebar2, Qt::LeftButton, 0, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(inside1), inside1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(inside2), inside2, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(titlebar1), titlebar1, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(titlebar2), titlebar2, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testDragWindow()
{
// Check that if we drag the mouse from inside the
// widgets title bar, we get a move event on the window
QWidget w;
w.show();
QPoint titlebar = w.geometry().topLeft() - QPoint(-100, 10);
QPoint moveTo = titlebar + QPoint(100, 0);
NativeEventList native;
native.append(new QNativeMouseButtonEvent(titlebar, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseDragEvent(moveTo, Qt::LeftButton, Qt::NoModifier));
native.append(500, new QNativeMouseButtonEvent(moveTo, Qt::LeftButton, 0, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QMouseEvent(QEvent::NonClientAreaMouseButtonPress, w.mapFromGlobal(titlebar), titlebar, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
expected.append(new QMouseEvent(QEvent::NonClientAreaMouseButtonRelease, w.mapFromGlobal(titlebar), moveTo, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testMouseEnter()
{
// When a mouse enters a widget, both a mouse enter events and a
// mouse move event should be sent. Let's test this:
QWidget w;
w.setMouseTracking(true);
w.show();
QPoint outside = w.geometry().topLeft() - QPoint(50, 0);
QPoint inside = w.geometry().center();
NativeEventList native;
native.append(new QNativeMouseMoveEvent(outside, Qt::NoModifier));
native.append(new QNativeMouseMoveEvent(inside, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QEvent(QEvent::Enter));
expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(inside), inside, Qt::NoButton, Qt::NoButton, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testChildDialogInFrontOfModalParent()
{
QSKIP("Modal dialog causes later tests to fail, see QTBUG-58474");
// Test that a child dialog of a modal parent dialog is
// in front of the parent, and active:
QDialog parent;
parent.setWindowModality(Qt::ApplicationModal);
QDialog child(&parent);
QPushButton button("close", &child);
connect(&button, SIGNAL(clicked()), &child, SLOT(close()));
parent.show();
child.show();
QPoint inside = button.mapToGlobal(button.geometry().center());
// Post a click on the button to close the child dialog:
NativeEventList native;
native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 0, Qt::NoModifier));
native.play();
QTest::qWait(100);
QVERIFY(!child.isVisible());
}
#if 0
// This test is disabled as of Qt-4.7.4 because we cannot do it
// unless we use the Cocoa sub window API. But using that opens up
// a world of side effects that we cannot live with. So we rather
// not support child-on-top-of-parent instead.
void tst_MacNativeEvents::testChildWindowInFrontOfParentWindow()
{
// Test that a child window always stacks in front of its parent window.
// Do this by first click on the parent, then on the child window button.
QWidget parent;
QPushButton child("a button", &parent);
child.setWindowFlags(Qt::Window);
connect(&child, SIGNAL(clicked()), &child, SLOT(close()));
parent.show();
child.show();
QPoint parent_p = parent.geometry().bottomLeft() + QPoint(20, -20);
QPoint child_p = child.geometry().center();
NativeEventList native;
native.append(new QNativeMouseButtonEvent(parent_p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(parent_p, Qt::LeftButton, 0, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(child_p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(child_p, Qt::LeftButton, 0, Qt::NoModifier));
native.play();
QTest::qWait(100);
QVERIFY(!child.isVisible());
}
#endif
/* This test can be enabled once setStackingOrder has been fixed in qwidget_mac.mm
void tst_MacNativeEvents::testChildToolWindowInFrontOfChildNormalWindow()
{
// Test that a child tool window always stacks in front of normal sibling windows.
// Do this by first click on the sibling, then on the tool window button.
QWidget parent;
QWidget normalChild(&parent, Qt::Window);
QPushButton toolChild("a button", &parent);
toolChild.setWindowFlags(Qt::Tool);
connect(&toolChild, SIGNAL(clicked()), &toolChild, SLOT(close()));
parent.show();
normalChild.show();
toolChild.show();
QPoint normalChild_p = normalChild.geometry().bottomLeft() + QPoint(20, -20);
QPoint toolChild_p = toolChild.geometry().center();
NativeEventList native;
native.append(new QNativeMouseButtonEvent(normalChild_p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(normalChild_p, Qt::LeftButton, 0, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(toolChild_p, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(toolChild_p, Qt::LeftButton, 0, Qt::NoModifier));
native.play();
QTest::qWait(100);
QVERIFY(!toolChild.isVisible());
}
*/
void tst_MacNativeEvents::testChildWindowInFrontOfStaysOnTopParentWindow()
{
// Test that a child window stacks on top of a stays-on-top parent.
QWidget parent(0, Qt::WindowStaysOnTopHint);
QPushButton button("close", &parent);
button.setWindowFlags(Qt::Window);
connect(&button, SIGNAL(clicked()), &button, SLOT(close()));
parent.show();
button.show();
QPoint inside = button.geometry().center();
// Post a click on the button to close the child dialog:
NativeEventList native;
native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 1, Qt::NoModifier));
native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 0, Qt::NoModifier));
native.play();
QTest::qWait(100);
QVERIFY(!button.isVisible());
}
void tst_MacNativeEvents::testKeyPressOnToplevel()
{
// Check that we receive keyevents for
// toplevel widgets. For leagacy reasons, and according to Qt on
// other platforms (carbon port + linux), we should get these events
// even when the focus policy is set to Qt::NoFocus when there is no
// other focus widget on screen:
QWidget w;
w.show();
NativeEventList native;
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::NoModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testModifierShift()
{
QWidget w;
w.show();
NativeEventList native;
native.append(new QNativeModifierEvent(Qt::ShiftModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::ShiftModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::ShiftModifier));
native.append(new QNativeModifierEvent(Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier));
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::ShiftModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ShiftModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testModifierAlt()
{
QWidget w;
w.show();
NativeEventList native;
native.append(new QNativeModifierEvent(Qt::AltModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::AltModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::AltModifier));
native.append(new QNativeModifierEvent(Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Alt, Qt::NoModifier));
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::AltModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::AltModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Alt, Qt::AltModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testModifierCtrl()
{
// On Mac, we switch the Command and Control modifier by default, so that Command
// means Meta, and Control means Command. Lets check that this works:
QWidget w;
w.show();
QCOMPARE(ushort(kControlUnicode), QKeySequence(Qt::Key_Meta).toString(QKeySequence::NativeText).at(0).unicode());
QCOMPARE(ushort(kCommandUnicode), QKeySequence(Qt::Key_Control).toString(QKeySequence::NativeText).at(0).unicode());
NativeEventList native;
native.append(new QNativeModifierEvent(Qt::ControlModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::ControlModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::ControlModifier));
native.append(new QNativeModifierEvent(Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Meta, Qt::NoModifier));
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::MetaModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::MetaModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Meta, Qt::MetaModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
}
void tst_MacNativeEvents::testModifierCtrlWithDontSwapCtrlAndMeta()
{
// On Mac, we switch the Command and Control modifier by default, so that Command
// means Meta, and Control means Command. Lets check that the flag to swith off
// this behaviour works. While working on this test I realized that we actually
// don't (and never have) respected this flag for raw key events. Only for
// menus, through QKeySequence. I don't want to change this behaviour now, at
// least not until someone complains. So I choose to let the test just stop
// any unintended regressions instead. If we decide to resepect the flag at one
// point, fix the test.
QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
QWidget w;
w.show();
QCOMPARE(ushort(kCommandUnicode), QKeySequence(Qt::Key_Meta).toString(QKeySequence::NativeText).at(0).unicode());
QCOMPARE(ushort(kControlUnicode), QKeySequence(Qt::Key_Control).toString(QKeySequence::NativeText).at(0).unicode());
NativeEventList native;
native.append(new QNativeModifierEvent(Qt::ControlModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::ControlModifier));
native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::ControlModifier));
native.append(new QNativeModifierEvent(Qt::NoModifier));
ExpectedEventList expected(&w);
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier));
expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier));
expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Control, Qt::ControlModifier));
native.play();
QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta, false);
}
QTEST_MAIN(tst_MacNativeEvents)
#include "tst_macnativeevents.moc"