From 3f885939c059605a9324a94e488793455c9cd848 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Mon, 5 May 2014 08:41:22 +0300 Subject: WinRT: Fix multi-touch on PC The pointer ID was incorrectly interpreted as a device ID, which caused creating a new QTouchDevice for each touch update and potential crashes in QtQuick. The handling has now been simplified and aligned with Windows Phone, treating all touch events as if they originate from the same device. Given that the native device has no ID, it is not possible to track the native device between events anyway (even the pointer values change). Task-number: QTBUG-38745 Change-Id: I24b6c00b765dcb49cd653638afafc04fdd80f774 Reviewed-by: Oliver Wolff Reviewed-by: Maurice Kalinowski --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 81 ++++++++++------------------ src/plugins/platforms/winrt/qwinrtscreen.h | 9 +--- 2 files changed, 31 insertions(+), 59 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 583441f396..b7bfce5931 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -425,17 +425,8 @@ QWinRTScreen::QWinRTScreen(ICoreWindow *window) #endif , m_cursor(new QWinRTCursor(window)) , m_orientation(Qt::PrimaryOrientation) + , m_touchDevice(Q_NULLPTR) { -#ifdef Q_OS_WINPHONE // On phone, there can be only one touch device - QTouchDevice *touchDevice = new QTouchDevice; - touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure); - touchDevice->setType(QTouchDevice::TouchScreen); - touchDevice->setName(QStringLiteral("WinPhoneTouchScreen")); - Pointer pointer = { Pointer::TouchScreen, touchDevice }; - m_pointers.insert(0, pointer); - QWindowSystemInterface::registerTouchDevice(touchDevice); -#endif - Rect rect; window->get_Bounds(&rect); m_geometry = QRect(0, 0, rect.Width, rect.Height); @@ -762,47 +753,25 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a if (FAILED(pointerPoint->get_Properties(&properties))) return E_INVALIDARG; -#ifdef Q_OS_WINPHONE - quint32 pointerId = 0; - Pointer pointer = m_pointers.value(pointerId); + PointerDeviceType pointerDeviceType; +#if defined(Q_OS_WINPHONE) && _MSC_VER <= 1700 + pointerDeviceType = PointerDeviceType_Touch; #else - Pointer pointer = { Pointer::Unknown, 0 }; - quint32 pointerId; - pointerPoint->get_PointerId(&pointerId); - if (m_pointers.contains(pointerId)) { - pointer = m_pointers.value(pointerId); - } else { // We have not yet enumerated this device. Do so now... - IPointerDevice *device; - if (SUCCEEDED(pointerPoint->get_PointerDevice(&device))) { - PointerDeviceType type; - device->get_PointerDeviceType(&type); - switch (type) { - case PointerDeviceType_Touch: - pointer.type = Pointer::TouchScreen; - pointer.device = new QTouchDevice; - pointer.device->setName(QStringLiteral("WinRT TouchScreen ") + QString::number(pointerId)); - // TODO: We may want to probe the device usage flags for more accurate values for these next two - pointer.device->setType(QTouchDevice::TouchScreen); - pointer.device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure); - QWindowSystemInterface::registerTouchDevice(pointer.device); - break; - - case PointerDeviceType_Pen: - pointer.type = Pointer::Tablet; - break; - - case PointerDeviceType_Mouse: - pointer.type = Pointer::Mouse; - break; - } - - m_pointers.insert(pointerId, pointer); - device->Release(); - } + ComPtr pointerDevice; + HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get pointer device."); + return S_OK; + } + + hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get pointer device type."); + return S_OK; } #endif - switch (pointer.type) { - case Pointer::Mouse: { + switch (pointerDeviceType) { + case PointerDeviceType_Mouse: { qint32 delta; properties->get_MouseWheelDelta(&delta); if (delta) { @@ -839,7 +808,15 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a break; } - case Pointer::TouchScreen: { + case PointerDeviceType_Touch: { + if (!m_touchDevice) { + m_touchDevice = new QTouchDevice; + m_touchDevice->setName(QStringLiteral("WinRTTouchScreen")); + m_touchDevice->setType(QTouchDevice::TouchScreen); + m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(m_touchDevice); + } + quint32 id; pointerPoint->get_PointerId(&id); @@ -867,7 +844,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a it.value().normalPosition = QPointF(pos.x()/m_geometry.width(), pos.y()/m_geometry.height()); it.value().pressure = pressure; - QWindowSystemInterface::handleTouchEvent(topWindow(), pointer.device, m_touchPoints.values(), mods); + QWindowSystemInterface::handleTouchEvent(topWindow(), m_touchDevice, m_touchPoints.values(), mods); // Remove released points, station others for (QHash::iterator i = m_touchPoints.begin(); i != m_touchPoints.end();) { @@ -879,7 +856,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a break; } - case Pointer::Tablet: { + case PointerDeviceType_Pen: { quint32 id; pointerPoint->get_PointerId(&id); @@ -902,7 +879,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a float rotation; properties->get_Twist(&rotation); - QWindowSystemInterface::handleTabletEvent(topWindow(), isPressed, pos, pos, pointerId, + QWindowSystemInterface::handleTabletEvent(topWindow(), isPressed, pos, pos, 0, pointerType, pressure, xTilt, yTilt, 0, rotation, 0, id, mods); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index c6511e9446..753d89541c 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -101,12 +101,6 @@ class QWinRTPageFlipper; class QWinRTCursor; class QWinRTInputContext; -struct Pointer { - enum Type { Unknown, Mouse, TouchScreen, Tablet }; - Type type; - QTouchDevice *device; -}; - class QWinRTScreen : public QPlatformScreen { public: @@ -165,6 +159,7 @@ private: ABI::Windows::UI::Core::ICoreWindow *m_coreWindow; ABI::Windows::UI::ViewManagement::IApplicationViewStatics *m_applicationView; ABI::Windows::ApplicationModel::Core::ICoreApplication *m_application; + QRect m_geometry; QImage::Format m_format; QSurfaceFormat m_surfaceFormat; @@ -183,7 +178,7 @@ private: #ifndef Q_OS_WINPHONE QHash > m_activeKeys; #endif - QHash m_pointers; + QTouchDevice *m_touchDevice; QHash m_touchPoints; }; -- cgit v1.2.3 From b80f732783e43dc21ddbce4b42d9bb61915a3fb6 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 29 Apr 2014 12:32:34 +0200 Subject: Use XI2 event detail to determine changed mouse button The button state part of the XI2 events appears to be badly constructed on some devices and platforms. Even where supported the 'detail' field of the XI2 events is what we should be reading since it indicates the button the event refers to and not just the state of all buttons. Task-number: QTBUG-38169 Change-Id: Iedb7971194b3c27448b72c285a54100c511c17e4 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbconnection.cpp | 13 ------------- src/plugins/platforms/xcb/qxcbconnection.h | 1 - src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 12 ++++++------ 3 files changed, 6 insertions(+), 20 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index e3b81c2b40..f5f6c712c5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1791,19 +1791,6 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub return true; } -bool QXcbConnection::xi2GetButtonState(void *event, int buttonNum) -{ - xXIDeviceEvent *xideviceevent = static_cast(event); - unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1]; - - for (int i = 0; i < (xideviceevent->buttons_len * 4); i++) { - if (buttonNum < 8) - return (buttonsMaskAddr[i] & (1 << buttonNum)); - buttonNum -= 8; - } - return false; -} - // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" // - "pad1" and "pad" became "pad0" diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 1933b89a19..6e511356c4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -532,7 +532,6 @@ private: #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); - static bool xi2GetButtonState(void *event, int buttonNum); #endif xcb_connection_t *m_connection; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 831ccba6f6..efa1691780 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -575,7 +575,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin #ifdef XCB_USE_XINPUT21 xXIGenericDeviceEvent *xiEvent = reinterpret_cast(event); - if (xiEvent->evtype == XI_Motion) { + if (xiEvent->evtype == XI_Motion && scrollingDevice.orientations) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast(event); if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { QPoint rawDelta; @@ -612,20 +612,20 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers); } } - } else if (xiEvent->evtype == XI_ButtonRelease) { + } else if (xiEvent->evtype == XI_ButtonRelease && scrollingDevice.legacyOrientations) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast(event); if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { QPoint angleDelta; if (scrollingDevice.legacyOrientations & Qt::Vertical) { - if (xi2GetButtonState(xiDeviceEvent, 4)) + if (xiDeviceEvent->detail == 4) angleDelta.setY(120); - else if (xi2GetButtonState(xiDeviceEvent, 5)) + else if (xiDeviceEvent->detail == 5) angleDelta.setY(-120); } if (scrollingDevice.legacyOrientations & Qt::Horizontal) { - if (xi2GetButtonState(xiDeviceEvent, 6)) + if (xiDeviceEvent->detail == 6) angleDelta.setX(120); - if (xi2GetButtonState(xiDeviceEvent, 7)) + else if (xiDeviceEvent->detail == 7) angleDelta.setX(-120); } if (!angleDelta.isNull()) { -- cgit v1.2.3