Windows: Remove legacy mouse handling
Pointer handling API was added in Windows 8. As we no longer support Windows 7, we can make mouse handling code easier to read/maintain be removing the legacy implementation. [ChangeLog][Windows] Legacy mouse handling has been removed. It is no longer possible to enforce legacy mouse handling by passing "-nowmpointer". Change-Id: I58387471999a371fd20c644abbcf855e192d220b Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> (cherry picked from commit 3a38de71da13103fbe5bdf6b822263e282e68368) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
fcae2b7f2d
commit
33b3054da1
@ -23,7 +23,6 @@ qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
|
||||
../windows/qwindowskeymapper.cpp ../windows/qwindowskeymapper.h
|
||||
../windows/qwindowsmenu.cpp ../windows/qwindowsmenu.h
|
||||
../windows/qwindowsmimeregistry.cpp ../windows/qwindowsmimeregistry.h
|
||||
../windows/qwindowsmousehandler.cpp ../windows/qwindowsmousehandler.h
|
||||
../windows/qwindowsnativeinterface.cpp ../windows/qwindowsnativeinterface.h
|
||||
../windows/qwindowsole.cpp ../windows/qwindowsole.h
|
||||
../windows/qwindowsopengltester.cpp ../windows/qwindowsopengltester.h
|
||||
|
@ -28,7 +28,6 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin
|
||||
qwindowskeymapper.cpp qwindowskeymapper.h
|
||||
qwindowsmenu.cpp qwindowsmenu.h
|
||||
qwindowsmimeregistry.cpp qwindowsmimeregistry.h
|
||||
qwindowsmousehandler.cpp qwindowsmousehandler.h
|
||||
qwindowsnativeinterface.cpp qwindowsnativeinterface.h
|
||||
qwindowsole.cpp qwindowsole.h
|
||||
qwindowsopengltester.cpp qwindowsopengltester.h
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "qwindowswindow.h"
|
||||
#include "qwindowskeymapper.h"
|
||||
#include "qwindowsnativeinterface.h"
|
||||
#include "qwindowsmousehandler.h"
|
||||
#include "qwindowspointerhandler.h"
|
||||
#include "qtwindowsglobal.h"
|
||||
#include "qwindowsmenu.h"
|
||||
@ -141,7 +140,6 @@ struct QWindowsContextPrivate {
|
||||
HDC m_displayContext = nullptr;
|
||||
int m_defaultDPI = 96;
|
||||
QWindowsKeyMapper m_keyMapper;
|
||||
QWindowsMouseHandler m_mouseHandler;
|
||||
QWindowsPointerHandler m_pointerHandler;
|
||||
QWindowsMimeRegistry m_mimeConverter;
|
||||
QWindowsScreenManager m_screenManager;
|
||||
@ -162,7 +160,7 @@ bool QWindowsContextPrivate::m_v2DpiAware = false;
|
||||
QWindowsContextPrivate::QWindowsContextPrivate()
|
||||
: m_oleInitializeResult(OleInitialize(nullptr))
|
||||
{
|
||||
if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice())
|
||||
if (m_pointerHandler.touchDevice())
|
||||
m_systemInfo |= QWindowsContext::SI_SupportsTouch;
|
||||
m_displayContext = GetDC(nullptr);
|
||||
m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY);
|
||||
@ -226,8 +224,7 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
|
||||
{
|
||||
if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
|
||||
return true;
|
||||
const bool usePointerHandler = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) != 0;
|
||||
auto touchDevice = usePointerHandler ? d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
|
||||
auto touchDevice = d->m_pointerHandler.touchDevice();
|
||||
if (touchDevice.isNull()) {
|
||||
const bool mouseEmulation =
|
||||
(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch) == 0;
|
||||
@ -236,7 +233,6 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
|
||||
if (touchDevice.isNull())
|
||||
return false;
|
||||
d->m_pointerHandler.setTouchDevice(touchDevice);
|
||||
d->m_mouseHandler.setTouchDevice(touchDevice);
|
||||
QWindowSystemInterface::registerInputDevice(touchDevice.data());
|
||||
|
||||
d->m_systemInfo |= QWindowsContext::SI_SupportsTouch;
|
||||
@ -276,15 +272,6 @@ bool QWindowsContext::disposeTablet()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool QWindowsContext::initPointer(unsigned integrationOptions)
|
||||
{
|
||||
if (integrationOptions & QWindowsIntegration::DontUseWMPointer)
|
||||
return false;
|
||||
|
||||
d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" LRESULT QT_WIN_CALLBACK qWindowsPowerWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (message != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE)
|
||||
@ -730,16 +717,12 @@ QWindow *QWindowsContext::findWindow(HWND hwnd) const
|
||||
|
||||
QWindow *QWindowsContext::windowUnderMouse() const
|
||||
{
|
||||
return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
|
||||
d->m_pointerHandler.windowUnderMouse() : d->m_mouseHandler.windowUnderMouse();
|
||||
return d->m_pointerHandler.windowUnderMouse();
|
||||
}
|
||||
|
||||
void QWindowsContext::clearWindowUnderMouse()
|
||||
{
|
||||
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
|
||||
d->m_pointerHandler.clearWindowUnderMouse();
|
||||
else
|
||||
d->m_mouseHandler.clearWindowUnderMouse();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1052,8 +1035,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
|
||||
|
||||
switch (et) {
|
||||
case QtWindows::GestureEvent:
|
||||
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
|
||||
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
|
||||
// TODO???
|
||||
break;
|
||||
case QtWindows::InputMethodOpenCandidateWindowEvent:
|
||||
case QtWindows::InputMethodCloseCandidateWindowEvent:
|
||||
@ -1193,16 +1175,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
|
||||
case QtWindows::NonClientMouseEvent:
|
||||
if (!platformWindow->frameStrutEventsEnabled())
|
||||
break;
|
||||
if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
|
||||
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
|
||||
else
|
||||
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
|
||||
case QtWindows::NonClientPointerEvent:
|
||||
if (!platformWindow->frameStrutEventsEnabled())
|
||||
break;
|
||||
if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
|
||||
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
|
||||
break;
|
||||
case QtWindows::EnterSizeMoveEvent:
|
||||
platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
|
||||
if (!IsZoomed(hwnd))
|
||||
@ -1216,8 +1193,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
|
||||
platformWindow->updateRestoreGeometry();
|
||||
return true;
|
||||
case QtWindows::ScrollEvent:
|
||||
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
|
||||
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
|
||||
// TODO???
|
||||
break;
|
||||
case QtWindows::MouseWheelEvent:
|
||||
case QtWindows::MouseEvent:
|
||||
@ -1228,20 +1204,14 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
|
||||
window = window->parent();
|
||||
if (!window)
|
||||
return false;
|
||||
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
|
||||
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
|
||||
else
|
||||
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
|
||||
}
|
||||
break;
|
||||
case QtWindows::TouchEvent:
|
||||
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
|
||||
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
|
||||
// TODO???
|
||||
break;
|
||||
case QtWindows::PointerEvent:
|
||||
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
|
||||
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
|
||||
break;
|
||||
case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
|
||||
case QtWindows::FocusOutEvent:
|
||||
handleFocusEvent(et, platformWindow);
|
||||
@ -1445,7 +1415,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
|
||||
// Mouse is left in pressed state after press on size grip (inside window),
|
||||
// no further mouse events are received
|
||||
// For cases 1,3, intercept WM_EXITSIZEMOVE to sync the buttons.
|
||||
const Qt::MouseButtons currentButtons = QWindowsMouseHandler::queryMouseButtons();
|
||||
const Qt::MouseButtons currentButtons = QWindowsPointerHandler::queryMouseButtons();
|
||||
const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
|
||||
if (currentButtons == appButtons)
|
||||
return;
|
||||
@ -1461,10 +1431,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
|
||||
currentButtons, button, type, keyboardModifiers);
|
||||
}
|
||||
}
|
||||
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
|
||||
d->m_pointerHandler.clearEvents();
|
||||
else
|
||||
d->m_mouseHandler.clearEvents();
|
||||
}
|
||||
|
||||
bool QWindowsContext::asyncExpose() const
|
||||
|
@ -53,8 +53,7 @@ public:
|
||||
enum SystemInfoFlags
|
||||
{
|
||||
SI_RTL_Extensions = 0x1,
|
||||
SI_SupportsTouch = 0x2,
|
||||
SI_SupportsPointer = 0x4,
|
||||
SI_SupportsTouch = 0x2
|
||||
};
|
||||
|
||||
// Verbose flag set by environment variable QT_QPA_VERBOSE
|
||||
@ -67,7 +66,6 @@ public:
|
||||
bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only.
|
||||
void registerTouchWindows();
|
||||
bool initTablet();
|
||||
bool initPointer(unsigned integrationOptions);
|
||||
bool disposeTablet();
|
||||
|
||||
bool initPowerNotificationHandler();
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "qwindowsintegration.h"
|
||||
#include "qwindowsdropdataobject.h"
|
||||
#include "qwindowswindow.h"
|
||||
#include "qwindowsmousehandler.h"
|
||||
#include "qwindowspointerhandler.h"
|
||||
#include "qwindowscursor.h"
|
||||
#include "qwindowskeymapper.h"
|
||||
|
||||
@ -341,7 +341,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
|
||||
// In some rare cases, when a mouse button is released but the mouse is static,
|
||||
// grfKeyState will not be updated with these released buttons until the mouse
|
||||
// is moved. So we use the async key state given by queryMouseButtons() instead.
|
||||
Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
|
||||
Qt::MouseButtons buttons = QWindowsPointerHandler::queryMouseButtons();
|
||||
|
||||
SCODE result = S_OK;
|
||||
if (fEscapePressed || QWindowsDrag::isCanceled()) {
|
||||
@ -366,7 +366,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
|
||||
const QPoint localPos = m_windowUnderMouse->handle()->mapFromGlobal(globalPos);
|
||||
QWindowSystemInterface::handleMouseEvent(m_windowUnderMouse.data(),
|
||||
QPointF(localPos), QPointF(globalPos),
|
||||
QWindowsMouseHandler::queryMouseButtons(),
|
||||
QWindowsPointerHandler::queryMouseButtons(),
|
||||
Qt::LeftButton, QEvent::MouseButtonRelease);
|
||||
}
|
||||
m_currentButtons = Qt::NoButton;
|
||||
@ -460,7 +460,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
|
||||
const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
|
||||
|
||||
lastModifiers = toQtKeyboardModifiers(grfKeyState);
|
||||
lastButtons = QWindowsMouseHandler::queryMouseButtons();
|
||||
lastButtons = QWindowsPointerHandler::queryMouseButtons();
|
||||
|
||||
const QPlatformDragQtResponse response =
|
||||
QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(),
|
||||
@ -530,7 +530,7 @@ QWindowsOleDropTarget::DragLeave()
|
||||
|
||||
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
|
||||
lastModifiers = keyMapper->queryKeyboardModifiers();
|
||||
lastButtons = QWindowsMouseHandler::queryMouseButtons();
|
||||
lastButtons = QWindowsPointerHandler::queryMouseButtons();
|
||||
|
||||
QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction,
|
||||
Qt::NoButton, Qt::NoModifier);
|
||||
@ -559,7 +559,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
|
||||
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
|
||||
|
||||
lastModifiers = toQtKeyboardModifiers(grfKeyState);
|
||||
lastButtons = QWindowsMouseHandler::queryMouseButtons();
|
||||
lastButtons = QWindowsPointerHandler::queryMouseButtons();
|
||||
|
||||
const QPlatformDropQtResponse response =
|
||||
QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "qwindowscontext.h"
|
||||
#include "qwindowswindow.h"
|
||||
#include "qwindowsintegration.h"
|
||||
#include "qwindowsmousehandler.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qobject.h>
|
||||
|
@ -173,8 +173,6 @@ static inline unsigned parseOptions(const QStringList ¶mList,
|
||||
options |= QWindowsIntegration::AlwaysUseNativeMenus;
|
||||
} else if (param == u"menus=none") {
|
||||
options |= QWindowsIntegration::NoNativeMenus;
|
||||
} else if (param == u"nowmpointer") {
|
||||
options |= QWindowsIntegration::DontUseWMPointer;
|
||||
} else if (param == u"reverse") {
|
||||
options |= QWindowsIntegration::RtlEnabled;
|
||||
} else if (param == u"darkmode=0") {
|
||||
@ -209,10 +207,7 @@ void QWindowsIntegrationPrivate::parseOptions(QWindowsIntegration *q, const QStr
|
||||
if (tabletAbsoluteRange >= 0)
|
||||
QWindowsContext::setTabletAbsoluteRange(tabletAbsoluteRange);
|
||||
|
||||
if (m_context.initPointer(m_options))
|
||||
QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
|
||||
else
|
||||
m_context.initTablet();
|
||||
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
|
||||
|
||||
if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
|
||||
|
@ -42,10 +42,9 @@ public:
|
||||
DontUseColorFonts = QWindowsFontDatabase::DontUseColorFonts,
|
||||
AlwaysUseNativeMenus = 0x100,
|
||||
NoNativeMenus = 0x200,
|
||||
DontUseWMPointer = 0x400,
|
||||
DetectAltGrModifier = 0x800,
|
||||
RtlEnabled = 0x1000,
|
||||
FontDatabaseGDI = 0x2000
|
||||
DetectAltGrModifier = 0x400,
|
||||
RtlEnabled = 0x0800,
|
||||
FontDatabaseGDI = 0x1000
|
||||
};
|
||||
|
||||
explicit QWindowsIntegration(const QStringList ¶mList);
|
||||
|
@ -1,653 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qwindowsmousehandler.h"
|
||||
#include "qwindowskeymapper.h"
|
||||
#include "qwindowscontext.h"
|
||||
#include "qwindowswindow.h"
|
||||
#include "qwindowsintegration.h"
|
||||
#include "qwindowsscreen.h"
|
||||
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qpointingdevice.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/qcursor.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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, nullptr, WM_KEYFIRST, WM_KEYLAST,
|
||||
PM_NOREMOVE)) {
|
||||
if (keyMsg.time < mouseMsg.time) {
|
||||
if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
|
||||
PeekMessage(&keyMsg, nullptr, 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.
|
||||
|
||||
\internal
|
||||
*/
|
||||
|
||||
QWindowsMouseHandler::QWindowsMouseHandler() = default;
|
||||
|
||||
const QPointingDevice *QWindowsMouseHandler::primaryMouse()
|
||||
{
|
||||
static QPointer<const QPointingDevice> result;
|
||||
if (!result)
|
||||
result = QPointingDevice::primaryPointingDevice();
|
||||
return result;
|
||||
}
|
||||
|
||||
void QWindowsMouseHandler::clearEvents()
|
||||
{
|
||||
m_lastEventType = QEvent::None;
|
||||
m_lastEventButton = Qt::NoButton;
|
||||
}
|
||||
|
||||
Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
|
||||
{
|
||||
Qt::MouseButtons result;
|
||||
const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
|
||||
if (GetAsyncKeyState(VK_LBUTTON) < 0)
|
||||
result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
|
||||
if (GetAsyncKeyState(VK_RBUTTON) < 0)
|
||||
result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
|
||||
if (GetAsyncKeyState(VK_MBUTTON) < 0)
|
||||
result |= Qt::MiddleButton;
|
||||
if (GetAsyncKeyState(VK_XBUTTON1) < 0)
|
||||
result |= Qt::XButton1;
|
||||
if (GetAsyncKeyState(VK_XBUTTON2) < 0)
|
||||
result |= Qt::XButton2;
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_CONSTINIT static QPoint lastMouseMovePos;
|
||||
|
||||
namespace {
|
||||
struct MouseEvent {
|
||||
QEvent::Type type;
|
||||
Qt::MouseButton button;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug d, const MouseEvent &e)
|
||||
{
|
||||
QDebugStateSaver saver(d);
|
||||
d.nospace();
|
||||
d << "MouseEvent(" << e.type << ", " << e.button << ')';
|
||||
return d;
|
||||
}
|
||||
#endif // QT_NO_DEBUG_STREAM
|
||||
} // namespace
|
||||
|
||||
static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON...
|
||||
{
|
||||
return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
|
||||
}
|
||||
|
||||
static inline MouseEvent eventFromMsg(const MSG &msg)
|
||||
{
|
||||
switch (msg.message) {
|
||||
case WM_MOUSEMOVE:
|
||||
return {QEvent::MouseMove, Qt::NoButton};
|
||||
case WM_LBUTTONDOWN:
|
||||
return {QEvent::MouseButtonPress, Qt::LeftButton};
|
||||
case WM_LBUTTONUP:
|
||||
return {QEvent::MouseButtonRelease, Qt::LeftButton};
|
||||
case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
|
||||
return {QEvent::MouseButtonPress, Qt::LeftButton};
|
||||
case WM_MBUTTONDOWN:
|
||||
return {QEvent::MouseButtonPress, Qt::MiddleButton};
|
||||
case WM_MBUTTONUP:
|
||||
return {QEvent::MouseButtonRelease, Qt::MiddleButton};
|
||||
case WM_MBUTTONDBLCLK:
|
||||
return {QEvent::MouseButtonPress, Qt::MiddleButton};
|
||||
case WM_RBUTTONDOWN:
|
||||
return {QEvent::MouseButtonPress, Qt::RightButton};
|
||||
case WM_RBUTTONUP:
|
||||
return {QEvent::MouseButtonRelease, Qt::RightButton};
|
||||
case WM_RBUTTONDBLCLK:
|
||||
return {QEvent::MouseButtonPress, Qt::RightButton};
|
||||
case WM_XBUTTONDOWN:
|
||||
return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
|
||||
case WM_XBUTTONUP:
|
||||
return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
|
||||
case WM_XBUTTONDBLCLK:
|
||||
return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
|
||||
case WM_NCMOUSEMOVE:
|
||||
return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
|
||||
case WM_NCLBUTTONDOWN:
|
||||
return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
|
||||
case WM_NCLBUTTONUP:
|
||||
return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
|
||||
case WM_NCMBUTTONDOWN:
|
||||
return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
|
||||
case WM_NCMBUTTONUP:
|
||||
return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
|
||||
case WM_NCMBUTTONDBLCLK:
|
||||
return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
|
||||
case WM_NCRBUTTONDOWN:
|
||||
return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
|
||||
case WM_NCRBUTTONUP:
|
||||
return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
|
||||
case WM_NCRBUTTONDBLCLK:
|
||||
return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
|
||||
default: // WM_MOUSELEAVE
|
||||
break;
|
||||
}
|
||||
return {QEvent::None, Qt::NoButton};
|
||||
}
|
||||
|
||||
bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
||||
QtWindows::WindowsEventType et,
|
||||
MSG msg, LRESULT *result)
|
||||
{
|
||||
enum : quint64 { signatureMask = 0xffffff00, miWpSignature = 0xff515700 };
|
||||
|
||||
if (et == QtWindows::MouseWheelEvent)
|
||||
return translateMouseWheelEvent(window, hwnd, msg, result);
|
||||
|
||||
QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
|
||||
RECT clientArea;
|
||||
GetClientRect(hwnd, &clientArea);
|
||||
winEventPosition.setX(clientArea.right - winEventPosition.x());
|
||||
}
|
||||
|
||||
QPoint clientPosition;
|
||||
QPoint globalPosition;
|
||||
if (et & QtWindows::NonClientEventFlag) {
|
||||
globalPosition = winEventPosition;
|
||||
clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
|
||||
} else {
|
||||
globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
|
||||
auto targetHwnd = hwnd;
|
||||
if (auto *pw = window->handle())
|
||||
targetHwnd = HWND(pw->winId());
|
||||
clientPosition = targetHwnd == hwnd
|
||||
? winEventPosition
|
||||
: QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPosition);
|
||||
}
|
||||
|
||||
// Windows sends a mouse move with no buttons pressed to signal "Enter"
|
||||
// when a window is shown over the cursor. Discard the event and only use
|
||||
// it for generating QEvent::Enter to be consistent with other platforms -
|
||||
// X11 and macOS.
|
||||
bool discardEvent = false;
|
||||
if (msg.message == WM_MOUSEMOVE) {
|
||||
const bool samePosition = globalPosition == lastMouseMovePos;
|
||||
lastMouseMovePos = globalPosition;
|
||||
if (msg.wParam == 0 && (m_windowUnderMouse.isNull() || samePosition))
|
||||
discardEvent = true;
|
||||
}
|
||||
|
||||
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
|
||||
|
||||
const QPointingDevice *device = primaryMouse();
|
||||
|
||||
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
|
||||
static const bool passSynthesizedMouseEvents =
|
||||
!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
|
||||
// Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch.
|
||||
// However, when tablet support is active, extraInfo is a packet serial number. This is not a problem
|
||||
// since we do not want to ignore mouse events coming from a tablet.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx
|
||||
const auto extraInfo = quint64(GetMessageExtraInfo());
|
||||
if ((extraInfo & signatureMask) == miWpSignature) {
|
||||
if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen.
|
||||
source = Qt::MouseEventSynthesizedBySystem;
|
||||
if (!m_touchDevice.isNull())
|
||||
device = m_touchDevice.data();
|
||||
if (!passSynthesizedMouseEvents)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
|
||||
const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
|
||||
const MouseEvent mouseEvent = eventFromMsg(msg);
|
||||
Qt::MouseButtons buttons;
|
||||
|
||||
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
|
||||
buttons = queryMouseButtons();
|
||||
else
|
||||
buttons = keyStateToMouseButtons(msg.wParam);
|
||||
|
||||
// When the left/right mouse buttons are pressed over the window title bar
|
||||
// WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP
|
||||
// messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE.
|
||||
// We detect it and generate the missing release events here. (QTBUG-75678)
|
||||
// The last event vars are cleared on QWindowsContext::handleExitSizeMove()
|
||||
// to avoid generating duplicated release events.
|
||||
if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
|
||||
&& (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
|
||||
&& (m_lastEventButton & buttons) == 0) {
|
||||
auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
|
||||
QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
|
||||
QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons, m_lastEventButton,
|
||||
releaseType, keyModifiers, source);
|
||||
}
|
||||
m_lastEventType = mouseEvent.type;
|
||||
m_lastEventButton = mouseEvent.button;
|
||||
|
||||
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
|
||||
QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition,
|
||||
globalPosition, buttons,
|
||||
mouseEvent.button, mouseEvent.type,
|
||||
keyModifiers, source);
|
||||
return false; // Allow further event processing (dragging of windows).
|
||||
}
|
||||
|
||||
*result = 0;
|
||||
if (msg.message == WM_MOUSELEAVE) {
|
||||
qCDebug(lcQpaEvents) << mouseEvent << "for" << window << "previous window under mouse="
|
||||
<< m_windowUnderMouse << "tracked window=" << m_trackedWindow;
|
||||
|
||||
// When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first,
|
||||
// so if m_trackedWindow is not the window here, it means the cursor has left the
|
||||
// application.
|
||||
if (window == m_trackedWindow) {
|
||||
QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow;
|
||||
qCDebug(lcQpaEvents) << "Generating leave event for " << leaveTarget;
|
||||
QWindowSystemInterface::handleLeaveEvent(leaveTarget);
|
||||
m_trackedWindow = nullptr;
|
||||
m_windowUnderMouse = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto *platformWindow = static_cast<QWindowsWindow *>(window->handle());
|
||||
|
||||
// If the window was recently resized via mouse double-click on the frame or title bar,
|
||||
// we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click,
|
||||
// but we will get at least one WM_MOUSEMOVE with left button down and the WM_LBUTTONUP,
|
||||
// which will result undesired mouse press and release events.
|
||||
// To avoid those, we ignore any events with left button down if we didn't
|
||||
// get the original WM_LBUTTONDOWN/WM_LBUTTONDBLCLK.
|
||||
if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK) {
|
||||
m_leftButtonDown = true;
|
||||
} else {
|
||||
const bool actualLeftDown = buttons & Qt::LeftButton;
|
||||
if (!m_leftButtonDown && actualLeftDown) {
|
||||
// Autocapture the mouse for current window to and ignore further events until release.
|
||||
// Capture is necessary so we don't get WM_MOUSELEAVEs to confuse matters.
|
||||
// This autocapture is released normally when button is released.
|
||||
if (!platformWindow->hasMouseCapture()) {
|
||||
platformWindow->applyCursor();
|
||||
platformWindow->setMouseGrabEnabled(true);
|
||||
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
|
||||
qCDebug(lcQpaEvents) << "Automatic mouse capture for missing buttondown event" << window;
|
||||
}
|
||||
m_previousCaptureWindow = window;
|
||||
return true;
|
||||
}
|
||||
if (m_leftButtonDown && !actualLeftDown)
|
||||
m_leftButtonDown = false;
|
||||
}
|
||||
|
||||
// In this context, neither an invisible nor a transparent window (transparent regarding mouse
|
||||
// events, "click-through") can be considered as the window under mouse.
|
||||
QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
|
||||
QWindowsScreen::windowAt(globalPosition, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window;
|
||||
while (currentWindowUnderMouse && currentWindowUnderMouse->flags() & Qt::WindowTransparentForInput)
|
||||
currentWindowUnderMouse = currentWindowUnderMouse->parent();
|
||||
// QTBUG-44332: When Qt is running at low integrity level and
|
||||
// a Qt Window is parented on a Window of a higher integrity process
|
||||
// using QWindow::fromWinId() (for example, Qt running in a browser plugin)
|
||||
// ChildWindowFromPointEx() may not find the Qt window (failing with ERROR_ACCESS_DENIED)
|
||||
if (!currentWindowUnderMouse) {
|
||||
const QRect clientRect(QPoint(0, 0), window->size());
|
||||
if (clientRect.contains(winEventPosition))
|
||||
currentWindowUnderMouse = window;
|
||||
}
|
||||
|
||||
compressMouseMove(&msg);
|
||||
// Qt expects the platform plugin to capture the mouse on
|
||||
// any button press until release.
|
||||
if (!platformWindow->hasMouseCapture()
|
||||
&& (mouseEvent.type == QEvent::MouseButtonPress || mouseEvent.type == QEvent::MouseButtonDblClick)) {
|
||||
platformWindow->setMouseGrabEnabled(true);
|
||||
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
|
||||
qCDebug(lcQpaEvents) << "Automatic mouse capture " << window;
|
||||
// Implement "Click to focus" for native child windows (unless it is a native widget window).
|
||||
if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window)
|
||||
window->requestActivate();
|
||||
} else if (platformWindow->hasMouseCapture()
|
||||
&& platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
|
||||
&& mouseEvent.type == QEvent::MouseButtonRelease
|
||||
&& !buttons) {
|
||||
platformWindow->setMouseGrabEnabled(false);
|
||||
qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window;
|
||||
}
|
||||
|
||||
const bool hasCapture = platformWindow->hasMouseCapture();
|
||||
const bool currentNotCapturing = hasCapture && currentWindowUnderMouse != window;
|
||||
// Enter new window: track to generate leave event.
|
||||
// If there is an active capture, only track if the current window is capturing,
|
||||
// so we don't get extra leave when cursor leaves the application.
|
||||
if (window != m_trackedWindow && !currentNotCapturing) {
|
||||
TRACKMOUSEEVENT tme;
|
||||
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||
tme.dwFlags = TME_LEAVE;
|
||||
tme.hwndTrack = hwnd;
|
||||
tme.dwHoverTime = HOVER_DEFAULT; //
|
||||
if (!TrackMouseEvent(&tme))
|
||||
qWarning("TrackMouseEvent failed.");
|
||||
m_trackedWindow = window;
|
||||
}
|
||||
|
||||
// No enter or leave events are sent as long as there is an autocapturing window.
|
||||
if (!hasCapture || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) {
|
||||
// Leave is needed if:
|
||||
// 1) There is no capture and we move from a window to another window.
|
||||
// Note: Leaving the application entirely is handled in WM_MOUSELEAVE case.
|
||||
// 2) There is capture and we move out of the capturing window.
|
||||
// 3) There is a new capture and we were over another window.
|
||||
if ((m_windowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
|
||||
&& (!hasCapture || window == m_windowUnderMouse))
|
||||
|| (hasCapture && m_previousCaptureWindow != window && m_windowUnderMouse
|
||||
&& m_windowUnderMouse != window)) {
|
||||
qCDebug(lcQpaEvents) << "Synthetic leave for " << m_windowUnderMouse;
|
||||
QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
|
||||
if (currentNotCapturing) {
|
||||
// Clear tracking if capturing and current window is not the capturing window
|
||||
// to avoid leave when mouse actually leaves the application.
|
||||
m_trackedWindow = nullptr;
|
||||
// We are not officially in any window, but we need to set some cursor to clear
|
||||
// whatever cursor the left window had, so apply the cursor of the capture window.
|
||||
platformWindow->applyCursor();
|
||||
}
|
||||
}
|
||||
// Enter is needed if:
|
||||
// 1) There is no capture and we move to a new window.
|
||||
// 2) There is capture and we move into the capturing window.
|
||||
// 3) The capture just ended and we are over non-capturing window.
|
||||
if ((currentWindowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
|
||||
&& (!hasCapture || currentWindowUnderMouse == window))
|
||||
|| (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse
|
||||
&& currentWindowUnderMouse != m_previousCaptureWindow)) {
|
||||
QPoint localPosition;
|
||||
qCDebug(lcQpaEvents) << "Entering " << currentWindowUnderMouse;
|
||||
if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderMouse)) {
|
||||
localPosition = wumPlatformWindow->mapFromGlobal(globalPosition);
|
||||
wumPlatformWindow->applyCursor();
|
||||
}
|
||||
QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse, localPosition, globalPosition);
|
||||
}
|
||||
// We need to track m_windowUnderMouse separately from m_trackedWindow, as
|
||||
// Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when
|
||||
// mouse capture is set.
|
||||
m_windowUnderMouse = currentWindowUnderMouse;
|
||||
}
|
||||
|
||||
if (!discardEvent && mouseEvent.type != QEvent::None) {
|
||||
QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons,
|
||||
mouseEvent.button, mouseEvent.type,
|
||||
keyModifiers, source);
|
||||
}
|
||||
m_previousCaptureWindow = hasCapture ? window : nullptr;
|
||||
// QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
|
||||
// is sent for unhandled WM_XBUTTONDOWN.
|
||||
return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
|
||||
|| QWindowSystemInterface::flushWindowSystemEvents();
|
||||
}
|
||||
|
||||
static bool isValidWheelReceiver(QWindow *candidate)
|
||||
{
|
||||
if (candidate) {
|
||||
const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate);
|
||||
if (toplevel->handle() && toplevel->handle()->isForeignWindow())
|
||||
return true;
|
||||
if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel))
|
||||
return !ww->testFlag(QWindowsWindow::BlockedByModal);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void redirectWheelEvent(QWindow *window, unsigned long timestamp, const QPoint &globalPos, int delta,
|
||||
Qt::Orientation orientation, Qt::KeyboardModifiers mods)
|
||||
{
|
||||
// Redirect wheel event to one of the following, in order of preference:
|
||||
// 1) The window under mouse
|
||||
// 2) The window receiving the event
|
||||
// If a window is blocked by modality, it can't get the event.
|
||||
|
||||
QWindow *receiver = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE);
|
||||
while (receiver && receiver->flags().testFlag(Qt::WindowTransparentForInput))
|
||||
receiver = receiver->parent();
|
||||
bool handleEvent = true;
|
||||
if (!isValidWheelReceiver(receiver)) {
|
||||
receiver = window;
|
||||
if (!isValidWheelReceiver(receiver))
|
||||
handleEvent = false;
|
||||
}
|
||||
|
||||
if (handleEvent) {
|
||||
const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0);
|
||||
QWindowSystemInterface::handleWheelEvent(receiver,
|
||||
timestamp,
|
||||
QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
|
||||
globalPos, QPoint(), point, mods);
|
||||
}
|
||||
}
|
||||
|
||||
bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
|
||||
MSG msg, LRESULT *)
|
||||
{
|
||||
const Qt::KeyboardModifiers mods = keyStateToModifiers(int(msg.wParam));
|
||||
|
||||
int delta;
|
||||
if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
|
||||
delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
|
||||
else
|
||||
delta = int(msg.wParam);
|
||||
|
||||
Qt::Orientation orientation = (msg.message == WM_MOUSEHWHEEL
|
||||
|| (mods & 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));
|
||||
redirectWheelEvent(window, msg.time, globalPos, delta, orientation, mods);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QWindowsMouseHandler::translateScrollEvent(QWindow *window, HWND,
|
||||
MSG msg, LRESULT *)
|
||||
{
|
||||
// This is a workaround against some touchpads that send WM_HSCROLL instead of WM_MOUSEHWHEEL.
|
||||
// We could also handle vertical scroll here but there's no reason to, there's no bug for vertical
|
||||
// (broken vertical scroll would have been noticed long time ago), so lets keep the change small
|
||||
// and minimize the chance for regressions.
|
||||
|
||||
int delta = 0;
|
||||
switch (LOWORD(msg.wParam)) {
|
||||
case SB_LINELEFT:
|
||||
delta = 120;
|
||||
break;
|
||||
case SB_LINERIGHT:
|
||||
delta = -120;
|
||||
break;
|
||||
case SB_PAGELEFT:
|
||||
delta = 240;
|
||||
break;
|
||||
case SB_PAGERIGHT:
|
||||
delta = -240;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
redirectWheelEvent(window, msg.time, QCursor::pos(), delta, Qt::Horizontal, Qt::NoModifier);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// from bool QApplicationPrivate::translateTouchEvent()
|
||||
bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
|
||||
QtWindows::WindowsEventType,
|
||||
MSG msg, LRESULT *)
|
||||
{
|
||||
using QTouchPoint = QWindowSystemInterface::TouchPoint;
|
||||
using QTouchPointList = QList<QWindowSystemInterface::TouchPoint>;
|
||||
|
||||
if (!QWindowsContext::instance()->initTouch()) {
|
||||
qWarning("Unable to initialize touch handling.");
|
||||
return true;
|
||||
}
|
||||
|
||||
const QScreen *screen = window->screen();
|
||||
if (!screen)
|
||||
screen = QGuiApplication::primaryScreen();
|
||||
if (!screen)
|
||||
return true;
|
||||
const QRect screenGeometry = screen->geometry();
|
||||
|
||||
const int winTouchPointCount = int(msg.wParam);
|
||||
const auto winTouchInputs = std::make_unique<TOUCHINPUT[]>(winTouchPointCount);
|
||||
|
||||
QTouchPointList touchPoints;
|
||||
touchPoints.reserve(winTouchPointCount);
|
||||
QEventPoint::States allStates;
|
||||
|
||||
GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(msg.lParam),
|
||||
UINT(msg.wParam), winTouchInputs.get(), sizeof(TOUCHINPUT));
|
||||
for (int i = 0; i < winTouchPointCount; ++i) {
|
||||
const TOUCHINPUT &winTouchInput = winTouchInputs[i];
|
||||
int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1);
|
||||
if (id == -1) {
|
||||
id = m_touchInputIDToTouchPointID.size();
|
||||
m_touchInputIDToTouchPointID.insert(winTouchInput.dwID, id);
|
||||
}
|
||||
QTouchPoint touchPoint;
|
||||
touchPoint.pressure = 1.0;
|
||||
touchPoint.id = id;
|
||||
if (m_lastTouchPositions.contains(id))
|
||||
touchPoint.normalPosition = m_lastTouchPositions.value(id);
|
||||
|
||||
const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) / qreal(100.);
|
||||
if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
|
||||
touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) / qreal(100.));
|
||||
touchPoint.area.moveCenter(screenPos);
|
||||
QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
|
||||
screenPos.y() / screenGeometry.height());
|
||||
const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
|
||||
touchPoint.normalPosition = normalPosition;
|
||||
|
||||
if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
|
||||
touchPoint.state = QEventPoint::State::Pressed;
|
||||
m_lastTouchPositions.insert(id, touchPoint.normalPosition);
|
||||
} else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
|
||||
touchPoint.state = QEventPoint::State::Released;
|
||||
m_lastTouchPositions.remove(id);
|
||||
} else {
|
||||
touchPoint.state = (stationaryTouchPoint
|
||||
? QEventPoint::State::Stationary
|
||||
: QEventPoint::State::Updated);
|
||||
m_lastTouchPositions.insert(id, touchPoint.normalPosition);
|
||||
}
|
||||
|
||||
allStates |= touchPoint.state;
|
||||
|
||||
touchPoints.append(touchPoint);
|
||||
}
|
||||
|
||||
CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(msg.lParam));
|
||||
|
||||
// all touch points released, forget the ids we've seen, they may not be reused
|
||||
if (allStates == QEventPoint::State::Released)
|
||||
m_touchInputIDToTouchPointID.clear();
|
||||
|
||||
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
|
||||
QWindowSystemInterface::handleTouchEvent(window,
|
||||
msg.time,
|
||||
m_touchDevice.data(),
|
||||
touchPoints,
|
||||
keyMapper->queryKeyboardModifiers());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QWindowsMouseHandler::translateGestureEvent(QWindow *window, HWND hwnd,
|
||||
QtWindows::WindowsEventType,
|
||||
MSG msg, LRESULT *)
|
||||
{
|
||||
Q_UNUSED(window);
|
||||
Q_UNUSED(hwnd);
|
||||
Q_UNUSED(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -1,115 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QWINDOWSMOUSEHANDLER_H
|
||||
#define QWINDOWSMOUSEHANDLER_H
|
||||
|
||||
#include "qtwindowsglobal.h"
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtGui/qevent.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindow;
|
||||
class QPointingDevice;
|
||||
|
||||
class QWindowsMouseHandler
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(QWindowsMouseHandler)
|
||||
public:
|
||||
using QPointingDevicePtr = QSharedPointer<QPointingDevice>;
|
||||
|
||||
QWindowsMouseHandler();
|
||||
|
||||
const QPointingDevicePtr &touchDevice() const { return m_touchDevice; }
|
||||
void setTouchDevice(const QPointingDevicePtr &d) { m_touchDevice = d; }
|
||||
|
||||
bool translateMouseEvent(QWindow *widget, HWND hwnd,
|
||||
QtWindows::WindowsEventType t, MSG msg,
|
||||
LRESULT *result);
|
||||
bool translateTouchEvent(QWindow *widget, HWND hwnd,
|
||||
QtWindows::WindowsEventType t, MSG msg,
|
||||
LRESULT *result);
|
||||
bool translateGestureEvent(QWindow *window, HWND hwnd,
|
||||
QtWindows::WindowsEventType,
|
||||
MSG msg, LRESULT *);
|
||||
bool translateScrollEvent(QWindow *window, HWND hwnd,
|
||||
MSG msg, LRESULT *result);
|
||||
|
||||
static inline Qt::MouseButtons keyStateToMouseButtons(WPARAM);
|
||||
static inline Qt::KeyboardModifiers keyStateToModifiers(int);
|
||||
static inline int mouseButtonsToKeyState(Qt::MouseButtons);
|
||||
|
||||
static Qt::MouseButtons queryMouseButtons();
|
||||
QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); }
|
||||
void clearWindowUnderMouse() { m_windowUnderMouse = nullptr; }
|
||||
void clearEvents();
|
||||
|
||||
static const QPointingDevice *primaryMouse();
|
||||
|
||||
private:
|
||||
inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd,
|
||||
MSG msg, LRESULT *result);
|
||||
|
||||
QPointer<QWindow> m_windowUnderMouse;
|
||||
QPointer<QWindow> m_trackedWindow;
|
||||
QHash<DWORD, int> m_touchInputIDToTouchPointID;
|
||||
QHash<int, QPointF> m_lastTouchPositions;
|
||||
QPointingDevicePtr m_touchDevice;
|
||||
bool m_leftButtonDown = false;
|
||||
QWindow *m_previousCaptureWindow = nullptr;
|
||||
QEvent::Type m_lastEventType = QEvent::None;
|
||||
Qt::MouseButton m_lastEventButton = Qt::NoButton;
|
||||
};
|
||||
|
||||
Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(WPARAM wParam)
|
||||
{
|
||||
Qt::MouseButtons mb(Qt::NoButton);
|
||||
if (wParam & MK_LBUTTON)
|
||||
mb |= Qt::LeftButton;
|
||||
if (wParam & MK_MBUTTON)
|
||||
mb |= Qt::MiddleButton;
|
||||
if (wParam & MK_RBUTTON)
|
||||
mb |= Qt::RightButton;
|
||||
if (wParam & MK_XBUTTON1)
|
||||
mb |= Qt::XButton1;
|
||||
if (wParam & MK_XBUTTON2)
|
||||
mb |= Qt::XButton2;
|
||||
return mb;
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers QWindowsMouseHandler::keyStateToModifiers(int wParam)
|
||||
{
|
||||
Qt::KeyboardModifiers mods(Qt::NoModifier);
|
||||
if (wParam & MK_CONTROL)
|
||||
mods |= Qt::ControlModifier;
|
||||
if (wParam & MK_SHIFT)
|
||||
mods |= Qt::ShiftModifier;
|
||||
if (GetKeyState(VK_MENU) < 0)
|
||||
mods |= Qt::AltModifier;
|
||||
return mods;
|
||||
}
|
||||
|
||||
int QWindowsMouseHandler::mouseButtonsToKeyState(Qt::MouseButtons mb)
|
||||
{
|
||||
int result = 0;
|
||||
if (mb & Qt::LeftButton)
|
||||
result |= MK_LBUTTON;
|
||||
if (mb & Qt::MiddleButton)
|
||||
result |= MK_MBUTTON;
|
||||
if (mb & Qt::RightButton)
|
||||
result |= MK_RBUTTON;
|
||||
if (mb & Qt::XButton1)
|
||||
result |= MK_XBUTTON1;
|
||||
if (mb & Qt::XButton2)
|
||||
result |= MK_XBUTTON2;
|
||||
return result;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWINDOWSMOUSEHANDLER_H
|
@ -4,7 +4,6 @@
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#include "qwindowspointerhandler.h"
|
||||
#include "qwindowsmousehandler.h"
|
||||
#if QT_CONFIG(tabletevent)
|
||||
# include "qwindowstabletsupport.h"
|
||||
#endif
|
||||
@ -39,6 +38,14 @@ enum {
|
||||
|
||||
qint64 QWindowsPointerHandler::m_nextInputDeviceId = 1;
|
||||
|
||||
const QPointingDevice *primaryMouse()
|
||||
{
|
||||
static QPointer<const QPointingDevice> result;
|
||||
if (!result)
|
||||
result = QPointingDevice::primaryPointingDevice();
|
||||
return result;
|
||||
}
|
||||
|
||||
QWindowsPointerHandler::~QWindowsPointerHandler()
|
||||
{
|
||||
}
|
||||
@ -215,7 +222,7 @@ static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)
|
||||
return result;
|
||||
}
|
||||
|
||||
static Qt::MouseButtons queryMouseButtons()
|
||||
Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons()
|
||||
{
|
||||
Qt::MouseButtons result = Qt::NoButton;
|
||||
const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
|
||||
@ -785,7 +792,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
|
||||
}
|
||||
|
||||
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
|
||||
const QPointingDevice *device = QWindowsMouseHandler::primaryMouse();
|
||||
const QPointingDevice *device = primaryMouse();
|
||||
|
||||
// Following the logic of the old mouse handler, only events synthesized
|
||||
// for touch screen are marked as such. On some systems, using the bit 7 of
|
||||
|
@ -38,12 +38,15 @@ public:
|
||||
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
|
||||
void clearEvents();
|
||||
|
||||
static Qt::MouseButtons queryMouseButtons();
|
||||
|
||||
private:
|
||||
bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count);
|
||||
bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo);
|
||||
bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers);
|
||||
void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons);
|
||||
void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos);
|
||||
|
||||
#if QT_CONFIG(tabletevent)
|
||||
QPointingDevicePtr findTabletDevice(QPointingDevice::PointerType pointerType) const;
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user