diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowscontext.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowscontext.cpp | 251 |
1 files changed, 217 insertions, 34 deletions
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index b0c9349da5..1f80ac5872 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -43,6 +43,7 @@ #include "qwindowswindow.h" #include "qwindowskeymapper.h" #include "qwindowsmousehandler.h" +#include "qwindowspointerhandler.h" #include "qtwindowsglobal.h" #include "qwindowsmenu.h" #include "qwindowsmime.h" @@ -52,7 +53,7 @@ #endif #include "qwindowstheme.h" #include <private/qguiapplication_p.h> -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) # include "uiautomation/qwindowsuiaaccessibility.h" #endif #if QT_CONFIG(sessionmanager) @@ -62,20 +63,20 @@ #include "qwindowsscreen.h" #include "qwindowstheme.h" -#include <QtGui/qtguiglobal.h> -#include <QtGui/QWindow> +#include <QtGui/qwindow.h> #include <qpa/qwindowsysteminterface.h> +#include <qpa/qwindowsysteminterface_p.h> #include <qpa/qplatformnativeinterface.h> -#include <QtGui/QGuiApplication> -#include <QtGui/QOpenGLContext> - -#include <QtCore/QSet> -#include <QtCore/QHash> -#include <QtCore/QStringList> -#include <QtCore/QDebug> -#include <QtCore/QOperatingSystemVersion> -#include <QtCore/QSysInfo> -#include <QtCore/QScopedArrayPointer> +#include <QtGui/qguiapplication.h> +#include <QtGui/qopenglcontext.h> + +#include <QtCore/qset.h> +#include <QtCore/qhash.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdebug.h> +#include <QtCore/qoperatingsystemversion.h> +#include <QtCore/qsysinfo.h> +#include <QtCore/qscopedpointer.h> #include <QtCore/private/qsystemlibrary_p.h> #include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h> @@ -85,11 +86,11 @@ #include <windowsx.h> #include <comdef.h> #include <dbt.h> +#include <wtsapi32.h> QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows") -Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore") Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl") Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime") @@ -147,7 +148,7 @@ static inline bool sessionManagerInteractionBlocked() { return false; } static inline int windowDpiAwareness(HWND hwnd) { - return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext + return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; } @@ -194,14 +195,35 @@ void QWindowsUser32DLL::init() getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences"); setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences"); + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) { + enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer"); + getPointerType = (GetPointerType)library.resolve("GetPointerType"); + getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo"); + getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects"); + getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo"); + getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo"); + getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory"); + getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo"); + getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory"); + skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages"); + } + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) { enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling"); getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext"); getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext"); + systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi"); } } +bool QWindowsUser32DLL::supportsPointerApi() +{ + return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects + && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory + && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages; +} + void QWindowsShcoreDLL::init() { if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) @@ -239,6 +261,7 @@ struct QWindowsContextPrivate { int m_defaultDPI = 96; QWindowsKeyMapper m_keyMapper; QWindowsMouseHandler m_mouseHandler; + QWindowsPointerHandler m_pointerHandler; QWindowsMimeConverter m_mimeConverter; QWindowsScreenManager m_screenManager; QSharedPointer<QWindowCreationContext> m_creationContext; @@ -256,7 +279,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() QWindowsContext::user32dll.init(); QWindowsContext::shcoredll.init(); - if (m_mouseHandler.touchDevice()) + if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; m_displayContext = GetDC(0); m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY); @@ -281,10 +304,6 @@ QWindowsContext::QWindowsContext() : const QByteArray bv = qgetenv("QT_QPA_VERBOSE"); if (!bv.isEmpty()) QLoggingCategory::setFilterRules(QString::fromLocal8Bit(bv)); -#if QT_CONFIG(tabletevent) - d->m_tabletSupport.reset(QWindowsTabletSupport::create()); - qCDebug(lcQpaTablet) << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); -#endif } QWindowsContext::~QWindowsContext() @@ -310,12 +329,17 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch) return true; - QTouchDevice *touchDevice = d->m_mouseHandler.ensureTouchDevice(); + QTouchDevice *touchDevice = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ? + d->m_pointerHandler.ensureTouchDevice() : d->m_mouseHandler.ensureTouchDevice(); if (!touchDevice) return false; - if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) - touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation); + if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) { + QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); + } else { + if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) + touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation); + } QWindowSystemInterface::registerTouchDevice(touchDevice); @@ -330,6 +354,33 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) return true; } +bool QWindowsContext::initTablet(unsigned integrationOptions) +{ + Q_UNUSED(integrationOptions); +#if QT_CONFIG(tabletevent) + d->m_tabletSupport.reset(QWindowsTabletSupport::create()); + return true; +#else + return false; +#endif +} + +bool QWindowsContext::initPointer(unsigned integrationOptions) +{ + if (integrationOptions & QWindowsIntegration::DontUseWMPointer) + return false; + + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) + return false; + + if (!QWindowsContext::user32dll.supportsPointerApi()) + return false; + + QWindowsContext::user32dll.enableMouseInPointer(TRUE); + d->m_systemInfo |= QWindowsContext::SI_SupportsPointer; + return true; +} + void QWindowsContext::setTabletAbsoluteRange(int a) { #if QT_CONFIG(tabletevent) @@ -340,6 +391,11 @@ void QWindowsContext::setTabletAbsoluteRange(int a) #endif } +void QWindowsContext::setDetectAltGrModifier(bool a) +{ + d->m_keyMapper.setDetectAltGrModifier(a); +} + int QWindowsContext::processDpiAwareness() { int result; @@ -548,7 +604,7 @@ void QWindowsContext::unregisterWindowClasses() { const HINSTANCE appInstance = static_cast<HINSTANCE>(GetModuleHandle(0)); - foreach (const QString &name, d->m_registeredWindowClassNames) { + for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) { if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose) qErrnoWarning("UnregisterClass failed for '%s'", qPrintable(name)); } @@ -632,12 +688,16 @@ QWindow *QWindowsContext::findWindow(HWND hwnd) const QWindow *QWindowsContext::windowUnderMouse() const { - return d->m_mouseHandler.windowUnderMouse(); + return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ? + d->m_pointerHandler.windowUnderMouse() : d->m_mouseHandler.windowUnderMouse(); } void QWindowsContext::clearWindowUnderMouse() { - d->m_mouseHandler.clearWindowUnderMouse(); + if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) + d->m_pointerHandler.clearWindowUnderMouse(); + else + d->m_mouseHandler.clearWindowUnderMouse(); } /*! @@ -696,6 +756,37 @@ QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent, return result; } +bool QWindowsContext::isSessionLocked() +{ + bool result = false; + const DWORD sessionId = WTSGetActiveConsoleSessionId(); + if (sessionId != 0xFFFFFFFF) { + LPTSTR buffer = nullptr; + DWORD size = 0; +#if !defined(Q_CC_MINGW) + if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId, + WTSSessionInfoEx, &buffer, &size) == TRUE + && size > 0) { + const WTSINFOEXW *info = reinterpret_cast<WTSINFOEXW *>(buffer); + result = info->Level == 1 && info->Data.WTSInfoExLevel1.SessionFlags == WTS_SESSIONSTATE_LOCK; + WTSFreeMemory(buffer); + } +#else // MinGW as of 7.3 does not have WTSINFOEXW in wtsapi32.h + // Retrieve the flags which are at offset 16 due to padding for 32/64bit alike. + if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId, + WTS_INFO_CLASS(25), &buffer, &size) == TRUE + && size >= 20) { + const DWORD *p = reinterpret_cast<DWORD *>(buffer); + const DWORD level = *p; + const DWORD sessionFlags = *(p + 4); + result = level == 1 && sessionFlags == 1; + WTSFreeMemory(buffer); + } +#endif // Q_CC_MINGW + } + return result; +} + QWindowsMimeConverter &QWindowsContext::mimeConverter() const { return d->m_mimeConverter; @@ -826,6 +917,45 @@ QByteArray QWindowsContext::comErrorString(HRESULT hr) return result; } +bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out, + unsigned dpi) +{ + const BOOL result = QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0 + ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi) + : SystemParametersInfo(action, param, out, 0); + return result == TRUE; +} + +bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out, + const QPlatformScreen *screen) +{ + return systemParametersInfo(action, param, out, screen ? screen->logicalDpi().first : 0); +} + +bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out, + const QPlatformWindow *win) +{ + return systemParametersInfoForScreen(action, param, out, win ? win->screen() : nullptr); +} + +bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi) +{ + memset(ncm, 0, sizeof(NONCLIENTMETRICS)); + ncm->cbSize = sizeof(NONCLIENTMETRICS); + return systemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, dpi); +} + +bool QWindowsContext::nonClientMetricsForScreen(NONCLIENTMETRICS *ncm, + const QPlatformScreen *screen) +{ + return nonClientMetrics(ncm, screen ? screen->logicalDpi().first : 0); +} + +bool QWindowsContext::nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win) +{ + return nonClientMetricsForScreen(ncm, win ? win->screen() : nullptr); +} + static inline QWindowsInputContext *windowsInputContext() { return qobject_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); @@ -870,6 +1000,7 @@ static inline bool isInputMessage(UINT m) case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: + case WM_INPUT: case WM_TOUCH: case WM_MOUSEHOVER: case WM_MOUSELEAVE: @@ -957,7 +1088,9 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, switch (et) { case QtWindows::GestureEvent: - return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result); + if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer)) + return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result); + break; case QtWindows::InputMethodOpenCandidateWindowEvent: case QtWindows::InputMethodCloseCandidateWindowEvent: // TODO: Release/regrab mouse if a popup has mouse grab. @@ -974,7 +1107,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::UnknownEvent: return false; case QtWindows::AccessibleObjectFromWindowRequest: -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) return QWindowsUiaAccessibility::handleWmGetObject(hwnd, wParam, lParam, result); #else return false; @@ -1083,18 +1216,25 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::ExposeEvent: return platformWindow->handleWmPaint(hwnd, message, wParam, lParam); case QtWindows::NonClientMouseEvent: - if (platformWindow->frameStrutEventsEnabled()) + if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); break; + case QtWindows::NonClientPointerEvent: + if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) + return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result); + break; case QtWindows::EnterSizeMoveEvent: platformWindow->setFlag(QWindowsWindow::ResizeMoveActive); return true; case QtWindows::ExitSizeMoveEvent: platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive); platformWindow->checkForScreenChanged(); + handleExitSizeMove(platformWindow->window()); return true; case QtWindows::ScrollEvent: - return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result); + if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer)) + return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result); + break; case QtWindows::MouseWheelEvent: case QtWindows::MouseEvent: case QtWindows::LeaveEvent: @@ -1104,10 +1244,20 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, window = window->parent(); if (!window) return false; - return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result); + if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer)) + return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result); + else + return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result); } + break; case QtWindows::TouchEvent: - return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result); + if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer)) + return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result); + 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); @@ -1150,6 +1300,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, } break; case QtWindows::MouseActivateWindowEvent: + case QtWindows::PointerActivateWindowEvent: if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) { *result = LRESULT(MA_NOACTIVATE); return true; @@ -1294,6 +1445,37 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } #endif +void QWindowsContext::handleExitSizeMove(QWindow *window) +{ + // Windows can be moved/resized by: + // 1) User moving a window by dragging the title bar: Causes a sequence + // of WM_NCLBUTTONDOWN, WM_NCMOUSEMOVE but no WM_NCLBUTTONUP, + // leaving the left mouse button 'pressed' + // 2) User choosing Resize/Move from System menu and using mouse/cursor keys: + // No mouse events are received + // 3) Programmatically via QSizeGrip calling QPlatformWindow::startSystemResize/Move(): + // 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 appButtons = QGuiApplication::mouseButtons(); + if (currentButtons == appButtons) + return; + const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + const QPoint globalPos = QWindowsCursor::mousePosition(); + const QPlatformWindow *platWin = window->handle(); + const QPoint localPos = platWin->mapFromGlobal(globalPos); + const QEvent::Type type = platWin->geometry().contains(globalPos) + ? QEvent::MouseButtonRelease : QEvent::NonClientAreaMouseButtonRelease; + for (Qt::MouseButton button : {Qt::LeftButton, Qt::RightButton, Qt::MiddleButton}) { + if (appButtons.testFlag(button) && !currentButtons.testFlag(button)) { + QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, + currentButtons, button, type, + keyboardModifiers); + } + } +} + bool QWindowsContext::asyncExpose() const { return d->m_asyncExpose; @@ -1306,7 +1488,8 @@ void QWindowsContext::setAsyncExpose(bool value) QTouchDevice *QWindowsContext::touchDevice() const { - return d->m_mouseHandler.touchDevice(); + return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ? + d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice(); } static DWORD readDwordRegistrySetting(const wchar_t *regKey, const wchar_t *subKey, DWORD defaultValue) @@ -1399,7 +1582,7 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0)); if (margins.left() >= 0) { if (platformWindow) { - platformWindow->setFrameMargins(margins); + platformWindow->setFullFrameMargins(margins); } else { const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext(); if (!ctx.isNull()) |