diff options
| -rw-r--r-- | src/plugins/platforms/winrt/qwinrtcursor.cpp | 40 | ||||
| -rw-r--r-- | src/plugins/platforms/winrt/qwinrtcursor.h | 1 | ||||
| -rw-r--r-- | src/plugins/platforms/winrt/qwinrtscreen.cpp | 59 | ||||
| -rw-r--r-- | src/plugins/platforms/winrt/qwinrtscreen.h | 9 | ||||
| -rw-r--r-- | tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 5 | ||||
| -rw-r--r-- | tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp | 3 | ||||
| -rw-r--r-- | tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 4 |
7 files changed, 112 insertions, 9 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index 3c918df935..6236ec1f2b 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -56,6 +56,11 @@ using namespace ABI::Windows::Foundation; QT_BEGIN_NAMESPACE +static inline bool qIsPointInRect(const Point &p, const Rect &r) +{ + return (p.X >= r.X && p.Y >= r.Y && p.X < r.X + r.Width && p.Y < r.Y + r.Height); +} + class QWinRTCursorPrivate { public: @@ -179,5 +184,40 @@ QPoint QWinRTCursor::pos() const : position; } +void QWinRTCursor::setPos(const QPoint &pos) +{ + QWinRTScreen *screen = static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle()); + Q_ASSERT(screen); + ComPtr<ICoreWindow> coreWindow = screen->coreWindow(); + Q_ASSERT(coreWindow); + const QPointF scaledPos = pos / screen->scaleFactor(); + QWinRTScreen::MousePositionTransition t; + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, scaledPos, &t]() { + ComPtr<ICoreWindow2> coreWindow2; + HRESULT hr = coreWindow.As(&coreWindow2); + RETURN_HR_IF_FAILED("Failed to cast core window."); + Rect bounds; + hr = coreWindow->get_Bounds(&bounds); + RETURN_HR_IF_FAILED("Failed to obtain window bounds."); + Point mousePos; + hr = coreWindow->get_PointerPosition(&mousePos); + RETURN_HR_IF_FAILED("Failed to obtain mouse position."); + const Point p = {FLOAT(scaledPos.x() + bounds.X), FLOAT(scaledPos.y() + bounds.Y)}; + const bool wasInWindow = qIsPointInRect(mousePos, bounds); + const bool willBeInWindow = qIsPointInRect(p, bounds); + if (wasInWindow && willBeInWindow) + t = QWinRTScreen::MousePositionTransition::StayedIn; + else if (wasInWindow && !willBeInWindow) + t = QWinRTScreen::MousePositionTransition::MovedOut; + else if (!wasInWindow && willBeInWindow) + t = QWinRTScreen::MousePositionTransition::MovedIn; + else + t = QWinRTScreen::MousePositionTransition::StayedOut; + return coreWindow2->put_PointerPosition(p); + }); + RETURN_VOID_IF_FAILED("Failed to set cursor position"); + screen->emulateMouseMove(scaledPos, t); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h index 7f579f1531..253827f38f 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.h +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -54,6 +54,7 @@ public: void changeCursor(QCursor * windowCursor, QWindow *window) override; #endif QPoint pos() const override; + void setPos(const QPoint &pos) override; private: QScopedPointer<QWinRTCursorPrivate> d_ptr; diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 7d6659f5e2..0c03c2865b 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -491,6 +491,7 @@ public: QAtomicPointer<QWinRTWindow> keyboardGrabWindow; QWindow *currentPressWindow = nullptr; QWindow *currentTargetWindow = nullptr; + bool firstMouseMove = true; }; // To be called from the XAML thread @@ -850,6 +851,7 @@ void QWinRTScreen::addWindow(QWindow *window) } handleExpose(); + d->firstMouseMove = true; QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); #if QT_CONFIG(draganddrop) @@ -1091,6 +1093,7 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) d->currentTargetWindow = d->mouseGrabWindow.load()->window(); QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos); + d->firstMouseMove = false; } return S_OK; } @@ -1315,6 +1318,62 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) return S_OK; } +void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransition transition) +{ + Q_D(QWinRTScreen); + if (transition == MousePositionTransition::StayedOut) + return; + qt_winrt_lastPointerPoint = nullptr; + const QPointF pos(point.x() * d->scaleFactor, point.y() * d->scaleFactor); + QPointF localPos = pos; + + const QPoint posPoint = pos.toPoint(); + QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this)); + d->currentTargetWindow = windowUnderPointer; + + if (d->mouseGrabWindow) + d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + + if (d->currentTargetWindow) { + const QPointF globalPosDelta = pos - posPoint; + localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta; + } + + // In case of a mouse grab we have to store the target of a press event + // to be able to send one additional release event to this target when the mouse + // button is released. This is a similar approach to AutoMouseCapture in the + // windows qpa backend. Otherwise the release might not be propagated and the original + // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1 + // menus. + if (d->currentPressWindow && d->mouseGrabWindow) { + const QPointF globalPosDelta = pos - posPoint; + const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta; + + QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, + Qt::NoButton, Qt::NoModifier); + d->currentPressWindow = nullptr; + } + // If the mouse button is released outside of a window, targetWindow is 0, but the event + // has to be delivered to the window, that initially received the mouse press. Do not reset + // d->currentTargetWindow though, as it is used (and reset) in onPointerExited. + if (d->currentPressWindow && !d->currentTargetWindow) { + d->currentTargetWindow = d->currentPressWindow; + d->currentPressWindow = nullptr; + } + + if (transition == MousePositionTransition::MovedOut) { + QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); + return; + } + + if (transition == MousePositionTransition::MovedIn || d->firstMouseMove) { + QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, localPos, pos); + d->firstMouseMove = false; + } + QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, Qt::NoButton, + Qt::NoModifier); +} + HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { Q_D(QWinRTScreen); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index fd6499c2b9..6d0d3cdf52 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -128,6 +128,15 @@ public: void setCursorRect(const QRectF &cursorRect); void setKeyboardRect(const QRectF &keyboardRect); + enum class MousePositionTransition { + MovedOut, + MovedIn, + StayedIn, + StayedOut + }; + + void emulateMouseMove(const QPointF &point, MousePositionTransition transition); + private: void handleExpose(); diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index fd0a051390..7c24bbaadd 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -2104,8 +2104,6 @@ void tst_QWindow::modalWindowEnterEventOnHide_QTBUG35109() // Wait for the enter event. It must be delivered here, otherwise second // compare can PASS because of this event even after "resetCounters()". - if (isPlatformWinRT()) - QEXPECT_FAIL("", "WinRT does not support QCursor::setPos.", Abort); QTRY_COMPARE(root.enterEventCount, 1); QTRY_COMPARE(root.leaveEventCount, 0); @@ -2126,6 +2124,9 @@ void tst_QWindow::modalWindowEnterEventOnHide_QTBUG35109() root.resetCounters(); modal.close(); + if (isPlatformWinRT()) + QEXPECT_FAIL("", "WinRT does not trigger the enter event correctly" + "- QTBUG-68297.", Abort); // Check for the enter event QTRY_COMPARE(root.enterEventCount, 1); } diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index c8b13b0f90..45c86800d6 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -1238,9 +1238,6 @@ void tst_QAbstractItemView::task200665_itemEntered() view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); QCursor::setPos(view.geometry().center()); -#ifdef Q_OS_WINRT - QEXPECT_FAIL("", "QCursor::setPos does not work on WinRT", Abort); -#endif QTRY_COMPARE(QCursor::pos(), view.geometry().center()); QSignalSpy spy(&view, SIGNAL(entered(QModelIndex))); view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum()); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index cb0a225195..e30429b7e7 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -9119,8 +9119,6 @@ void tst_QWidget::syntheticEnterLeave() QCOMPARE(child1->numLeaveEvents, 0); // This event arrives asynchronously - if (m_platform == QStringLiteral("winrt")) - QEXPECT_FAIL("", "WinRT: This fails. QTBUG-68297.", Abort); QTRY_COMPARE(window.numEnterEvents, 1); QCOMPARE(child2->numEnterEvents, 1); QCOMPARE(grandChild->numEnterEvents, 1); @@ -9205,8 +9203,6 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave() QCursor::setPos(child.mapToGlobal(QPoint(100, 100))); // Make sure the cursor has entered the child. - if (m_platform == QStringLiteral("winrt")) - QEXPECT_FAIL("", "WinRT: This fails. QTBUG-68297.", Abort); QTRY_VERIFY(child.numEnterEvents > 0); child.hide(); |
