winrt: Fix input grabbing
Beside its usage in widgets, mouse grabs are required for QML menus to work. Task-number: QTBUG-57079 Change-Id: I306cb68624186da69725470e147bc7b979dac8e4 Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
parent
10143ea803
commit
181860e1af
@ -486,6 +486,9 @@ public:
|
||||
QHash<ApplicationView2CallbackRemover, EventRegistrationToken> view2Tokens;
|
||||
ComPtr<IApplicationView2> view2;
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
||||
QAtomicPointer<QWinRTWindow> mouseGrabWindow;
|
||||
QAtomicPointer<QWinRTWindow> keyboardGrabWindow;
|
||||
QWindow *currentPressWindow = 0;
|
||||
};
|
||||
|
||||
// To be called from the XAML thread
|
||||
@ -877,6 +880,44 @@ void QWinRTScreen::lower(QWindow *window)
|
||||
handleExpose();
|
||||
}
|
||||
|
||||
bool QWinRTScreen::setMouseGrabWindow(QWinRTWindow *window, bool grab)
|
||||
{
|
||||
Q_D(QWinRTScreen);
|
||||
qCDebug(lcQpaWindows) << __FUNCTION__ << window
|
||||
<< "(" << window->window()->objectName() << "):" << grab;
|
||||
|
||||
if (!grab || window == nullptr)
|
||||
d->mouseGrabWindow = nullptr;
|
||||
else if (d->mouseGrabWindow != window)
|
||||
d->mouseGrabWindow = window;
|
||||
return grab;
|
||||
}
|
||||
|
||||
QWinRTWindow *QWinRTScreen::mouseGrabWindow() const
|
||||
{
|
||||
Q_D(const QWinRTScreen);
|
||||
return d->mouseGrabWindow;
|
||||
}
|
||||
|
||||
bool QWinRTScreen::setKeyboardGrabWindow(QWinRTWindow *window, bool grab)
|
||||
{
|
||||
Q_D(QWinRTScreen);
|
||||
qCDebug(lcQpaWindows) << __FUNCTION__ << window
|
||||
<< "(" << window->window()->objectName() << "):" << grab;
|
||||
|
||||
if (!grab || window == nullptr)
|
||||
d->keyboardGrabWindow = nullptr;
|
||||
else if (d->keyboardGrabWindow != window)
|
||||
d->keyboardGrabWindow = window;
|
||||
return grab;
|
||||
}
|
||||
|
||||
QWinRTWindow *QWinRTScreen::keyboardGrabWindow() const
|
||||
{
|
||||
Q_D(const QWinRTScreen);
|
||||
return d->keyboardGrabWindow;
|
||||
}
|
||||
|
||||
void QWinRTScreen::updateWindowTitle(const QString &title)
|
||||
{
|
||||
Q_D(QWinRTScreen);
|
||||
@ -1022,7 +1063,11 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
|
||||
pointerPoint->get_Position(&point);
|
||||
QPoint pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
|
||||
|
||||
QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos);
|
||||
QWindow *targetWindow = topWindow();
|
||||
if (d->mouseGrabWindow)
|
||||
targetWindow = d->mouseGrabWindow.load()->window();
|
||||
|
||||
QWindowSystemInterface::handleEnterEvent(targetWindow, pos, pos);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@ -1041,7 +1086,11 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
|
||||
|
||||
d->touchPoints.remove(id);
|
||||
|
||||
QWindowSystemInterface::handleLeaveEvent(0);
|
||||
QWindow *targetWindow = nullptr;
|
||||
if (d->mouseGrabWindow)
|
||||
targetWindow = d->mouseGrabWindow.load()->window();
|
||||
|
||||
QWindowSystemInterface::handleLeaveEvent(targetWindow);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -1063,7 +1112,12 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
|
||||
QPointF localPos = pos;
|
||||
|
||||
const QPoint posPoint = pos.toPoint();
|
||||
QWindow *targetWindow = windowAt(posPoint);
|
||||
QWindow *windowUnderPointer = windowAt(posPoint);
|
||||
QWindow *targetWindow = windowUnderPointer;
|
||||
|
||||
if (d->mouseGrabWindow)
|
||||
targetWindow = d->mouseGrabWindow.load()->window();
|
||||
|
||||
if (targetWindow) {
|
||||
const QPointF globalPosDelta = pos - posPoint;
|
||||
localPos = targetWindow->mapFromGlobal(posPoint) + globalPosDelta;
|
||||
@ -1127,6 +1181,22 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
|
||||
if (isPressed)
|
||||
buttons |= Qt::XButton2;
|
||||
|
||||
// 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 (buttons != Qt::NoButton && d->currentPressWindow == nullptr && !d->mouseGrabWindow)
|
||||
d->currentPressWindow = windowUnderPointer;
|
||||
if (!isPressed && d->currentPressWindow && d->mouseGrabWindow) {
|
||||
const QPointF globalPosDelta = pos - posPoint;
|
||||
const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta;
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, buttons, mods);
|
||||
d->currentPressWindow = nullptr;
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(targetWindow, localPos, pos, buttons, mods);
|
||||
|
||||
break;
|
||||
|
@ -83,6 +83,7 @@ class QTouchDevice;
|
||||
class QWinRTCursor;
|
||||
class QWinRTInputContext;
|
||||
class QWinRTScreenPrivate;
|
||||
class QWinRTWindow;
|
||||
class QWinRTScreen : public QPlatformScreen
|
||||
{
|
||||
public:
|
||||
@ -110,6 +111,12 @@ public:
|
||||
void raise(QWindow *window);
|
||||
void lower(QWindow *window);
|
||||
|
||||
bool setMouseGrabWindow(QWinRTWindow *window, bool grab);
|
||||
QWinRTWindow* mouseGrabWindow() const;
|
||||
|
||||
bool setKeyboardGrabWindow(QWinRTWindow *window, bool grab);
|
||||
QWinRTWindow* keyboardGrabWindow() const;
|
||||
|
||||
void updateWindowTitle(const QString &title);
|
||||
|
||||
ABI::Windows::UI::Core::ICoreWindow *coreWindow() const;
|
||||
|
@ -191,6 +191,11 @@ QWinRTWindow::~QWinRTWindow()
|
||||
});
|
||||
RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down");
|
||||
|
||||
if (d->screen->mouseGrabWindow() == this)
|
||||
d->screen->setMouseGrabWindow(this, false);
|
||||
if (d->screen->keyboardGrabWindow() == this)
|
||||
d->screen->setKeyboardGrabWindow(this, false);
|
||||
|
||||
d->screen->removeWindow(window());
|
||||
|
||||
if (!d->surface)
|
||||
@ -384,6 +389,24 @@ void QWinRTWindow::setWindowState(Qt::WindowState state)
|
||||
d->state = state;
|
||||
}
|
||||
|
||||
bool QWinRTWindow::setMouseGrabEnabled(bool grab)
|
||||
{
|
||||
Q_D(QWinRTWindow);
|
||||
if (!isActive() && grab) {
|
||||
qWarning("%s: Not setting mouse grab for invisible window %s/'%s'",
|
||||
__FUNCTION__, window()->metaObject()->className(),
|
||||
qPrintable(window()->objectName()));
|
||||
return false;
|
||||
}
|
||||
return d->screen->setMouseGrabWindow(this, grab);
|
||||
}
|
||||
|
||||
bool QWinRTWindow::setKeyboardGrabEnabled(bool grab)
|
||||
{
|
||||
Q_D(QWinRTWindow);
|
||||
return d->screen->setKeyboardGrabWindow(this, grab);
|
||||
}
|
||||
|
||||
EGLSurface QWinRTWindow::eglSurface() const
|
||||
{
|
||||
Q_D(const QWinRTWindow);
|
||||
|
@ -70,6 +70,9 @@ public:
|
||||
qreal devicePixelRatio() const Q_DECL_OVERRIDE;
|
||||
void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE;
|
||||
|
||||
bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE;
|
||||
bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE;
|
||||
|
||||
EGLSurface eglSurface() const;
|
||||
void createEglSurface(EGLDisplay display, EGLConfig config);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user