From 8b0c6e6d68053b62b3b38e9a2cf24e39b6df9086 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 7 May 2010 10:44:34 +0200 Subject: Autotest, Mac: added more native key event testing Added a couple of more tests that checks, among others, modifier flags. It turns out that there are some issues related to this: 1. When releasing a key while holding the command modifier, we do not key at key up event from cocoa. 2. The AA_MacDontSwapCtrlAndMeta attribute turns out to be half-way implemented. This test will not fail on any of this issues. --- tests/auto/macnativeevents/expectedeventlist.cpp | 29 ++++-- tests/auto/macnativeevents/expectedeventlist.h | 2 +- tests/auto/macnativeevents/nativeeventlist.cpp | 8 +- tests/auto/macnativeevents/nativeeventlist.h | 1 + tests/auto/macnativeevents/qnativeevents_mac.cpp | 8 +- tests/auto/macnativeevents/tst_macnativeevents.cpp | 107 +++++++++++++++++++++ 6 files changed, 139 insertions(+), 16 deletions(-) diff --git a/tests/auto/macnativeevents/expectedeventlist.cpp b/tests/auto/macnativeevents/expectedeventlist.cpp index 0679dcb..82a594b 100644 --- a/tests/auto/macnativeevents/expectedeventlist.cpp +++ b/tests/auto/macnativeevents/expectedeventlist.cpp @@ -49,7 +49,9 @@ ExpectedEventList::ExpectedEventList(QObject *target) : QObject(target), eventCount(0) { target->installEventFilter(this); - debug = !qgetenv("NATIVEDEBUG").isEmpty(); + debug = qgetenv("NATIVEDEBUG").toInt(); + if (debug > 0) + qDebug() << "Debug level sat to:" << debug; } ExpectedEventList::~ExpectedEventList() @@ -104,14 +106,17 @@ void ExpectedEventList::compareMouseEvents(QEvent *received, QEvent *expected) && (e1->globalPos() == e2->globalPos()) && (e1->button() == e2->button()) && (e1->buttons() == e2->buttons()) - && (e1->modifiers() == e2->modifiers())) + && (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) { + if (debug == 0) { qWarning() << "Expected event" << eventListNr << "differs from received event:"; QCOMPARE(e1->pos(), e2->pos()); QCOMPARE(e1->globalPos(), e2->globalPos()); @@ -135,14 +140,17 @@ void ExpectedEventList::compareKeyEvents(QEvent *received, QEvent *expected) if (e1->key() == e2->key() && (e1->modifiers() == e2->modifiers()) && (e1->count() == e2->count()) - && (e1->isAutoRepeat() == e2->isAutoRepeat())) + && (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) { + if (debug == 0) { qWarning() << "Expected event" << eventListNr << "differs from received event:"; QCOMPARE(e1->key(), e2->key()); QCOMPARE(e1->modifiers(), e2->modifiers()); @@ -150,18 +158,19 @@ void ExpectedEventList::compareKeyEvents(QEvent *received, QEvent *expected) QCOMPARE(e1->isAutoRepeat(), e2->isAutoRepeat()); } else { qWarning() << "*** FAIL *** : Expected event" << eventListNr << "differs from received event:"; - qWarning() << "Received:" << e1 << e1->key(); - qWarning() << "Expected:" << e2 << e2->key(); + 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) + if (debug > 1) qDebug() << received; if (eventList.isEmpty()) return false; + bool eat = false; QEvent *expected = eventList.first(); if (expected->type() == received->type()) { eventList.removeFirst(); @@ -175,11 +184,13 @@ bool ExpectedEventList::eventFilter(QObject *, QEvent *received) 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: { @@ -198,6 +209,6 @@ bool ExpectedEventList::eventFilter(QObject *, QEvent *received) QAbstractEventDispatcher::instance()->interrupt(); } - return false; + return eat; } diff --git a/tests/auto/macnativeevents/expectedeventlist.h b/tests/auto/macnativeevents/expectedeventlist.h index bd9f358..21eb193 100644 --- a/tests/auto/macnativeevents/expectedeventlist.h +++ b/tests/auto/macnativeevents/expectedeventlist.h @@ -51,7 +51,7 @@ class ExpectedEventList : public QObject { QList eventList; QBasicTimer timer; - bool debug; + int debug; int eventCount; void timerEvent(QTimerEvent *); diff --git a/tests/auto/macnativeevents/nativeeventlist.cpp b/tests/auto/macnativeevents/nativeeventlist.cpp index 1a90ee0..f730377 100644 --- a/tests/auto/macnativeevents/nativeeventlist.cpp +++ b/tests/auto/macnativeevents/nativeeventlist.cpp @@ -47,7 +47,8 @@ NativeEventList::NativeEventList(int defaultWaitMs) , wait(false) , defaultWaitMs(defaultWaitMs) { - QString multiplier = qgetenv("NATIVEDEBUG"); + debug = qgetenv("NATIVEDEBUG").toInt(); + QString multiplier = qgetenv("NATIVEDEBUGSPEED"); if (!multiplier.isEmpty()) setTimeMultiplier(multiplier.toFloat()); } @@ -61,8 +62,11 @@ NativeEventList::~NativeEventList() void NativeEventList::sendNextEvent() { QNativeEvent *e = eventList.at(currIndex).second; - if (e) + if (e) { + if (debug > 0) + qDebug() << "Sending:" << *e; QNativeInput::sendNativeEvent(*e); + } waitNextEvent(); } diff --git a/tests/auto/macnativeevents/nativeeventlist.h b/tests/auto/macnativeevents/nativeeventlist.h index efcca43..9f9498d 100644 --- a/tests/auto/macnativeevents/nativeeventlist.h +++ b/tests/auto/macnativeevents/nativeeventlist.h @@ -76,6 +76,7 @@ private: int currIndex; bool wait; int defaultWaitMs; + int debug; }; #endif diff --git a/tests/auto/macnativeevents/qnativeevents_mac.cpp b/tests/auto/macnativeevents/qnativeevents_mac.cpp index 6c04bf3..cc12cc9 100644 --- a/tests/auto/macnativeevents/qnativeevents_mac.cpp +++ b/tests/auto/macnativeevents/qnativeevents_mac.cpp @@ -54,11 +54,11 @@ static Qt::KeyboardModifiers getModifiersFromQuartzEvent(CGEventRef inEvent) if (flags & kCGEventFlagMaskShift || flags & kCGEventFlagMaskAlphaShift) m |= Qt::ShiftModifier; if (flags & kCGEventFlagMaskControl) - m |= Qt::MetaModifier; + m |= Qt::ControlModifier; if (flags & kCGEventFlagMaskAlternate) m |= Qt::AltModifier; if (flags & kCGEventFlagMaskCommand) - m |= Qt::ControlModifier; + m |= Qt::MetaModifier; return m; } @@ -67,11 +67,11 @@ static void setModifiersFromQNativeEvent(CGEventRef inEvent, const QNativeEvent CGEventFlags flags = 0; if (event.modifiers.testFlag(Qt::ShiftModifier)) flags |= kCGEventFlagMaskShift; - if (event.modifiers.testFlag(Qt::MetaModifier)) + if (event.modifiers.testFlag(Qt::ControlModifier)) flags |= kCGEventFlagMaskControl; if (event.modifiers.testFlag(Qt::AltModifier)) flags |= kCGEventFlagMaskAlternate; - if (event.modifiers.testFlag(Qt::ControlModifier)) + if (event.modifiers.testFlag(Qt::MetaModifier)) flags |= kCGEventFlagMaskCommand; CGEventSetFlags(inEvent, flags); } diff --git a/tests/auto/macnativeevents/tst_macnativeevents.cpp b/tests/auto/macnativeevents/tst_macnativeevents.cpp index ffd0596..16638ce 100644 --- a/tests/auto/macnativeevents/tst_macnativeevents.cpp +++ b/tests/auto/macnativeevents/tst_macnativeevents.cpp @@ -48,6 +48,7 @@ #include "qnativeevents.h" #include "nativeeventlist.h" #include "expectedeventlist.h" +#include #ifdef Q_OS_MAC @@ -68,6 +69,10 @@ private slots: void testMouseEnter(); void testChildDialogInFrontOfModalParent(); void testKeyPressOnToplevel(); + void testModifierShift(); + void testModifierAlt(); + void testModifierCtrl(); + void testModifierCtrlWithDontSwapCtrlAndMeta(); }; void tst_MacNativeEvents::testMouseMoveLocation() @@ -330,6 +335,108 @@ void tst_MacNativeEvents::testKeyPressOnToplevel() 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 realised 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) -- cgit v0.12