Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:06:18

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