summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/winrt/qwinrtcursor.cpp40
-rw-r--r--src/plugins/platforms/winrt/qwinrtcursor.h1
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp59
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.h9
-rw-r--r--tests/auto/gui/kernel/qwindow/tst_qwindow.cpp5
-rw-r--r--tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp3
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp4
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();