summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/qwindowsmousehandler.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-08-17 15:58:39 +0200
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-08-18 12:00:46 +0200
commit0b8d0804219b7e2e6179112d663b989d5b749d17 (patch)
tree4660a721ed39cc3e806c382f0f9287cedaa2d1a2 /src/plugins/platforms/windows/qwindowsmousehandler.cpp
parent6136a792bc54c07dc4cf66481530b79b40110614 (diff)
Add Windows to the Lighthouse.
Add an initial Lighthouse plugin for the Windows operating system. Change-Id: I6934562266e1aa0ac270bf6107df05a9e56ef82c Reviewed-on: http://codereview.qt.nokia.com/3107 Reviewed-by: Oliver Wolff <oliver.wolff@nokia.com> Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsmousehandler.cpp')
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
new file mode 100644
index 0000000000..dea965b439
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwindowsmousehandler.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "qwindowsintegration.h"
+
+#include <QtGui/QWindowSystemInterface>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+
+#include <QtCore/QDebug>
+#include <QtCore/QScopedArrayPointer>
+
+#include <windowsx.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline void compressMouseMove(MSG *msg)
+{
+ // Compress mouse move events
+ if (msg->message == WM_MOUSEMOVE) {
+ MSG mouseMsg;
+ while (PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEFIRST,
+ WM_MOUSELAST, PM_NOREMOVE)) {
+ if (mouseMsg.message == WM_MOUSEMOVE) {
+#define PEEKMESSAGE_IS_BROKEN 1
+#ifdef PEEKMESSAGE_IS_BROKEN
+ // Since the Windows PeekMessage() function doesn't
+ // correctly return the wParam for WM_MOUSEMOVE events
+ // if there is a key release event in the queue
+ // _before_ the mouse event, we have to also consider
+ // key release events (kls 2003-05-13):
+ MSG keyMsg;
+ bool done = false;
+ while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST,
+ PM_NOREMOVE)) {
+ if (keyMsg.time < mouseMsg.time) {
+ if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
+ PeekMessage(&keyMsg, 0, keyMsg.message,
+ keyMsg.message, PM_REMOVE);
+ } else {
+ done = true;
+ break;
+ }
+ } else {
+ break; // no key event before the WM_MOUSEMOVE event
+ }
+ }
+ if (done)
+ break;
+#else
+ // Actually the following 'if' should work instead of
+ // the above key event checking, but apparently
+ // PeekMessage() is broken :-(
+ if (mouseMsg.wParam != msg.wParam)
+ break; // leave the message in the queue because
+ // the key state has changed
+#endif
+ // Update the passed in MSG structure with the
+ // most recent one.
+ msg->lParam = mouseMsg.lParam;
+ msg->wParam = mouseMsg.wParam;
+ // Extract the x,y coordinates from the lParam as we do in the WndProc
+ msg->pt.x = GET_X_LPARAM(mouseMsg.lParam);
+ msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
+ ClientToScreen(msg->hwnd, &(msg->pt));
+ // Remove the mouse move message
+ PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE,
+ WM_MOUSEMOVE, PM_REMOVE);
+ } else {
+ break; // there was no more WM_MOUSEMOVE event
+ }
+ }
+ }
+}
+
+/*!
+ \class QWindowsMouseHandler
+ \brief Windows mouse handler
+
+ Dispatches mouse and touch events. Separate for code cleanliness.
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsMouseHandler::QWindowsMouseHandler() :
+ m_windowUnderMouse(0)
+{
+}
+
+bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
+ QtWindows::WindowsEventType et,
+ MSG msg, LRESULT *result)
+{
+ if (et & QtWindows::NonClientEventFlag)
+ return false;
+ if (et == QtWindows::MouseWheelEvent)
+ return translateMouseWheelEvent(window, hwnd, msg, result);
+ *result = 0;
+ if (msg.message == WM_MOUSELEAVE) {
+ // When moving out of a child, MouseMove within parent is received first
+ // (see below)
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "WM_MOUSELEAVE for " << window << " current= " << m_windowUnderMouse;
+ if (window == m_windowUnderMouse) {
+ QWindowSystemInterface::handleLeaveEvent(window);
+ m_windowUnderMouse = 0;
+ }
+ return true;
+ }
+ compressMouseMove(&msg);
+ const QPoint client(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ // Enter new window: track to generate leave event.
+ if (m_windowUnderMouse != window) {
+ // The tracking on m_windowUnderMouse might still be active and
+ // trigger later on.
+ if (m_windowUnderMouse) {
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Synthetic leave for " << m_windowUnderMouse;
+ QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
+ }
+ m_windowUnderMouse = window;
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Entering " << window;
+ QWindowsWindow::baseWindowOf(window)->applyCursor();
+ QWindowSystemInterface::handleEnterEvent(window);
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ tme.dwHoverTime = HOVER_DEFAULT; //
+ if (!TrackMouseEvent(&tme))
+ qWarning("TrackMouseEvent failed.");
+ }
+ QWindowSystemInterface::handleMouseEvent(window, client,
+ QWindowsGeometryHint::mapToGlobal(hwnd, client),
+ keyStateToMouseButtons((int)msg.wParam));
+ return true;
+}
+
+bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
+ MSG msg, LRESULT *)
+{
+ const Qt::MouseButtons buttons = keyStateToMouseButtons((int)msg.wParam);
+ int delta;
+ if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
+ delta = (short) HIWORD (msg.wParam);
+ else
+ delta = (int) msg.wParam;
+
+ Qt::Orientation orientation = (msg.message == WM_MOUSEHWHEEL
+ || (buttons & Qt::AltModifier)) ?
+ Qt::Horizontal : Qt::Vertical;
+
+ // according to the MSDN documentation on WM_MOUSEHWHEEL:
+ // a positive value indicates that the wheel was rotated to the right;
+ // a negative value indicates that the wheel was rotated to the left.
+ // Qt defines this value as the exact opposite, so we have to flip the value!
+ if (msg.message == WM_MOUSEHWHEEL)
+ delta = -delta;
+
+ const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ // TODO: if there is a widget under the mouse and it is not shadowed
+ // QWindow *receiver = windowAt(pos);
+ // by modality, we send the event to it first.
+ //synaptics touchpad shows its own widget at this position
+ //so widgetAt() will fail with that HWND, try child of this widget
+ // if (!receiver) receiver = window->childAt(pos);
+ QWindow *receiver = window;
+ QWindowSystemInterface::handleWheelEvent(receiver,
+ QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
+ globalPos,
+ delta, orientation);
+ return true;
+}
+
+// from bool QApplicationPrivate::translateTouchEvent()
+bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
+ QtWindows::WindowsEventType,
+ MSG msg, LRESULT *)
+{
+ typedef QWindowSystemInterface::TouchPoint QTouchPoint;
+ typedef QList<QWindowSystemInterface::TouchPoint> QTouchPointList;
+
+ const QRect screenGeometry = window->screen()->geometry();
+
+ const int winTouchPointCount = msg.wParam;
+ QScopedArrayPointer<TOUCHINPUT> winTouchInputs(new TOUCHINPUT[winTouchPointCount]);
+ memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchPointCount);
+
+ QTouchPointList touchPoints;
+ touchPoints.reserve(winTouchPointCount);
+ Qt::TouchPointStates allStates = 0;
+
+ Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo);
+
+ QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT));
+ for (int i = 0; i < winTouchPointCount; ++i) {
+ const TOUCHINPUT &winTouchInput = winTouchInputs[i];
+ QTouchPoint touchPoint;
+ touchPoint.pressure = 1.0;
+ touchPoint.isPrimary = (winTouchInput.dwFlags & TOUCHEVENTF_PRIMARY) != 0;
+ touchPoint.id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1);
+ if (touchPoint.id == -1) {
+ touchPoint.id = m_touchInputIDToTouchPointID.size();
+ m_touchInputIDToTouchPointID.insert(winTouchInput.dwID, touchPoint.id);
+ }
+
+ QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.));
+ if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
+ touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.),
+ qreal(winTouchInput.cyContact) / qreal(100.)));
+ touchPoint.area.moveCenter(screenPos);
+
+ if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
+ touchPoint.state = Qt::TouchPointPressed;
+ } else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
+ touchPoint.state = Qt::TouchPointReleased;
+ } else {
+ // TODO: Previous code checked"
+ // screenPos == touchPoint.normalPosition -> Qt::TouchPointStationary, but
+ // but touchPoint.normalPosition was never initialized?
+ touchPoint.state = touchPoint.state;
+ }
+
+ touchPoint.normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
+ screenPos.y() / screenGeometry.height());
+
+ allStates |= touchPoint.state;
+
+ touchPoints.append(touchPoint);
+ }
+
+ QWindowsContext::user32dll.closeTouchInputHandle((HANDLE) msg.lParam);
+
+ // all touch points released, forget the ids we've seen, they may not be reused
+ if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased)
+ m_touchInputIDToTouchPointID.clear();
+
+ // TODO: Device used to be hardcoded to screen in previous code.
+ // What is the correct event type? Which parts of translateRawTouchEvent() are required?
+ QWindowSystemInterface::handleTouchEvent(window, QEvent::TouchBegin,
+ QTouchEvent::TouchScreen,
+ touchPoints);
+ return true;
+}
+
+QT_END_NAMESPACE