summaryrefslogtreecommitdiffstats
path: root/tests/auto/macnativeevents
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /tests/auto/macnativeevents
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/macnativeevents')
-rw-r--r--tests/auto/macnativeevents/expectedeventlist.cpp214
-rw-r--r--tests/auto/macnativeevents/expectedeventlist.h71
-rw-r--r--tests/auto/macnativeevents/macnativeevents.pro16
-rw-r--r--tests/auto/macnativeevents/nativeeventlist.cpp114
-rw-r--r--tests/auto/macnativeevents/nativeeventlist.h82
-rw-r--r--tests/auto/macnativeevents/qnativeevents.cpp378
-rw-r--r--tests/auto/macnativeevents/qnativeevents.h228
-rw-r--r--tests/auto/macnativeevents/qnativeevents_mac.cpp382
-rw-r--r--tests/auto/macnativeevents/tst_macnativeevents.cpp535
9 files changed, 2020 insertions, 0 deletions
diff --git a/tests/auto/macnativeevents/expectedeventlist.cpp b/tests/auto/macnativeevents/expectedeventlist.cpp
new file mode 100644
index 0000000000..78be0976d4
--- /dev/null
+++ b/tests/auto/macnativeevents/expectedeventlist.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "expectedeventlist.h"
+#include <QDebug>
+#include <QCoreApplication>
+#include <QAbstractEventDispatcher>
+#include <QtTest/QtTest>
+
+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;
+}
+
diff --git a/tests/auto/macnativeevents/expectedeventlist.h b/tests/auto/macnativeevents/expectedeventlist.h
new file mode 100644
index 0000000000..850c0a5362
--- /dev/null
+++ b/tests/auto/macnativeevents/expectedeventlist.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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
+
diff --git a/tests/auto/macnativeevents/macnativeevents.pro b/tests/auto/macnativeevents/macnativeevents.pro
new file mode 100644
index 0000000000..af34942b12
--- /dev/null
+++ b/tests/auto/macnativeevents/macnativeevents.pro
@@ -0,0 +1,16 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Wed Nov 29 22:24:47 2006
+######################################################################
+
+load(qttest_p4)
+TEMPLATE = app
+DEPENDPATH += .
+INCLUDEPATH += .
+LIBS += -framework Carbon
+
+HEADERS += qnativeevents.h nativeeventlist.h expectedeventlist.h
+SOURCES += qnativeevents.cpp qnativeevents_mac.cpp
+SOURCES += expectedeventlist.cpp nativeeventlist.cpp
+SOURCES += tst_macnativeevents.cpp
+
+requires(mac)
diff --git a/tests/auto/macnativeevents/nativeeventlist.cpp b/tests/auto/macnativeevents/nativeeventlist.cpp
new file mode 100644
index 0000000000..c3303c2fed
--- /dev/null
+++ b/tests/auto/macnativeevents/nativeeventlist.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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;
+}
+
diff --git a/tests/auto/macnativeevents/nativeeventlist.h b/tests/auto/macnativeevents/nativeeventlist.h
new file mode 100644
index 0000000000..551e9603ae
--- /dev/null
+++ b/tests/auto/macnativeevents/nativeeventlist.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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 = 0);
+
+ 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
diff --git a/tests/auto/macnativeevents/qnativeevents.cpp b/tests/auto/macnativeevents/qnativeevents.cpp
new file mode 100644
index 0000000000..a94643d8c1
--- /dev/null
+++ b/tests/auto/macnativeevents/qnativeevents.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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, int pid)
+{
+ 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), pid);
+ 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::MidButton:
+ return "button = MidButton";
+ 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::MidButton;
+ 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::MidButton;
+ 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;
+}
+
diff --git a/tests/auto/macnativeevents/qnativeevents.h b/tests/auto/macnativeevents/qnativeevents.h
new file mode 100644
index 0000000000..9c1219337e
--- /dev/null
+++ b/tests/auto/macnativeevents/qnativeevents.h
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q_NATIVE_INPUT
+#define Q_NATIVE_INPUT
+
+#include <QtCore>
+
+namespace Qt {
+namespace Native {
+ enum Status {Success, Failure};
+}}
+
+// ----------------------------------------------------------------------------
+// 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, int pid = 0);
+ static Qt::Native::Status sendNativeModifierEvent(const QNativeModifierEvent &event);
+ // sendNativeEvent will NOT differ from OS to OS.
+ static Qt::Native::Status sendNativeEvent(const QNativeEvent &event, int pid = 0);
+
+ // The following methods will differ in implementation from OS to OS:
+ Qt::Native::Status subscribeForNativeEvents();
+ Qt::Native::Status unsubscribeForNativeEvents();
+};
+
+#endif // Q_NATIVE_INPUT
diff --git a/tests/auto/macnativeevents/qnativeevents_mac.cpp b/tests/auto/macnativeevents/qnativeevents_mac.cpp
new file mode 100644
index 0000000000..ee08cc8adf
--- /dev/null
+++ b/tests/auto/macnativeevents/qnativeevents_mac.cpp
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnativeevents.h"
+#include <Carbon/Carbon.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 = 0;
+ if (event.modifiers.testFlag(Qt::ShiftModifier))
+ flags |= kCGEventFlagMaskShift;
+ if (event.modifiers.testFlag(Qt::ControlModifier))
+ flags |= kCGEventFlagMaskControl;
+ if (event.modifiers.testFlag(Qt::AltModifier))
+ flags |= kCGEventFlagMaskAlternate;
+ if (event.modifiers.testFlag(Qt::MetaModifier))
+ 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, int pid = 0)
+{
+ uid_t uid = geteuid();
+ if (uid != 0)
+ qWarning("MacNativeEvents: You must be root to listen for key events!");
+
+ CFMachPortRef port;
+ if (!pid){
+ port = CGEventTapCreate(kCGHIDEventTap,
+ kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
+ kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
+ } else {
+ ProcessSerialNumber psn;
+ GetProcessForPID(pid, &psn);
+ port = CGEventTapCreateForPSN(&psn,
+ kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
+ kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
+ }
+
+ CFRunLoopSourceRef eventSrc = CFMachPortCreateRunLoopSource(NULL, port, 0);
+ CFRunLoopAddSource((CFRunLoopRef) GetCFRunLoopFromEventLoop(GetMainEventLoop()),
+ eventSrc, kCFRunLoopCommonModes);
+
+ return Qt::Native::Success;
+}
+
+Qt::Native::Status removeEventHandler_Quartz()
+{
+ return Qt::Native::Success; // ToDo:
+}
+
+Qt::Native::Status sendNativeKeyEventToProcess_Quartz(const QNativeKeyEvent &event, int pid)
+{
+ ProcessSerialNumber psn;
+ GetProcessForPID(pid, &psn);
+
+ CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press);
+ setModifiersFromQNativeEvent(e, event);
+ SetFrontProcess(&psn);
+ CGEventPostToPSN(&psn, e);
+ CFRelease(e);
+ return Qt::Native::Success;
+}
+
+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, 0);
+ 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 = 0;
+ 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;
+
+ CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button);
+ 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 = 0;
+ if (event.button == Qt::LeftButton)
+ type = kCGEventLeftMouseDragged;
+ else if (event.button == Qt::RightButton)
+ type = kCGEventRightMouseDragged;
+ else
+ type = kCGEventOtherMouseDragged;
+
+ CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button);
+ 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, int pid)
+{
+ if (!pid)
+ return sendNativeKeyEvent_Quartz(event);
+ else
+ return sendNativeKeyEventToProcess_Quartz(event, pid);
+}
+
+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;
+
diff --git a/tests/auto/macnativeevents/tst_macnativeevents.cpp b/tests/auto/macnativeevents/tst_macnativeevents.cpp
new file mode 100644
index 0000000000..9c18a3ccd1
--- /dev/null
+++ b/tests/auto/macnativeevents/tst_macnativeevents.cpp
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QDialog>
+#include <QPushButton>
+#include <QtTest/QtTest>
+
+#include "qnativeevents.h"
+#include "nativeeventlist.h"
+#include "expectedeventlist.h"
+#include <Carbon/Carbon.h>
+
+#ifdef Q_OS_MAC
+
+QT_USE_NAMESPACE
+
+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();
+#ifdef QT_MAC_USE_COCOA
+// void testChildWindowInFrontOfParentWindow();
+// void testChildToolWindowInFrontOfChildNormalWindow();
+ void testChildWindowInFrontOfStaysOnTopParentWindow();
+#endif
+ 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 sendt. Lets 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()
+{
+ // 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());
+}
+
+#ifdef QT_MAC_USE_COCOA
+#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());
+}
+#endif
+
+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();
+
+ QVERIFY(kControlUnicode == QKeySequence(Qt::Key_Meta).toString(QKeySequence::NativeText)[0]);
+ QVERIFY(kCommandUnicode == QKeySequence(Qt::Key_Control).toString(QKeySequence::NativeText)[0]);
+
+ 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 the flag at one
+ // point, fix the test.
+ QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
+ QWidget w;
+ w.show();
+
+ QVERIFY(kCommandUnicode == QKeySequence(Qt::Key_Meta).toString(QKeySequence::NativeText)[0]);
+ QVERIFY(kControlUnicode == QKeySequence(Qt::Key_Control).toString(QKeySequence::NativeText)[0]);
+
+ 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::ControlModifier));
+ expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier));
+ expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Meta, Qt::ControlModifier));
+
+ native.play();
+ QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
+ QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta, false);
+}
+
+#include "tst_macnativeevents.moc"
+
+QTEST_MAIN(tst_MacNativeEvents)
+
+#else
+
+QTEST_NOOP_MAIN
+
+#endif