Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:12:24

0001 // Copyright (C) 2021 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QTESTMOUSE_H
0005 #define QTESTMOUSE_H
0006 
0007 #if 0
0008 // inform syncqt
0009 #pragma qt_no_master_include
0010 #endif
0011 
0012 #include <QtTest/qttestglobal.h>
0013 #include <QtTest/qtestassert.h>
0014 #include <QtTest/qtestsystem.h>
0015 #include <QtTest/qtestspontaneevent.h>
0016 #include <QtCore/qpoint.h>
0017 #include <QtCore/qstring.h>
0018 #include <QtCore/qpointer.h>
0019 #include <QtGui/qevent.h>
0020 #include <QtGui/qwindow.h>
0021 
0022 #ifdef QT_WIDGETS_LIB
0023 #include <QtWidgets/qapplication.h>
0024 #include <QtWidgets/qwidget.h>
0025 #endif
0026 
0027 #include <QtCore/QDebug>
0028 
0029 QT_BEGIN_NAMESPACE
0030 
0031 Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global,
0032                                       Qt::MouseButtons state, Qt::MouseButton button,
0033                                       QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp);
0034 
0035 namespace QTestPrivate
0036 {
0037     extern Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons;
0038 }
0039 
0040 namespace QTest
0041 {
0042     enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDClick, MouseMove };
0043 
0044     extern Q_TESTLIB_EXPORT int lastMouseTimestamp;
0045 
0046     // This value is used to emulate timestamps to avoid creating double clicks by mistake.
0047     // Use this constant instead of QStyleHints::mouseDoubleClickInterval property to avoid tests
0048     // to depend on platform themes.
0049     static const int mouseDoubleClickInterval = 500;
0050 
0051     /*! \internal
0052         This function creates a QPA mouse event of type specified by \a action
0053         and calls QWindowSystemInterface::handleMouseEvent(), simulating the
0054         windowing system and bypassing the platform plugin. \a delay is the
0055         amount of time to be added to the simulated clock so that
0056         QInputEvent::timestamp() will be greater than that of the previous
0057         event. We expect all event-handling code to rely on the event
0058         timestamps, not the system clock; therefore tests can be run faster
0059         than real-time.
0060 
0061         If \a delay is not given, a default minimum mouse delay is used, and
0062         unintended double-click events are prevented by incrementing the
0063         timestamp by 500ms after each mouse release. Therefore, to test
0064         double-clicks, it's necessary to give a realistic \a delay value (for
0065         example, 10ms).
0066     */
0067     static void mouseEvent(MouseAction action, QWindow *window, Qt::MouseButton button,
0068                            Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
0069     {
0070         QTEST_ASSERT(window);
0071         extern int Q_TESTLIB_EXPORT defaultMouseDelay();
0072 
0073         // pos is in window local coordinates
0074         const QSize windowSize = window->geometry().size();
0075         if (windowSize.width() <= pos.x() || windowSize.height() <= pos.y()) {
0076             qWarning("Mouse event at %d, %d occurs outside target window (%dx%d).",
0077                      pos.x(), pos.y(), windowSize.width(), windowSize.height());
0078         }
0079 
0080         int actualDelay = (delay == -1 || delay < defaultMouseDelay()) ? defaultMouseDelay() : delay;
0081         lastMouseTimestamp += qMax(1, actualDelay);
0082 
0083         if (pos.isNull())
0084             pos = QPoint(window->width() / 2, window->height() / 2);
0085 
0086         QTEST_ASSERT(!stateKey || stateKey & Qt::KeyboardModifierMask);
0087 
0088         stateKey &= Qt::KeyboardModifierMask;
0089 
0090         QPointF global = window->mapToGlobal(pos);
0091         QPointer<QWindow> w(window);
0092 
0093         using namespace QTestPrivate;
0094         switch (action)
0095         {
0096         case MouseDClick:
0097             qtestMouseButtons.setFlag(button, true);
0098             qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonPress,
0099                                 stateKey, lastMouseTimestamp);
0100             qtestMouseButtons.setFlag(button, false);
0101             qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonRelease,
0102                                 stateKey, lastMouseTimestamp);
0103             Q_FALLTHROUGH();
0104         case MousePress:
0105         case MouseClick:
0106             qtestMouseButtons.setFlag(button, true);
0107             qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonPress,
0108                                 stateKey, lastMouseTimestamp);
0109             if (action == MousePress)
0110                 break;
0111             Q_FALLTHROUGH();
0112         case MouseRelease:
0113             qtestMouseButtons.setFlag(button, false);
0114             qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonRelease,
0115                                 stateKey, lastMouseTimestamp);
0116             if (delay == -1)
0117                 lastMouseTimestamp += mouseDoubleClickInterval; // avoid double clicks being generated
0118             break;
0119         case MouseMove:
0120             qt_handleMouseEvent(w, pos, global, qtestMouseButtons, Qt::NoButton, QEvent::MouseMove,
0121                                 stateKey, lastMouseTimestamp);
0122             break;
0123         default:
0124             QTEST_ASSERT(false);
0125         }
0126         qApp->processEvents();
0127     }
0128 
0129     inline void mousePress(QWindow *window, Qt::MouseButton button,
0130                            Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0131                            QPoint pos = QPoint(), int delay=-1)
0132     { mouseEvent(MousePress, window, button, stateKey, pos, delay); }
0133     inline void mouseRelease(QWindow *window, Qt::MouseButton button,
0134                              Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0135                              QPoint pos = QPoint(), int delay=-1)
0136     { mouseEvent(MouseRelease, window, button, stateKey, pos, delay); }
0137     inline void mouseClick(QWindow *window, Qt::MouseButton button,
0138                            Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0139                            QPoint pos = QPoint(), int delay=-1)
0140     { mouseEvent(MouseClick, window, button, stateKey, pos, delay); }
0141     inline void mouseDClick(QWindow *window, Qt::MouseButton button,
0142                             Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0143                             QPoint pos = QPoint(), int delay=-1)
0144     { mouseEvent(MouseDClick, window, button, stateKey, pos, delay); }
0145     inline void mouseMove(QWindow *window, QPoint pos = QPoint(), int delay=-1)
0146     { mouseEvent(MouseMove, window, Qt::NoButton, Qt::KeyboardModifiers(), pos, delay); }
0147 
0148 #ifdef QT_WIDGETS_LIB
0149     static void mouseEvent(MouseAction action, QWidget *widget, Qt::MouseButton button,
0150                            Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
0151     {
0152         QTEST_ASSERT(widget);
0153 
0154         if (pos.isNull())
0155             pos = widget->rect().center();
0156 
0157 #ifdef QTEST_QPA_MOUSE_HANDLING
0158         QWindow *w = widget->window()->windowHandle();
0159         QTEST_ASSERT(w);
0160         mouseEvent(action, w, button, stateKey, w->mapFromGlobal(widget->mapToGlobal(pos)), delay);
0161 #else
0162         extern int Q_TESTLIB_EXPORT defaultMouseDelay();
0163 
0164         if (delay == -1 || delay < defaultMouseDelay())
0165             delay = defaultMouseDelay();
0166         lastMouseTimestamp += qMax(1, delay);
0167 
0168         if (action == MouseClick) {
0169             mouseEvent(MousePress, widget, button, stateKey, pos);
0170             mouseEvent(MouseRelease, widget, button, stateKey, pos);
0171             return;
0172         }
0173 
0174         QTEST_ASSERT(!stateKey || stateKey & Qt::KeyboardModifierMask);
0175 
0176         stateKey &= Qt::KeyboardModifierMask;
0177 
0178         QEvent::Type meType = QEvent::None;
0179         using namespace QTestPrivate;
0180         switch (action)
0181         {
0182             case MousePress:
0183                 qtestMouseButtons.setFlag(button, true);
0184                 meType = QEvent::MouseButtonPress;
0185                 break;
0186             case MouseRelease:
0187                 qtestMouseButtons.setFlag(button, false);
0188                 meType = QEvent::MouseButtonRelease;
0189                 break;
0190             case MouseDClick:
0191                 qtestMouseButtons.setFlag(button, true);
0192                 meType = QEvent::MouseButtonDblClick;
0193                 break;
0194             case MouseMove:
0195                 // ### Qt 7: compatibility with < Qt 6.3, we should not rely on QCursor::setPos
0196                 // for generating mouse move events, and code that depends on QCursor::pos should
0197                 // be tested using QCursor::setPos explicitly.
0198                 if (qtestMouseButtons == Qt::NoButton) {
0199                     QCursor::setPos(widget->mapToGlobal(pos));
0200                     qApp->processEvents();
0201                     return;
0202                 }
0203                 meType = QEvent::MouseMove;
0204                 break;
0205             default:
0206                 QTEST_ASSERT(false);
0207         }
0208         QMouseEvent me(meType, pos, widget->mapToGlobal(pos), button, qtestMouseButtons, stateKey, QPointingDevice::primaryPointingDevice());
0209         me.setTimestamp(lastMouseTimestamp);
0210         if (action == MouseRelease) // avoid double clicks being generated
0211             lastMouseTimestamp += mouseDoubleClickInterval;
0212 
0213         QSpontaneKeyEvent::setSpontaneous(&me);
0214         if (!qApp->notify(widget, &me)) {
0215             static const char *const mouseActionNames[] =
0216                 { "MousePress", "MouseRelease", "MouseClick", "MouseDClick", "MouseMove" };
0217             qWarning("Mouse event \"%s\" not accepted by receiving widget",
0218                      mouseActionNames[static_cast<int>(action)]);
0219         }
0220 #endif
0221     }
0222 
0223     inline void mousePress(QWidget *widget, Qt::MouseButton button,
0224                            Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0225                            QPoint pos = QPoint(), int delay=-1)
0226     { mouseEvent(MousePress, widget, button, stateKey, pos, delay); }
0227     inline void mouseRelease(QWidget *widget, Qt::MouseButton button,
0228                              Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0229                              QPoint pos = QPoint(), int delay=-1)
0230     { mouseEvent(MouseRelease, widget, button, stateKey, pos, delay); }
0231     inline void mouseClick(QWidget *widget, Qt::MouseButton button,
0232                            Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0233                            QPoint pos = QPoint(), int delay=-1)
0234     { mouseEvent(MouseClick, widget, button, stateKey, pos, delay); }
0235     inline void mouseDClick(QWidget *widget, Qt::MouseButton button,
0236                             Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(),
0237                             QPoint pos = QPoint(), int delay=-1)
0238     { mouseEvent(MouseDClick, widget, button, stateKey, pos, delay); }
0239     inline void mouseMove(QWidget *widget, QPoint pos = QPoint(), int delay=-1)
0240     { mouseEvent(MouseMove, widget, Qt::NoButton, Qt::KeyboardModifiers(), pos, delay); }
0241 #endif // QT_WIDGETS_LIB
0242 }
0243 
0244 QT_END_NAMESPACE
0245 
0246 #endif // QTESTMOUSE_H