Add Windows Pointer Input Messages support
Replaces the handling of tablet/touchscreen/touchpad/mouse input with a unified implementation based on the Windows Pointer Input Messages added to Windows 8. The legacy implementation is still used for Windows 7. Task-number: QTBUG-60437 Change-Id: I0a0f48ee9d5365f84ba528aa04c6ab1fe4253c50 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
parent
dffbf4a7f6
commit
20d6dac63c
@ -184,7 +184,29 @@ messageDebugEntries[] = {
|
||||
{WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD", true},
|
||||
{WM_THEMECHANGED, "WM_THEMECHANGED", true},
|
||||
{0x90, "WM_UAHDESTROYWINDOW", true},
|
||||
{0x272, "WM_UNREGISTER_WINDOW_SERVICES", true}
|
||||
{0x272, "WM_UNREGISTER_WINDOW_SERVICES", true},
|
||||
#ifdef WM_POINTERUPDATE
|
||||
{WM_POINTERDEVICECHANGE, "WM_POINTERDEVICECHANGE", true},
|
||||
{WM_POINTERDEVICEINRANGE, "WM_POINTERDEVICEINRANGE", true},
|
||||
{WM_POINTERDEVICEOUTOFRANGE, "WM_POINTERDEVICEOUTOFRANGE", true},
|
||||
{WM_NCPOINTERUPDATE, "WM_NCPOINTERUPDATE", true},
|
||||
{WM_NCPOINTERDOWN, "WM_NCPOINTERDOWN", true},
|
||||
{WM_NCPOINTERUP, "WM_NCPOINTERUP", true},
|
||||
{WM_POINTERUPDATE, "WM_POINTERUPDATE", true},
|
||||
{WM_POINTERDOWN, "WM_POINTERDOWN", true},
|
||||
{WM_POINTERUP, "WM_POINTERUP", true},
|
||||
{WM_POINTERENTER, "WM_POINTERENTER", true},
|
||||
{WM_POINTERLEAVE, "WM_POINTERLEAVE", true},
|
||||
{WM_POINTERACTIVATE, "WM_POINTERACTIVATE", true},
|
||||
{WM_POINTERCAPTURECHANGED, "WM_POINTERCAPTURECHANGED", true},
|
||||
{WM_TOUCHHITTESTING, "WM_TOUCHHITTESTING", true},
|
||||
{WM_POINTERWHEEL, "WM_POINTERWHEEL", true},
|
||||
{WM_POINTERHWHEEL, "WM_POINTERHWHEEL", true},
|
||||
{DM_POINTERHITTEST, "DM_POINTERHITTEST", true},
|
||||
{WM_POINTERROUTEDTO, "WM_POINTERROUTEDTO", true},
|
||||
{WM_POINTERROUTEDAWAY, "WM_POINTERROUTEDAWAY", true},
|
||||
{WM_POINTERROUTEDRELEASED, "WM_POINTERROUTEDRELEASED", true}
|
||||
#endif // WM_POINTERUPDATE
|
||||
};
|
||||
|
||||
static inline const MessageDebugEntry *messageDebugEntry(UINT msg)
|
||||
|
@ -60,6 +60,21 @@
|
||||
# define WM_DPICHANGED 0x02E0
|
||||
#endif
|
||||
|
||||
// WM_POINTER support from Windows 8 onwards (WINVER >= 0x0602)
|
||||
#ifndef WM_POINTERUPDATE
|
||||
# define WM_NCPOINTERUPDATE 0x0241
|
||||
# define WM_NCPOINTERDOWN 0x0242
|
||||
# define WM_NCPOINTERUP 0x0243
|
||||
# define WM_POINTERUPDATE 0x0245
|
||||
# define WM_POINTERDOWN 0x0246
|
||||
# define WM_POINTERUP 0x0247
|
||||
# define WM_POINTERENTER 0x0249
|
||||
# define WM_POINTERLEAVE 0x024A
|
||||
# define WM_POINTERACTIVATE 0x024B
|
||||
# define WM_POINTERWHEEL 0x024E
|
||||
# define WM_POINTERHWHEEL 0x024F
|
||||
#endif // WM_POINTERUPDATE
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWindows
|
||||
@ -78,6 +93,7 @@ enum
|
||||
ApplicationEventFlag = 0x1000000,
|
||||
ThemingEventFlag = 0x2000000,
|
||||
GenericEventFlag = 0x4000000, // Misc
|
||||
PointerEventFlag = 0x8000000,
|
||||
};
|
||||
|
||||
enum WindowsEventType // Simplify event types
|
||||
@ -103,13 +119,16 @@ enum WindowsEventType // Simplify event types
|
||||
DpiChangedEvent = WindowEventFlag + 21,
|
||||
EnterSizeMoveEvent = WindowEventFlag + 22,
|
||||
ExitSizeMoveEvent = WindowEventFlag + 23,
|
||||
PointerActivateWindowEvent = WindowEventFlag + 24,
|
||||
MouseEvent = MouseEventFlag + 1,
|
||||
MouseWheelEvent = MouseEventFlag + 2,
|
||||
CursorEvent = MouseEventFlag + 3,
|
||||
TouchEvent = TouchEventFlag + 1,
|
||||
PointerEvent = PointerEventFlag + 1,
|
||||
NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1,
|
||||
NonClientHitTest = NonClientEventFlag + 2,
|
||||
NonClientCreate = NonClientEventFlag + 3,
|
||||
NonClientPointerEvent = NonClientEventFlag + PointerEventFlag + 4,
|
||||
KeyEvent = KeyEventFlag + 1,
|
||||
KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
|
||||
KeyboardLayoutChangeEvent = KeyEventFlag + 2,
|
||||
@ -167,6 +186,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
|
||||
QtWindows::ActivateApplicationEvent : QtWindows::DeactivateApplicationEvent;
|
||||
case WM_MOUSEACTIVATE:
|
||||
return QtWindows::MouseActivateWindowEvent;
|
||||
case WM_POINTERACTIVATE:
|
||||
return QtWindows::PointerActivateWindowEvent;
|
||||
case WM_ACTIVATE:
|
||||
return LOWORD(wParamIn) == WA_INACTIVE ?
|
||||
QtWindows::DeactivateWindowEvent : QtWindows::ActivateWindowEvent;
|
||||
@ -297,6 +318,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
|
||||
if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST)
|
||||
|| (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK))
|
||||
return QtWindows::MouseEvent;
|
||||
if (message >= WM_NCPOINTERUPDATE && message <= WM_NCPOINTERUP)
|
||||
return QtWindows::NonClientPointerEvent;
|
||||
if (message >= WM_POINTERUPDATE && message <= WM_POINTERHWHEEL)
|
||||
return QtWindows::PointerEvent;
|
||||
return QtWindows::UnknownEvent;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -193,6 +194,15 @@ 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");
|
||||
getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo");
|
||||
getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo");
|
||||
getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo");
|
||||
}
|
||||
|
||||
if (QOperatingSystemVersion::current()
|
||||
>= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) {
|
||||
enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling");
|
||||
@ -201,6 +211,11 @@ void QWindowsUser32DLL::init()
|
||||
}
|
||||
}
|
||||
|
||||
bool QWindowsUser32DLL::supportsPointerApi()
|
||||
{
|
||||
return enableMouseInPointer && getPointerType && getPointerInfo && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo;
|
||||
}
|
||||
|
||||
void QWindowsShcoreDLL::init()
|
||||
{
|
||||
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
|
||||
@ -238,6 +253,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;
|
||||
@ -255,7 +271,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);
|
||||
@ -280,10 +296,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()
|
||||
@ -309,7 +321,8 @@ 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;
|
||||
|
||||
@ -329,6 +342,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)
|
||||
@ -631,12 +671,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();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -957,7 +1001,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.
|
||||
@ -1083,19 +1129,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();
|
||||
QWindowsMouseHandler::handleExitSizeMove(platformWindow->window());
|
||||
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:
|
||||
@ -1105,10 +1157,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);
|
||||
@ -1151,6 +1213,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;
|
||||
@ -1295,6 +1358,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;
|
||||
@ -1307,7 +1401,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)
|
||||
|
@ -85,7 +85,14 @@ class QTouchDevice;
|
||||
struct QWindowsUser32DLL
|
||||
{
|
||||
inline void init();
|
||||
inline bool supportsPointerApi();
|
||||
|
||||
typedef BOOL (WINAPI *EnableMouseInPointer)(BOOL);
|
||||
typedef BOOL (WINAPI *GetPointerType)(UINT32, PVOID);
|
||||
typedef BOOL (WINAPI *GetPointerInfo)(UINT32, PVOID);
|
||||
typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID);
|
||||
typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID);
|
||||
typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID);
|
||||
typedef BOOL (WINAPI *SetProcessDPIAware)();
|
||||
typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND);
|
||||
typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND);
|
||||
@ -95,6 +102,14 @@ struct QWindowsUser32DLL
|
||||
typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND);
|
||||
typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int);
|
||||
|
||||
// Windows pointer functions (Windows 8 or later).
|
||||
EnableMouseInPointer enableMouseInPointer = nullptr;
|
||||
GetPointerType getPointerType = nullptr;
|
||||
GetPointerInfo getPointerInfo = nullptr;
|
||||
GetPointerTouchInfo getPointerTouchInfo = nullptr;
|
||||
GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr;
|
||||
GetPointerPenInfo getPointerPenInfo = nullptr;
|
||||
|
||||
// Windows Vista onwards
|
||||
SetProcessDPIAware setProcessDPIAware = nullptr;
|
||||
|
||||
@ -134,7 +149,8 @@ public:
|
||||
enum SystemInfoFlags
|
||||
{
|
||||
SI_RTL_Extensions = 0x1,
|
||||
SI_SupportsTouch = 0x2
|
||||
SI_SupportsTouch = 0x2,
|
||||
SI_SupportsPointer = 0x4,
|
||||
};
|
||||
|
||||
// Verbose flag set by environment variable QT_QPA_VERBOSE
|
||||
@ -145,6 +161,8 @@ public:
|
||||
|
||||
bool initTouch();
|
||||
bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only.
|
||||
bool initTablet(unsigned integrationOptions);
|
||||
bool initPointer(unsigned integrationOptions);
|
||||
|
||||
int defaultDPI() const;
|
||||
|
||||
@ -220,6 +238,7 @@ private:
|
||||
#ifndef QT_NO_CONTEXTMENU
|
||||
bool handleContextMenuEvent(QWindow *window, const MSG &msg);
|
||||
#endif
|
||||
void handleExitSizeMove(QWindow *window);
|
||||
void unregisterWindowClasses();
|
||||
|
||||
QScopedPointer<QWindowsContextPrivate> d;
|
||||
|
@ -212,6 +212,8 @@ static inline unsigned parseOptions(const QStringList ¶mList,
|
||||
options |= QWindowsIntegration::AlwaysUseNativeMenus;
|
||||
} else if (param == QLatin1String("menus=none")) {
|
||||
options |= QWindowsIntegration::NoNativeMenus;
|
||||
} else if (param == QLatin1String("nowmpointer")) {
|
||||
options |= QWindowsIntegration::DontUseWMPointer;
|
||||
} else {
|
||||
qWarning() << "Unknown option" << param;
|
||||
}
|
||||
@ -230,8 +232,13 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL
|
||||
QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware;
|
||||
m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness);
|
||||
QWindowsFontDatabase::setFontOptions(m_options);
|
||||
if (tabletAbsoluteRange >= 0)
|
||||
m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
|
||||
|
||||
if (!m_context.initPointer(m_options)) {
|
||||
m_context.initTablet(m_options);
|
||||
if (tabletAbsoluteRange >= 0)
|
||||
m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
|
||||
}
|
||||
|
||||
if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
|
||||
if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
|
||||
m_context.setProcessDpiAwareness(dpiAwareness);
|
||||
|
@ -66,7 +66,8 @@ public:
|
||||
DontUseDirectWriteFonts = QWindowsFontDatabase::DontUseDirectWriteFonts,
|
||||
DontUseColorFonts = QWindowsFontDatabase::DontUseColorFonts,
|
||||
AlwaysUseNativeMenus = 0x100,
|
||||
NoNativeMenus = 0x200
|
||||
NoNativeMenus = 0x200,
|
||||
DontUseWMPointer = 0x400,
|
||||
};
|
||||
|
||||
explicit QWindowsIntegration(const QStringList ¶mList);
|
||||
|
@ -119,20 +119,16 @@ static inline void compressMouseMove(MSG *msg)
|
||||
|
||||
static inline QTouchDevice *createTouchDevice()
|
||||
{
|
||||
enum { QT_SM_TABLETPC = 86, QT_SM_DIGITIZER = 94, QT_SM_MAXIMUMTOUCHES = 95,
|
||||
QT_NID_INTEGRATED_TOUCH = 0x1, QT_NID_EXTERNAL_TOUCH = 0x02,
|
||||
QT_NID_MULTI_INPUT = 0x40, QT_NID_READY = 0x80 };
|
||||
|
||||
const int digitizers = GetSystemMetrics(QT_SM_DIGITIZER);
|
||||
if (!(digitizers & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH)))
|
||||
const int digitizers = GetSystemMetrics(SM_DIGITIZER);
|
||||
if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
|
||||
return 0;
|
||||
const int tabletPc = GetSystemMetrics(QT_SM_TABLETPC);
|
||||
const int maxTouchPoints = GetSystemMetrics(QT_SM_MAXIMUMTOUCHES);
|
||||
qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~QT_NID_READY)
|
||||
<< "Ready:" << (digitizers & QT_NID_READY) << dec << noshowbase
|
||||
const int tabletPc = GetSystemMetrics(SM_TABLETPC);
|
||||
const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
|
||||
qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY)
|
||||
<< "Ready:" << (digitizers & NID_READY) << dec << noshowbase
|
||||
<< "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
|
||||
QTouchDevice *result = new QTouchDevice;
|
||||
result->setType(digitizers & QT_NID_INTEGRATED_TOUCH
|
||||
result->setType(digitizers & NID_INTEGRATED_TOUCH
|
||||
? QTouchDevice::TouchScreen : QTouchDevice::TouchPad);
|
||||
QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition;
|
||||
if (result->type() == QTouchDevice::TouchPad)
|
||||
@ -178,37 +174,6 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
|
||||
return result;
|
||||
}
|
||||
|
||||
void QWindowsMouseHandler::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QPoint lastMouseMovePos;
|
||||
|
||||
namespace {
|
||||
|
@ -80,8 +80,6 @@ public:
|
||||
QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); }
|
||||
void clearWindowUnderMouse() { m_windowUnderMouse = 0; }
|
||||
|
||||
static void handleExitSizeMove(QWindow *window);
|
||||
|
||||
private:
|
||||
inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd,
|
||||
MSG msg, LRESULT *result);
|
||||
|
573
src/plugins/platforms/windows/qwindowspointerhandler.cpp
Normal file
573
src/plugins/platforms/windows/qwindowspointerhandler.cpp
Normal file
@ -0,0 +1,573 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(WINVER) && WINVER < 0x0603
|
||||
# undef WINVER
|
||||
#endif
|
||||
#if !defined(WINVER)
|
||||
# define WINVER 0x0603 // Enable pointer functions for MinGW
|
||||
#endif
|
||||
|
||||
#include "qwindowspointerhandler.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/qtouchdevice.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qoperatingsystemversion.h>
|
||||
|
||||
#include <windowsx.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
enum {
|
||||
QT_PT_POINTER = 1,
|
||||
QT_PT_TOUCH = 2,
|
||||
QT_PT_PEN = 3,
|
||||
QT_PT_MOUSE = 4,
|
||||
QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD
|
||||
};
|
||||
|
||||
bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
|
||||
{
|
||||
*result = 0;
|
||||
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
|
||||
|
||||
POINTER_INPUT_TYPE pointerType;
|
||||
if (!QWindowsContext::user32dll.getPointerType(pointerId, &pointerType)) {
|
||||
qWarning() << "GetPointerType() failed:" << qt_error_string();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (pointerType) {
|
||||
case QT_PT_POINTER:
|
||||
case QT_PT_MOUSE:
|
||||
case QT_PT_TOUCHPAD: {
|
||||
POINTER_INFO pointerInfo;
|
||||
if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) {
|
||||
qWarning() << "GetPointerInfo() failed:" << qt_error_string();
|
||||
return false;
|
||||
}
|
||||
return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo);
|
||||
}
|
||||
case QT_PT_TOUCH: {
|
||||
quint32 pointerCount = 0;
|
||||
if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) {
|
||||
qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
|
||||
return false;
|
||||
}
|
||||
QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
|
||||
if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
|
||||
qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
|
||||
return false;
|
||||
}
|
||||
return translateTouchEvent(window, hwnd, et, msg, touchInfo.data(), pointerCount);
|
||||
}
|
||||
case QT_PT_PEN: {
|
||||
POINTER_PEN_INFO penInfo;
|
||||
if (!QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo)) {
|
||||
qWarning() << "GetPointerPenInfo() failed:" << qt_error_string();
|
||||
return false;
|
||||
}
|
||||
return translatePenEvent(window, hwnd, et, msg, &penInfo);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QPoint globalPos, QEvent::Type *eventType, Qt::MouseButton *mouseButton)
|
||||
{
|
||||
static const QHash<POINTER_BUTTON_CHANGE_TYPE, Qt::MouseButton> buttonMapping {
|
||||
{POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton},
|
||||
{POINTER_CHANGE_FIRSTBUTTON_UP, Qt::LeftButton},
|
||||
{POINTER_CHANGE_SECONDBUTTON_DOWN, Qt::RightButton},
|
||||
{POINTER_CHANGE_SECONDBUTTON_UP, Qt::RightButton},
|
||||
{POINTER_CHANGE_THIRDBUTTON_DOWN, Qt::MiddleButton},
|
||||
{POINTER_CHANGE_THIRDBUTTON_UP, Qt::MiddleButton},
|
||||
{POINTER_CHANGE_FOURTHBUTTON_DOWN, Qt::XButton1},
|
||||
{POINTER_CHANGE_FOURTHBUTTON_UP, Qt::XButton1},
|
||||
{POINTER_CHANGE_FIFTHBUTTON_DOWN, Qt::XButton2},
|
||||
{POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2},
|
||||
};
|
||||
|
||||
static const QHash<UINT, QEvent::Type> eventMapping {
|
||||
{WM_POINTERUPDATE, QEvent::MouseMove},
|
||||
{WM_POINTERDOWN, QEvent::MouseButtonPress},
|
||||
{WM_POINTERUP, QEvent::MouseButtonRelease},
|
||||
{WM_NCPOINTERUPDATE, QEvent::NonClientAreaMouseMove},
|
||||
{WM_NCPOINTERDOWN, QEvent::NonClientAreaMouseButtonPress},
|
||||
{WM_NCPOINTERUP, QEvent::NonClientAreaMouseButtonRelease},
|
||||
{WM_POINTERWHEEL, QEvent::Wheel},
|
||||
{WM_POINTERHWHEEL, QEvent::Wheel},
|
||||
};
|
||||
|
||||
if (!eventType || !mouseButton)
|
||||
return;
|
||||
|
||||
if (message == WM_POINTERDOWN || message == WM_POINTERUP || message == WM_NCPOINTERDOWN || message == WM_NCPOINTERUP)
|
||||
*mouseButton = buttonMapping.value(changeType, Qt::NoButton);
|
||||
else
|
||||
*mouseButton = Qt::NoButton;
|
||||
|
||||
*eventType = eventMapping.value(message, QEvent::None);
|
||||
|
||||
// Pointer messages lack a double click indicator. Check if this is the case here.
|
||||
if (message == WM_POINTERDOWN) {
|
||||
static LONG lastTime = 0;
|
||||
static Qt::MouseButton lastButton = Qt::NoButton;
|
||||
static QPoint lastPos;
|
||||
LONG messageTime = GetMessageTime();
|
||||
if (*mouseButton == lastButton
|
||||
&& messageTime - lastTime < (LONG)GetDoubleClickTime()
|
||||
&& qAbs(globalPos.x() - lastPos.x()) < GetSystemMetrics(SM_CXDOUBLECLK)
|
||||
&& qAbs(globalPos.y() - lastPos.y()) < GetSystemMetrics(SM_CYDOUBLECLK)) {
|
||||
*eventType = QEvent::MouseButtonDblClick;
|
||||
}
|
||||
lastTime = messageTime;
|
||||
lastButton = *mouseButton;
|
||||
lastPos = globalPos;
|
||||
}
|
||||
}
|
||||
|
||||
static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos)
|
||||
{
|
||||
QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
|
||||
|
||||
while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput)
|
||||
currentWindowUnderPointer = currentWindowUnderPointer->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 (!currentWindowUnderPointer) {
|
||||
const QRect clientRect(QPoint(0, 0), window->size());
|
||||
if (clientRect.contains(globalPos))
|
||||
currentWindowUnderPointer = window;
|
||||
}
|
||||
return currentWindowUnderPointer;
|
||||
}
|
||||
|
||||
static bool trackLeave(HWND hwnd)
|
||||
{
|
||||
TRACKMOUSEEVENT tme;
|
||||
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||
tme.dwFlags = TME_LEAVE;
|
||||
tme.hwndTrack = hwnd;
|
||||
tme.dwHoverTime = HOVER_DEFAULT;
|
||||
return TrackMouseEvent(&tme);
|
||||
}
|
||||
|
||||
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 QTouchDevice *createTouchDevice()
|
||||
{
|
||||
const int digitizers = GetSystemMetrics(SM_DIGITIZER);
|
||||
if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
|
||||
return nullptr;
|
||||
const int tabletPc = GetSystemMetrics(SM_TABLETPC);
|
||||
const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
|
||||
qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY)
|
||||
<< "Ready:" << (digitizers & NID_READY) << dec << noshowbase
|
||||
<< "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
|
||||
QTouchDevice *result = new QTouchDevice;
|
||||
result->setType(digitizers & NID_INTEGRATED_TOUCH
|
||||
? QTouchDevice::TouchScreen : QTouchDevice::TouchPad);
|
||||
QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition;
|
||||
if (result->type() == QTouchDevice::TouchPad)
|
||||
capabilities |= QTouchDevice::MouseEmulation;
|
||||
result->setCapabilities(capabilities);
|
||||
result->setMaximumTouchPoints(maxTouchPoints);
|
||||
return result;
|
||||
}
|
||||
|
||||
QTouchDevice *QWindowsPointerHandler::ensureTouchDevice()
|
||||
{
|
||||
if (!m_touchDevice)
|
||||
m_touchDevice.reset(createTouchDevice());
|
||||
return m_touchDevice.data();
|
||||
}
|
||||
|
||||
Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons()
|
||||
{
|
||||
Qt::MouseButtons result = 0;
|
||||
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::MidButton;
|
||||
if (GetAsyncKeyState(VK_XBUTTON1) < 0)
|
||||
result |= Qt::XButton1;
|
||||
if (GetAsyncKeyState(VK_XBUTTON2) < 0)
|
||||
result |= Qt::XButton2;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd,
|
||||
QtWindows::WindowsEventType et,
|
||||
MSG msg, PVOID vPointerInfo)
|
||||
{
|
||||
POINTER_INFO *pointerInfo = static_cast<POINTER_INFO *>(vPointerInfo);
|
||||
const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y);
|
||||
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
|
||||
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
|
||||
const Qt::MouseButtons mouseButtons = queryMouseButtons();
|
||||
|
||||
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
|
||||
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
|
||||
|
||||
switch (msg.message) {
|
||||
case WM_NCPOINTERDOWN:
|
||||
case WM_NCPOINTERUP:
|
||||
case WM_NCPOINTERUPDATE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE: {
|
||||
|
||||
QEvent::Type eventType;
|
||||
Qt::MouseButton button;
|
||||
getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, globalPos, &eventType, &button);
|
||||
|
||||
if (et & QtWindows::NonClientEventFlag) {
|
||||
QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
|
||||
keyModifiers, Qt::MouseEventNotSynthesized);
|
||||
return false; // To allow window dragging, etc.
|
||||
} else {
|
||||
if (currentWindowUnderPointer != m_windowUnderPointer) {
|
||||
if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
|
||||
QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
|
||||
m_currentWindow = nullptr;
|
||||
}
|
||||
|
||||
if (currentWindowUnderPointer) {
|
||||
if (currentWindowUnderPointer != m_currentWindow) {
|
||||
QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, localPos, globalPos);
|
||||
m_currentWindow = currentWindowUnderPointer;
|
||||
if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer))
|
||||
wumPlatformWindow->applyCursor();
|
||||
trackLeave(hwnd);
|
||||
}
|
||||
} else {
|
||||
platformWindow->applyCursor();
|
||||
}
|
||||
m_windowUnderPointer = currentWindowUnderPointer;
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
|
||||
keyModifiers, Qt::MouseEventNotSynthesized);
|
||||
|
||||
// The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND
|
||||
// has go to through DefWindowProc() for resizing to work, so we return false here,
|
||||
// unless the mouse is captured, as it would mess with menu processing.
|
||||
return msg.message != WM_POINTERDOWN || GetCapture();
|
||||
}
|
||||
}
|
||||
case WM_POINTERHWHEEL:
|
||||
case WM_POINTERWHEEL: {
|
||||
|
||||
int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
|
||||
|
||||
// Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL
|
||||
if (msg.message == WM_POINTERHWHEEL)
|
||||
delta = -delta;
|
||||
|
||||
const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ?
|
||||
QPoint(delta, 0) : QPoint(0, delta);
|
||||
|
||||
if (isValidWheelReceiver(window))
|
||||
QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
|
||||
return true;
|
||||
}
|
||||
case WM_POINTERLEAVE:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
QtWindows::WindowsEventType et,
|
||||
MSG msg, PVOID vTouchInfo, quint32 count)
|
||||
{
|
||||
Q_UNUSED(hwnd);
|
||||
Q_UNUSED(et);
|
||||
|
||||
if (et & QtWindows::NonClientEventFlag)
|
||||
return false; // Let DefWindowProc() handle Non Client messages.
|
||||
|
||||
if (count < 1)
|
||||
return false;
|
||||
|
||||
const QScreen *screen = window->screen();
|
||||
if (!screen)
|
||||
screen = QGuiApplication::primaryScreen();
|
||||
if (!screen)
|
||||
return false;
|
||||
|
||||
POINTER_TOUCH_INFO *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
|
||||
|
||||
const QRect screenGeometry = screen->geometry();
|
||||
|
||||
QList<QWindowSystemInterface::TouchPoint> touchPoints;
|
||||
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
|
||||
QWindowSystemInterface::TouchPoint touchPoint;
|
||||
touchPoint.id = touchInfo[i].pointerInfo.pointerId;
|
||||
touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
|
||||
touchInfo[i].pressure / 1024.0 : 1.0;
|
||||
if (m_lastTouchPositions.contains(touchPoint.id))
|
||||
touchPoint.normalPosition = m_lastTouchPositions.value(touchPoint.id);
|
||||
|
||||
const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
|
||||
touchInfo[i].pointerInfo.ptPixelLocation.y);
|
||||
|
||||
if (touchInfo[i].touchMask & TOUCH_MASK_CONTACTAREA)
|
||||
touchPoint.area.setSize(QSizeF(touchInfo[i].rcContact.right - touchInfo[i].rcContact.left,
|
||||
touchInfo[i].rcContact.bottom - touchInfo[i].rcContact.top));
|
||||
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 (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
|
||||
touchPoint.state = Qt::TouchPointPressed;
|
||||
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
|
||||
} else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
|
||||
touchPoint.state = Qt::TouchPointReleased;
|
||||
m_lastTouchPositions.remove(touchPoint.id);
|
||||
} else {
|
||||
touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved;
|
||||
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
|
||||
}
|
||||
touchPoints.append(touchPoint);
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints,
|
||||
QWindowsKeyMapper::queryKeyboardModifiers());
|
||||
|
||||
if (!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) {
|
||||
|
||||
const QPoint globalPos = QPoint(touchInfo->pointerInfo.ptPixelLocation.x, touchInfo->pointerInfo.ptPixelLocation.y);
|
||||
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
|
||||
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
|
||||
const Qt::MouseButtons mouseButtons = queryMouseButtons();
|
||||
|
||||
QEvent::Type eventType;
|
||||
Qt::MouseButton button;
|
||||
getMouseEventInfo(msg.message, touchInfo->pointerInfo.ButtonChangeType, globalPos, &eventType, &button);
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
|
||||
keyModifiers, Qt::MouseEventSynthesizedByQt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et,
|
||||
MSG msg, PVOID vPenInfo)
|
||||
{
|
||||
if (et & QtWindows::NonClientEventFlag)
|
||||
return false; // Let DefWindowProc() handle Non Client messages.
|
||||
|
||||
POINTER_PEN_INFO *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo);
|
||||
const quint32 pointerId = penInfo->pointerInfo.pointerId;
|
||||
const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
|
||||
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
|
||||
const qreal pressure = (penInfo->penMask & PEN_MASK_PRESSURE) ? qreal(penInfo->pressure) / 1024.0 : 0.5;
|
||||
const qreal rotation = (penInfo->penMask & PEN_MASK_ROTATION) ? qreal(penInfo->rotation) : 0.0;
|
||||
const qreal tangentialPressure = 0.0;
|
||||
const int xTilt = (penInfo->penMask & PEN_MASK_TILT_X) ? penInfo->tiltX : 0;
|
||||
const int yTilt = (penInfo->penMask & PEN_MASK_TILT_Y) ? penInfo->tiltY : 0;
|
||||
const int z = 0;
|
||||
|
||||
const QTabletEvent::TabletDevice device = QTabletEvent::Stylus;
|
||||
QTabletEvent::PointerType type;
|
||||
Qt::MouseButtons mouseButtons;
|
||||
|
||||
const bool pointerInContact = IS_POINTER_INCONTACT_WPARAM(msg.wParam);
|
||||
if (pointerInContact)
|
||||
mouseButtons = Qt::LeftButton;
|
||||
|
||||
if (penInfo->penFlags & (PEN_FLAG_ERASER | PEN_FLAG_INVERTED)) {
|
||||
type = QTabletEvent::Eraser;
|
||||
} else {
|
||||
type = QTabletEvent::Pen;
|
||||
if (pointerInContact && penInfo->penFlags & PEN_FLAG_BARREL)
|
||||
mouseButtons = Qt::RightButton; // Either left or right, not both
|
||||
}
|
||||
|
||||
switch (msg.message) {
|
||||
case WM_POINTERENTER: {
|
||||
QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, pointerId);
|
||||
m_windowUnderPointer = window;
|
||||
// The local coordinates may fall outside the window.
|
||||
// Wait until the next update to send the enter event.
|
||||
m_needsEnterOnPointerUpdate = true;
|
||||
break;
|
||||
}
|
||||
case WM_POINTERLEAVE:
|
||||
if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
|
||||
QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
|
||||
m_windowUnderPointer = nullptr;
|
||||
m_currentWindow = nullptr;
|
||||
}
|
||||
QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, pointerId);
|
||||
break;
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE: {
|
||||
QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(pointerId).target; // Pass to window that grabbed it.
|
||||
if (!target && m_windowUnderPointer)
|
||||
target = m_windowUnderPointer;
|
||||
if (!target)
|
||||
target = window;
|
||||
|
||||
if (m_needsEnterOnPointerUpdate) {
|
||||
m_needsEnterOnPointerUpdate = false;
|
||||
if (window != m_currentWindow) {
|
||||
QWindowSystemInterface::handleEnterEvent(window, localPos, globalPos);
|
||||
m_currentWindow = window;
|
||||
if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(target))
|
||||
wumPlatformWindow->applyCursor();
|
||||
}
|
||||
}
|
||||
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
|
||||
|
||||
QWindowSystemInterface::handleTabletEvent(target, localPos, globalPos, device, type, mouseButtons,
|
||||
pressure, xTilt, yTilt, tangentialPressure, rotation, z,
|
||||
pointerId, keyModifiers);
|
||||
|
||||
QEvent::Type eventType;
|
||||
Qt::MouseButton button;
|
||||
getMouseEventInfo(msg.message, penInfo->pointerInfo.ButtonChangeType, globalPos, &eventType, &button);
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(target, localPos, globalPos, mouseButtons, button, eventType,
|
||||
keyModifiers, Qt::MouseEventSynthesizedByQt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SetCursorPos()/TrackMouseEvent() will generate old-style WM_MOUSE messages. Handle them here.
|
||||
bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
|
||||
{
|
||||
Q_UNUSED(et);
|
||||
|
||||
*result = 0;
|
||||
if (msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE)
|
||||
return false;
|
||||
|
||||
const QPoint localPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
const QPoint globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, localPos);
|
||||
|
||||
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
|
||||
|
||||
if (msg.message == WM_MOUSELEAVE) {
|
||||
if (window == m_currentWindow) {
|
||||
QWindowSystemInterface::handleLeaveEvent(window);
|
||||
m_windowUnderPointer = nullptr;
|
||||
m_currentWindow = nullptr;
|
||||
platformWindow->applyCursor();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.
|
||||
static QPoint lastMouseMovePos;
|
||||
const bool discardEvent = msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos);
|
||||
lastMouseMovePos = globalPos;
|
||||
|
||||
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
|
||||
|
||||
if (currentWindowUnderPointer != m_windowUnderPointer) {
|
||||
if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
|
||||
QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
|
||||
m_currentWindow = nullptr;
|
||||
}
|
||||
|
||||
if (currentWindowUnderPointer) {
|
||||
if (currentWindowUnderPointer != m_currentWindow) {
|
||||
QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, localPos, globalPos);
|
||||
m_currentWindow = currentWindowUnderPointer;
|
||||
if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer))
|
||||
wumPlatformWindow->applyCursor();
|
||||
trackLeave(hwnd);
|
||||
}
|
||||
} else {
|
||||
platformWindow->applyCursor();
|
||||
}
|
||||
m_windowUnderPointer = currentWindowUnderPointer;
|
||||
}
|
||||
|
||||
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
|
||||
const Qt::MouseButtons mouseButtons = queryMouseButtons();
|
||||
|
||||
if (!discardEvent)
|
||||
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::NoButton, QEvent::MouseMove,
|
||||
keyModifiers, Qt::MouseEventNotSynthesized);
|
||||
return false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
82
src/plugins/platforms/windows/qwindowspointerhandler.h
Normal file
82
src/plugins/platforms/windows/qwindowspointerhandler.h
Normal file
@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QWINDOWSPOINTERHANDLER_H
|
||||
#define QWINDOWSPOINTERHANDLER_H
|
||||
|
||||
#include "qtwindowsglobal.h"
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qhash.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindow;
|
||||
class QTouchDevice;
|
||||
|
||||
class QWindowsPointerHandler
|
||||
{
|
||||
Q_DISABLE_COPY(QWindowsPointerHandler)
|
||||
public:
|
||||
QWindowsPointerHandler() = default;
|
||||
bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result);
|
||||
bool translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result);
|
||||
QTouchDevice *touchDevice() const { return m_touchDevice.data(); }
|
||||
QTouchDevice *ensureTouchDevice();
|
||||
Qt::MouseButtons queryMouseButtons();
|
||||
QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); }
|
||||
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
|
||||
|
||||
private:
|
||||
bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo);
|
||||
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);
|
||||
|
||||
QScopedPointer<QTouchDevice> m_touchDevice;
|
||||
QHash<int, QPointF> m_lastTouchPositions;
|
||||
QPointer<QWindow> m_windowUnderPointer;
|
||||
QPointer<QWindow> m_currentWindow;
|
||||
bool m_needsEnterOnPointerUpdate = false;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWINDOWSPOINTERHANDLER_H
|
@ -18,6 +18,7 @@ SOURCES += \
|
||||
$$PWD/qwindowsscreen.cpp \
|
||||
$$PWD/qwindowskeymapper.cpp \
|
||||
$$PWD/qwindowsmousehandler.cpp \
|
||||
$$PWD/qwindowspointerhandler.cpp \
|
||||
$$PWD/qwindowsole.cpp \
|
||||
$$PWD/qwindowsdropdataobject.cpp \
|
||||
$$PWD/qwindowsmime.cpp \
|
||||
@ -40,6 +41,7 @@ HEADERS += \
|
||||
$$PWD/qwindowsscreen.h \
|
||||
$$PWD/qwindowskeymapper.h \
|
||||
$$PWD/qwindowsmousehandler.h \
|
||||
$$PWD/qwindowspointerhandler.h \
|
||||
$$PWD/qtwindowsglobal.h \
|
||||
$$PWD/qwindowsole.h \
|
||||
$$PWD/qwindowsdropdataobject.h \
|
||||
|
Loading…
x
Reference in New Issue
Block a user