diff options
Diffstat (limited to 'src/plugins/platforms/windows')
23 files changed, 202 insertions, 881 deletions
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt index 4b92317978..bbb8c46cf6 100644 --- a/src/plugins/platforms/windows/CMakeLists.txt +++ b/src/plugins/platforms/windows/CMakeLists.txt @@ -8,7 +8,7 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin OUTPUT_NAME qwindows PLUGIN_TYPE platforms - DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES windows + DEFAULT_IF "windows" IN_LIST QT_QPA_PLATFORMS SOURCES main.cpp qtwindowsglobal.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 @@ -132,6 +131,8 @@ qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_tablete qwindowstabletsupport.cpp qwindowstabletsupport.h INCLUDE_DIRECTORIES ${QtBase_SOURCE_DIR}/src/3rdparty/wintab + ATTRIBUTION_FILE_DIR_PATHS + ../../../3rdparty/wintab ) qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_sessionmanager diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index de65a2171d..11a9290a2e 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -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); @@ -201,6 +199,8 @@ QWindowsContext::~QWindowsContext() if (d->m_powerDummyWindow) DestroyWindow(d->m_powerDummyWindow); + d->m_screenManager.destroyWindow(); + unregisterWindowClasses(); if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) { #ifdef QT_USE_FACTORY_CACHE_REGISTRATION @@ -224,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; @@ -234,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; @@ -274,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) @@ -728,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(); + d->m_pointerHandler.clearWindowUnderMouse(); } /*! @@ -1050,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: @@ -1191,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); + return sessionManagerInteractionBlocked() || d->m_pointerHandler.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; + return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result); case QtWindows::EnterSizeMoveEvent: platformWindow->setFlag(QWindowsWindow::ResizeMoveActive); if (!IsZoomed(hwnd)) @@ -1214,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: @@ -1226,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); + return sessionManagerInteractionBlocked() || d->m_pointerHandler.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; + return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result); case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow(). case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); @@ -1443,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; @@ -1459,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(); + d->m_pointerHandler.clearEvents(); } bool QWindowsContext::asyncExpose() const diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 0539a22afc..4e9be1af96 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -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(); diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index c6f55c3509..b872ef2ad6 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -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(), diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 0281025b5b..4b524c7a2c 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -5,7 +5,6 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsintegration.h" -#include "qwindowsmousehandler.h" #include <QtCore/qdebug.h> #include <QtCore/qobject.h> diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index aa6be266da..487e1d47b6 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -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(); + QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents); QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication. diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index c271207741..932a69a6b7 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -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); diff --git a/src/plugins/platforms/windows/qwindowsmimeregistry.cpp b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp index 8d147e8fa0..71faf4fe3b 100644 --- a/src/plugins/platforms/windows/qwindowsmimeregistry.cpp +++ b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp @@ -923,16 +923,8 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject * const bool canGetDibV5 = canGetData(CF_DIBV5, pDataObj); const bool hasOrigDibV5 = canGetDibV5 ? hasOriginalDIBV5(pDataObj) : false; qCDebug(lcQpaMime) << "canGetDibV5:" << canGetDibV5 << "hasOrigDibV5:" << hasOrigDibV5; - if (hasOrigDibV5) { - qCDebug(lcQpaMime) << "Decoding DIBV5"; - QImage img; - QByteArray data = getData(CF_DIBV5, pDataObj); - QBuffer buffer(&data); - if (readDib(buffer, img)) - return img; - } - //PNG, MS Office place this (undocumented) - if (canGetData(CF_PNG, pDataObj)) { + // PNG, MS Office place this (undocumented) + if (!hasOrigDibV5 && canGetData(CF_PNG, pDataObj)) { qCDebug(lcQpaMime) << "Decoding PNG"; QImage img; QByteArray data = getData(CF_PNG, pDataObj); @@ -940,11 +932,11 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject * return img; } } - //Fallback to DIB - if (canGetData(CF_DIB, pDataObj)) { + + if (canGetDibV5 || canGetData(CF_DIB, pDataObj)) { qCDebug(lcQpaMime) << "Decoding DIB"; QImage img; - QByteArray data = getData(CF_DIBV5, pDataObj); + QByteArray data = getData(canGetDibV5 ? CF_DIBV5 : CF_DIB, pDataObj); QBuffer buffer(&data); if (readDib(buffer, img)) return img; diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp deleted file mode 100644 index 9af9fba408..0000000000 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ /dev/null @@ -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 diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h deleted file mode 100644 index 7fde349f58..0000000000 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ /dev/null @@ -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 diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 6a790bcc1b..38d1cdd738 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -65,7 +65,9 @@ private: QDirect3D9Handle::QDirect3D9Handle() { +#ifndef QT_NO_OPENGL m_direct3D9 = Direct3DCreate9(D3D_SDK_VERSION); +#endif } QDirect3D9Handle::~QDirect3D9Handle() diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 71c7217671..7995716444 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -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 diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index b64a8c146a..1827dd9df0 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -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 diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index a50f9fd4b0..1f22fb4f60 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -698,11 +698,15 @@ void QWindowsScreenManager::initialize() handleScreenChanges(); } -QWindowsScreenManager::~QWindowsScreenManager() +void QWindowsScreenManager::destroyWindow() { + qCDebug(lcQpaScreen) << "Destroying display change observer" << m_displayChangeObserver; DestroyWindow(m_displayChangeObserver); + m_displayChangeObserver = nullptr; } +QWindowsScreenManager::~QWindowsScreenManager() = default; + bool QWindowsScreenManager::isSingleScreen() { return QWindowsContext::instance()->screenManager().screens().size() < 2; diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 0467ab2a0c..ea6a29efe3 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -105,6 +105,7 @@ public: QWindowsScreenManager(); void initialize(); + void destroyWindow(); ~QWindowsScreenManager(); void clearScreens(); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 96ae6197b4..a89fb1e5bd 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -33,7 +33,6 @@ public: Qt::ColorScheme colorScheme() const override; void requestColorScheme(Qt::ColorScheme scheme) override; - Qt::ColorScheme requestedColorScheme() const { return s_colorSchemeOverride; } static void handleSettingsChanged(); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index ee0b88ba54..4b7ce0a979 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -855,12 +855,6 @@ static inline bool shouldApplyDarkFrame(const QWindow *w) if (!QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) return false; - // the application explicitly overrides the color scheme - if (const auto requestedColorScheme = QWindowsTheme::instance()->requestedColorScheme(); - requestedColorScheme != Qt::ColorScheme::Unknown) { - return requestedColorScheme == Qt::ColorScheme::Dark; - } - // if the application supports a dark border, and the palette is dark (window background color // is darker than the text), then turn dark-border support on, otherwise use a light border. auto *dWindow = QWindowPrivate::get(const_cast<QWindow*>(w)); @@ -2488,6 +2482,11 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) GetWindowPlacement(m_data.hwnd, &windowPlacement); const RECT geometry = RECTfromQRect(m_data.restoreGeometry); windowPlacement.rcNormalPosition = geometry; + // Even if the window is hidden, windowPlacement's showCmd is not SW_HIDE, so change it + // manually to avoid unhiding a hidden window with the subsequent call to + // SetWindowPlacement(). + if (!isVisible()) + windowPlacement.showCmd = SW_HIDE; SetWindowPlacement(m_data.hwnd, &windowPlacement); } // QTBUG-17548: We send expose events when receiving WM_Paint, but for diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 024711e7f3..b3cddc11d8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -347,6 +347,8 @@ public: int savedDpi() const { return m_savedDpi; } qreal dpiRelativeScale(const UINT dpi) const; + bool isFrameless() const { return m_data.flags.testFlag(Qt::FramelessWindowHint); } + private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp index 1abb412ccd..5892493281 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp @@ -127,6 +127,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event return; switch (event->type()) { + case QAccessible::Announcement: + QWindowsUiaMainProvider::raiseNotification(static_cast<QAccessibleAnnouncementEvent *>(event)); + break; case QAccessible::Focus: QWindowsUiaMainProvider::notifyFocusChange(event); break; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 95ddbcced6..0f2e2d8a5c 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -23,6 +23,7 @@ #include "qwindowsuiaprovidercache.h" #include <QtCore/qloggingcategory.h> +#include <QtGui/private/qaccessiblebridgeutils_p.h> #include <QtGui/qaccessible.h> #include <QtGui/qguiapplication.h> #include <QtGui/qwindow.h> @@ -204,6 +205,24 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event) } } +void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + BSTR message = bStrFromQString(event->message()); + QAccessible::AnnouncementPoliteness prio = event->politeness(); + NotificationProcessing processing = (prio == QAccessible::AnnouncementPoliteness::Assertive) + ? NotificationProcessing_ImportantAll + : NotificationProcessing_All; + BSTR activityId = bStrFromQString(QString::fromLatin1("")); + UiaRaiseNotificationEvent(provider, NotificationKind_Other, processing, message, activityId); + + ::SysFreeString(message); + ::SysFreeString(activityId); + } + } +} + HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface) { HRESULT result = QComObject::QueryInterface(iid, iface); @@ -370,6 +389,93 @@ void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface* pRetVal->parray = elements; } +void QWindowsUiaMainProvider::setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal) +{ + Q_ASSERT(accessible); + + QAccessibleAttributesInterface *attributesIface = accessible->attributesInterface(); + if (!attributesIface) + return; + + QString ariaString; + const QList<QAccessible::Attribute> attrKeys = attributesIface->attributeKeys(); + for (qsizetype i = 0; i < attrKeys.size(); ++i) { + if (i != 0) + ariaString += QStringLiteral(";"); + const QAccessible::Attribute key = attrKeys.at(i); + const QVariant value = attributesIface->attributeValue(key); + // see "Core Accessibility API Mappings" spec: https://www.w3.org/TR/core-aam-1.2/ + switch (key) { + case QAccessible::Attribute::Custom: + { + // forward custom attributes as-is + Q_ASSERT((value.canConvert<QHash<QString, QString>>())); + const QHash<QString, QString> attrMap = value.value<QHash<QString, QString>>(); + for (auto [name, val] : attrMap.asKeyValueRange()) { + if (name != *attrMap.keyBegin()) + ariaString += QStringLiteral(";"); + ariaString += name + QStringLiteral("=") + val; + } + break; + } + case QAccessible::Attribute::Level: + Q_ASSERT(value.canConvert<int>()); + ariaString += QStringLiteral("level=") + QString::number(value.toInt()); + break; + default: + break; + } + } + + setVariantString(ariaString, pRetVal); +} + +void QWindowsUiaMainProvider::setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal) +{ + Q_ASSERT(accessible); + + QAccessibleAttributesInterface *attributesIface = accessible->attributesInterface(); + if (!attributesIface) + return; + + // currently, only heading styles are implemented here + if (accessible->role() != QAccessible::Role::Heading) + return; + + const QVariant levelVariant = attributesIface->attributeValue(QAccessible::Attribute::Level); + if (!levelVariant.isValid()) + return; + + Q_ASSERT(levelVariant.canConvert<int>()); + // UIA only has styles for heading levels 1-9 + const int level = levelVariant.toInt(); + if (level < 1 || level > 9) + return; + + const int styleId = styleIdForHeadingLevel(level); + setVariantI4(styleId, pRetVal); +} + +int QWindowsUiaMainProvider::styleIdForHeadingLevel(int headingLevel) +{ + // only heading levels 1-9 have a corresponding UIA style ID + Q_ASSERT(headingLevel > 0 && headingLevel <= 9); + + static constexpr int styles[] = { + StyleId_Heading1, + StyleId_Heading2, + StyleId_Heading3, + StyleId_Heading4, + StyleId_Heading5, + StyleId_Heading6, + StyleId_Heading7, + StyleId_Heading8, + StyleId_Heading9, + }; + + return styles[headingLevel - 1]; +} + HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal) { qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp; @@ -393,9 +499,12 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR // Accelerator key. setVariantString(accessible->text(QAccessible::Accelerator), pRetVal); break; + case UIA_AriaPropertiesPropertyId: + setAriaProperties(accessible, pRetVal); + break; case UIA_AutomationIdPropertyId: // Automation ID, which can be used by tools to select a specific control in the UI. - setVariantString(automationIdForAccessible(accessible), pRetVal); + setVariantString(QAccessibleBridgeUtils::accessibleId(accessible), pRetVal); break; case UIA_ClassNamePropertyId: // Class name. @@ -493,31 +602,15 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR setVariantString(name, pRetVal); break; } + case UIA_StyleIdAttributeId: + setStyle(accessible, pRetVal); + break; default: break; } return S_OK; } -// Generates an ID based on the name of the controls and their parents. -QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInterface *accessible) -{ - QString result; - if (accessible) { - QObject *obj = accessible->object(); - while (obj) { - QString name = obj->objectName(); - if (name.isEmpty()) - return result; - if (!result.isEmpty()) - result.prepend(u'.'); - result.prepend(name); - obj = obj->parent(); - } - } - return result; -} - HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderSimple **pRetVal) { qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h index 99db0ed318..8ea343e425 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h @@ -34,6 +34,7 @@ public: static void notifyNameChange(QAccessibleEvent *event); static void notifySelectionChange(QAccessibleEvent *event); static void notifyTextChange(QAccessibleEvent *event); + static void raiseNotification(QAccessibleAnnouncementEvent *event); // IUnknown HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override; @@ -58,8 +59,11 @@ public: HRESULT STDMETHODCALLTYPE GetFocus(IRawElementProviderFragment **pRetVal) override; private: - QString automationIdForAccessible(const QAccessibleInterface *accessible); static void fillVariantArrayForRelation(QAccessibleInterface *accessible, QAccessible::Relation relation, VARIANT *pRetVal); + static void setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal); + static void setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal); + /** Returns the UIA style ID for a heading level from 1 to 9. */ + static int styleIdForHeadingLevel(int headingLevel); static QMutex m_mutex; }; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp index 1593a07202..6954a881d0 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp @@ -69,6 +69,14 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *pProvider, EVE return func.invoke(pProvider, id); } +HRESULT WINAPI UiaRaiseNotificationEvent( + IRawElementProviderSimple *pProvider, NotificationKind notificationKind, + NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId) +{ + static auto func = winapi_func("uiautomationcore", FN(UiaRaiseNotificationEvent)); + return func.invoke(pProvider, notificationKind, notificationProcessing, displayString, activityId); +} + #endif // defined(__MINGW32__) || defined(__MINGW64__) #endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h index a192b9b0fb..4eb37bafa0 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h @@ -14,8 +14,19 @@ #define UIA_SelectionPattern2Id 10034 #define UIA_IsReadOnlyAttributeId 40015 #define UIA_StrikethroughStyleAttributeId 40026 +#define UIA_StyleIdAttributeId 40034 #define UIA_CaretPositionAttributeId 40038 +#define StyleId_Heading1 70001 +#define StyleId_Heading2 70002 +#define StyleId_Heading3 70003 +#define StyleId_Heading4 70004 +#define StyleId_Heading5 70005 +#define StyleId_Heading6 70006 +#define StyleId_Heading7 70007 +#define StyleId_Heading8 70008 +#define StyleId_Heading9 70009 + enum CaretPosition { CaretPosition_Unknown = 0, CaretPosition_EndOfLine = 1, |