1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QApplication>
43 #include <QWidget>
44 #include <QDialog>
45 #include <QPushButton>
46 #include <QtTest/QtTest>
47 
48 #include "qnativeevents.h"
49 #include "nativeeventlist.h"
50 #include "expectedeventlist.h"
51 #include <Carbon/Carbon.h>
52 
53 #ifdef Q_OS_MAC
54 
55 QT_USE_NAMESPACE
56 
57 class tst_MacNativeEvents : public QObject
58 {
59 Q_OBJECT
60 private slots:
61     void testMouseMoveLocation();
62     void testPushButtonPressRelease();
63     void testMouseLeftDoubleClick();
64     void stressTestMouseLeftDoubleClick();
65     void testMouseDragInside();
66     void testMouseDragOutside();
67     void testMouseDragToNonClientArea();
68     void testDragWindow();
69     void testMouseEnter();
70     void testChildDialogInFrontOfModalParent();
71 #ifdef QT_MAC_USE_COCOA
72 //    void testChildWindowInFrontOfParentWindow();
73 //    void testChildToolWindowInFrontOfChildNormalWindow();
74     void testChildWindowInFrontOfStaysOnTopParentWindow();
75 #endif
76     void testKeyPressOnToplevel();
77     void testModifierShift();
78     void testModifierAlt();
79     void testModifierCtrl();
80     void testModifierCtrlWithDontSwapCtrlAndMeta();
81 };
82 
testMouseMoveLocation()83 void tst_MacNativeEvents::testMouseMoveLocation()
84 {
85     QWidget w;
86     w.setMouseTracking(true);
87     w.show();
88     QPoint p = w.geometry().center();
89 
90     NativeEventList native;
91     native.append(new QNativeMouseMoveEvent(p, Qt::NoModifier));
92 
93     ExpectedEventList expected(&w);
94     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(p), p, Qt::NoButton, Qt::NoButton, Qt::NoModifier));
95 
96     native.play();
97     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
98 }
99 
testPushButtonPressRelease()100 void tst_MacNativeEvents::testPushButtonPressRelease()
101 {
102     // Check that a native mouse press and release generates the
103     // same qevents on a pushbutton:
104     QPushButton w("click me");
105     w.show();
106     QPoint p = w.geometry().center();
107 
108     NativeEventList native;
109     native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 1, Qt::NoModifier));
110     native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
111 
112     ExpectedEventList expected(&w);
113     expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
114     expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
115 
116     native.play();
117     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
118 }
119 
testMouseLeftDoubleClick()120 void tst_MacNativeEvents::testMouseLeftDoubleClick()
121 {
122     // Check that a native double click makes
123     // the test widget receive a press-release-click-release:
124     QWidget w;
125     w.show();
126     QPoint p = w.geometry().center();
127 
128     NativeEventList native;
129     native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 1, Qt::NoModifier));
130     native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
131     native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 2, Qt::NoModifier));
132     native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
133 
134     ExpectedEventList expected(&w);
135     expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
136     expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
137     expected.append(new QMouseEvent(QEvent::MouseButtonDblClick, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
138     expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
139 
140     native.play();
141     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
142 }
143 
stressTestMouseLeftDoubleClick()144 void tst_MacNativeEvents::stressTestMouseLeftDoubleClick()
145 {
146     // Check that multiple, fast, double clicks makes
147     // the test widget receive correct click events
148     QWidget w;
149     w.show();
150     QPoint p = w.geometry().center();
151 
152     NativeEventList native;
153     ExpectedEventList expected(&w);
154 
155     for (int i=0; i<10; ++i){
156         native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 1, Qt::NoModifier));
157         native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
158         native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 2, Qt::NoModifier));
159         native.append(new QNativeMouseButtonEvent(p, Qt::LeftButton, 0, Qt::NoModifier));
160 
161         expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
162         expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
163         expected.append(new QMouseEvent(QEvent::MouseButtonDblClick, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
164         expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p), p, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
165     }
166 
167     native.play();
168     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
169 }
170 
testMouseDragInside()171 void tst_MacNativeEvents::testMouseDragInside()
172 {
173     // Check that a mouse drag inside a widget
174     // will cause press-move-release events to be delivered
175     QWidget w;
176     w.show();
177     QPoint p1 = w.geometry().center();
178     QPoint p2 = p1 - QPoint(10, 0);
179     QPoint p3 = p1 - QPoint(20, 0);
180     QPoint p4 = p1 - QPoint(30, 0);
181 
182     NativeEventList native;
183     native.append(new QNativeMouseButtonEvent(p1, Qt::LeftButton, 1, Qt::NoModifier));
184     native.append(new QNativeMouseDragEvent(p2, Qt::LeftButton, Qt::NoModifier));
185     native.append(new QNativeMouseDragEvent(p3, Qt::LeftButton, Qt::NoModifier));
186     native.append(new QNativeMouseButtonEvent(p4, Qt::LeftButton, 0, Qt::NoModifier));
187 
188     ExpectedEventList expected(&w);
189     expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(p1), p1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
190     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(p2), p2, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
191     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(p3), p3, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
192     expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(p4), p4, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
193 
194     native.play();
195     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
196 }
197 
testMouseDragOutside()198 void tst_MacNativeEvents::testMouseDragOutside()
199 {
200     // Check that if we drag the mouse from inside the
201     // widget, and release it outside, we still get mouse move
202     // and release events when the mouse is outside the widget.
203     QWidget w;
204     w.show();
205     QPoint inside1 = w.geometry().center();
206     QPoint inside2 = inside1 - QPoint(10, 0);
207     QPoint outside1 = w.geometry().topLeft() - QPoint(50, 0);
208     QPoint outside2 = outside1 - QPoint(10, 0);
209 
210     NativeEventList native;
211     native.append(new QNativeMouseButtonEvent(inside1, Qt::LeftButton, 1, Qt::NoModifier));
212     native.append(new QNativeMouseDragEvent(inside2, Qt::LeftButton, Qt::NoModifier));
213     native.append(new QNativeMouseDragEvent(outside1, Qt::LeftButton, Qt::NoModifier));
214     native.append(new QNativeMouseButtonEvent(outside2, Qt::LeftButton, 0, Qt::NoModifier));
215 
216     ExpectedEventList expected(&w);
217     expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(inside1), inside1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
218     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(inside2), inside2, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
219     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(outside1), outside1, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
220     expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(outside2), outside2, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
221 
222     native.play();
223     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
224 }
225 
testMouseDragToNonClientArea()226 void tst_MacNativeEvents::testMouseDragToNonClientArea()
227 {
228     // Check that if we drag the mouse from inside the
229     // widget, and release it on the title bar, we still get mouse move
230     // and release events when the mouse is on the title bar
231     QWidget w;
232     w.show();
233     QPoint inside1 = w.geometry().center();
234     QPoint inside2 = inside1 - QPoint(10, 0);
235     QPoint titlebar1 = w.geometry().topLeft() - QPoint(-100, 10);
236     QPoint titlebar2 = titlebar1 - QPoint(10, 0);
237 
238     NativeEventList native;
239     native.append(new QNativeMouseButtonEvent(inside1, Qt::LeftButton, 1, Qt::NoModifier));
240     native.append(new QNativeMouseDragEvent(inside2, Qt::LeftButton, Qt::NoModifier));
241     native.append(new QNativeMouseDragEvent(titlebar1, Qt::LeftButton, Qt::NoModifier));
242     native.append(new QNativeMouseButtonEvent(titlebar2, Qt::LeftButton, 0, Qt::NoModifier));
243 
244     ExpectedEventList expected(&w);
245     expected.append(new QMouseEvent(QEvent::MouseButtonPress, w.mapFromGlobal(inside1), inside1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
246     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(inside2), inside2, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
247     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(titlebar1), titlebar1, Qt::NoButton, Qt::LeftButton, Qt::NoModifier));
248     expected.append(new QMouseEvent(QEvent::MouseButtonRelease, w.mapFromGlobal(titlebar2), titlebar2, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
249 
250     native.play();
251     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
252 }
253 
testDragWindow()254 void tst_MacNativeEvents::testDragWindow()
255 {
256     // Check that if we drag the mouse from inside the
257     // widgets title bar, we get a move event on the window
258     QWidget w;
259     w.show();
260     QPoint titlebar = w.geometry().topLeft() - QPoint(-100, 10);
261     QPoint moveTo = titlebar + QPoint(100, 0);
262 
263     NativeEventList native;
264     native.append(new QNativeMouseButtonEvent(titlebar, Qt::LeftButton, 1, Qt::NoModifier));
265     native.append(new QNativeMouseDragEvent(moveTo, Qt::LeftButton, Qt::NoModifier));
266     native.append(500, new QNativeMouseButtonEvent(moveTo, Qt::LeftButton, 0, Qt::NoModifier));
267 
268     ExpectedEventList expected(&w);
269     expected.append(new QMouseEvent(QEvent::NonClientAreaMouseButtonPress, w.mapFromGlobal(titlebar), titlebar, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
270     expected.append(new QMouseEvent(QEvent::NonClientAreaMouseButtonRelease, w.mapFromGlobal(titlebar), moveTo, Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
271 
272     native.play();
273     bool waited = expected.waitForAllEvents();
274     if (!waited) {
275         QEXPECT_FAIL("", "QTBUG-26804", Continue);
276     }
277     QVERIFY2(waited, "the test did not receive all expected events!");
278 }
279 
testMouseEnter()280 void tst_MacNativeEvents::testMouseEnter()
281 {
282     // When a mouse enters a widget, both a mouse enter events and a
283     // mouse move event should be sendt. Lets test this:
284     QWidget w;
285     w.setMouseTracking(true);
286     w.show();
287     QPoint outside = w.geometry().topLeft() - QPoint(50, 0);
288     QPoint inside = w.geometry().center();
289 
290     NativeEventList native;
291     native.append(new QNativeMouseMoveEvent(outside, Qt::NoModifier));
292     native.append(new QNativeMouseMoveEvent(inside, Qt::NoModifier));
293 
294     ExpectedEventList expected(&w);
295     expected.append(new QEvent(QEvent::Enter));
296     expected.append(new QMouseEvent(QEvent::MouseMove, w.mapFromGlobal(inside), inside, Qt::NoButton, Qt::NoButton, Qt::NoModifier));
297 
298     native.play();
299     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
300 }
301 
testChildDialogInFrontOfModalParent()302 void tst_MacNativeEvents::testChildDialogInFrontOfModalParent()
303 {
304     // Test that a child dialog of a modal parent dialog is
305     // in front of the parent, and active:
306     QDialog parent;
307     parent.setWindowModality(Qt::ApplicationModal);
308     QDialog child(&parent);
309     QPushButton button("close", &child);
310     connect(&button, SIGNAL(clicked()), &child, SLOT(close()));
311     parent.show();
312     child.show();
313     QPoint inside = button.mapToGlobal(button.geometry().center());
314 
315     // Post a click on the button to close the child dialog:
316     NativeEventList native;
317     native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 1, Qt::NoModifier));
318     native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 0, Qt::NoModifier));
319 
320     native.play();
321     QTest::qWait(100);
322     QVERIFY(!child.isVisible());
323 }
324 
325 #ifdef QT_MAC_USE_COCOA
326 #if 0
327 // This test is disabled as of Qt-4.7.4 because we cannot do it
328 // unless we use the Cocoa sub window API. But using that opens up
329 // a world of side effects that we cannot live with. So we rather
330 // not support child-on-top-of-parent instead.
331 void tst_MacNativeEvents::testChildWindowInFrontOfParentWindow()
332 {
333     // Test that a child window always stacks in front of its parent window.
334     // Do this by first click on the parent, then on the child window button.
335     QWidget parent;
336     QPushButton child("a button", &parent);
337     child.setWindowFlags(Qt::Window);
338     connect(&child, SIGNAL(clicked()), &child, SLOT(close()));
339     parent.show();
340     child.show();
341 
342     QPoint parent_p = parent.geometry().bottomLeft() + QPoint(20, -20);
343     QPoint child_p = child.geometry().center();
344 
345     NativeEventList native;
346     native.append(new QNativeMouseButtonEvent(parent_p, Qt::LeftButton, 1, Qt::NoModifier));
347     native.append(new QNativeMouseButtonEvent(parent_p, Qt::LeftButton, 0, Qt::NoModifier));
348     native.append(new QNativeMouseButtonEvent(child_p, Qt::LeftButton, 1, Qt::NoModifier));
349     native.append(new QNativeMouseButtonEvent(child_p, Qt::LeftButton, 0, Qt::NoModifier));
350 
351     native.play();
352     QTest::qWait(100);
353     QVERIFY(!child.isVisible());
354 }
355 #endif
356 
357 /* This test can be enabled once setStackingOrder has been fixed in qwidget_mac.mm
358 void tst_MacNativeEvents::testChildToolWindowInFrontOfChildNormalWindow()
359 {
360     // Test that a child tool window always stacks in front of normal sibling windows.
361     // Do this by first click on the sibling, then on the tool window button.
362     QWidget parent;
363     QWidget normalChild(&parent, Qt::Window);
364     QPushButton toolChild("a button", &parent);
365     toolChild.setWindowFlags(Qt::Tool);
366     connect(&toolChild, SIGNAL(clicked()), &toolChild, SLOT(close()));
367     parent.show();
368     normalChild.show();
369     toolChild.show();
370 
371     QPoint normalChild_p = normalChild.geometry().bottomLeft() + QPoint(20, -20);
372     QPoint toolChild_p = toolChild.geometry().center();
373 
374     NativeEventList native;
375     native.append(new QNativeMouseButtonEvent(normalChild_p, Qt::LeftButton, 1, Qt::NoModifier));
376     native.append(new QNativeMouseButtonEvent(normalChild_p, Qt::LeftButton, 0, Qt::NoModifier));
377     native.append(new QNativeMouseButtonEvent(toolChild_p, Qt::LeftButton, 1, Qt::NoModifier));
378     native.append(new QNativeMouseButtonEvent(toolChild_p, Qt::LeftButton, 0, Qt::NoModifier));
379 
380     native.play();
381     QTest::qWait(100);
382     QVERIFY(!toolChild.isVisible());
383 }
384 */
testChildWindowInFrontOfStaysOnTopParentWindow()385 void tst_MacNativeEvents::testChildWindowInFrontOfStaysOnTopParentWindow()
386 {
387     // Test that a child window stacks on top of a stays-on-top parent.
388     QWidget parent(0, Qt::WindowStaysOnTopHint);
389     QPushButton button("close", &parent);
390     button.setWindowFlags(Qt::Window);
391     connect(&button, SIGNAL(clicked()), &button, SLOT(close()));
392     parent.show();
393     button.show();
394     QPoint inside = button.geometry().center();
395 
396     // Post a click on the button to close the child dialog:
397     NativeEventList native;
398     native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 1, Qt::NoModifier));
399     native.append(new QNativeMouseButtonEvent(inside, Qt::LeftButton, 0, Qt::NoModifier));
400 
401     native.play();
402     QTest::qWait(100);
403     QVERIFY(!button.isVisible());
404 }
405 #endif
406 
testKeyPressOnToplevel()407 void tst_MacNativeEvents::testKeyPressOnToplevel()
408 {
409     // Check that we receive keyevents for
410     // toplevel widgets. For leagacy reasons, and according to Qt on
411     // other platforms (carbon port + linux), we should get these events
412     // even when the focus policy is set to Qt::NoFocus when there is no
413     // other focus widget on screen:
414     QWidget w;
415     w.show();
416 
417     NativeEventList native;
418     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::NoModifier));
419     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::NoModifier));
420 
421     ExpectedEventList expected(&w);
422     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier));
423     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier));
424 
425     native.play();
426     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
427 }
428 
testModifierShift()429 void tst_MacNativeEvents::testModifierShift()
430 {
431     QWidget w;
432     w.show();
433 
434     NativeEventList native;
435     native.append(new QNativeModifierEvent(Qt::ShiftModifier));
436     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::ShiftModifier));
437     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::ShiftModifier));
438     native.append(new QNativeModifierEvent(Qt::NoModifier));
439 
440     ExpectedEventList expected(&w);
441     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier));
442     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::ShiftModifier));
443     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ShiftModifier));
444     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier));
445 
446     native.play();
447     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
448 }
449 
testModifierAlt()450 void tst_MacNativeEvents::testModifierAlt()
451 {
452     QWidget w;
453     w.show();
454 
455     NativeEventList native;
456     native.append(new QNativeModifierEvent(Qt::AltModifier));
457     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::AltModifier));
458     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::AltModifier));
459     native.append(new QNativeModifierEvent(Qt::NoModifier));
460 
461     ExpectedEventList expected(&w);
462     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Alt, Qt::NoModifier));
463     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::AltModifier));
464     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::AltModifier));
465     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Alt, Qt::AltModifier));
466 
467     native.play();
468     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
469 }
470 
testModifierCtrl()471 void tst_MacNativeEvents::testModifierCtrl()
472 {
473     // On Mac, we switch the Command and Control modifier by default, so that Command
474     // means Meta, and Control means Command. Lets check that this works:
475     QWidget w;
476     w.show();
477 
478     QVERIFY(kControlUnicode == QKeySequence(Qt::Key_Meta).toString(QKeySequence::NativeText)[0]);
479     QVERIFY(kCommandUnicode == QKeySequence(Qt::Key_Control).toString(QKeySequence::NativeText)[0]);
480 
481     NativeEventList native;
482     native.append(new QNativeModifierEvent(Qt::ControlModifier));
483     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::ControlModifier));
484     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::ControlModifier));
485     native.append(new QNativeModifierEvent(Qt::NoModifier));
486 
487     ExpectedEventList expected(&w);
488     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Meta, Qt::NoModifier));
489     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::MetaModifier));
490     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::MetaModifier));
491     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Meta, Qt::MetaModifier));
492 
493     native.play();
494     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
495 }
496 
testModifierCtrlWithDontSwapCtrlAndMeta()497 void tst_MacNativeEvents::testModifierCtrlWithDontSwapCtrlAndMeta()
498 {
499     // On Mac, we switch the Command and Control modifier by default, so that Command
500     // means Meta, and Control means Command. Lets check that the flag to swith off
501     // this behaviour works. While working on this test I realized that we actually
502     // don't (and never have) respected this flag for raw key events. Only for
503     // menus, through QKeySequence. I don't want to change this behaviour now, at
504     // least not until someone complains. So I choose to let the test just stop
505     // any unintended regressions instead. If we decide to resepect the the flag at one
506     // point, fix the test.
507     QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
508     QWidget w;
509     w.show();
510 
511     QVERIFY(kCommandUnicode == QKeySequence(Qt::Key_Meta).toString(QKeySequence::NativeText)[0]);
512     QVERIFY(kControlUnicode == QKeySequence(Qt::Key_Control).toString(QKeySequence::NativeText)[0]);
513 
514     NativeEventList native;
515     native.append(new QNativeModifierEvent(Qt::ControlModifier));
516     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, true, Qt::ControlModifier));
517     native.append(new QNativeKeyEvent(QNativeKeyEvent::Key_A, false, Qt::ControlModifier));
518     native.append(new QNativeModifierEvent(Qt::NoModifier));
519 
520     ExpectedEventList expected(&w);
521     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_Meta, Qt::NoModifier));
522     expected.append(new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier));
523     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier));
524     expected.append(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Meta, Qt::ControlModifier));
525 
526     native.play();
527     QVERIFY2(expected.waitForAllEvents(), "the test did not receive all expected events!");
528     QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta, false);
529 }
530 
531 #include "tst_macnativeevents.moc"
532 
533 QTEST_MAIN(tst_MacNativeEvents)
534 
535 #else
536 
537 QTEST_NOOP_MAIN
538 
539 #endif
540