4#include <QtCore/qt_windows.h>
7#if QT_CONFIG(tabletevent)
8# include "qwindowstabletsupport.h"
16#include <QtGui/qguiapplication.h>
17#include <QtGui/qscreen.h>
18#include <QtGui/qpointingdevice.h>
19#include <QtGui/qwindow.h>
20#include <QtGui/private/qguiapplication_p.h>
21#include <QtCore/qvarlengtharray.h>
22#include <QtCore/qloggingcategory.h>
23#include <QtCore/qqueue.h>
43 static QPointer<
const QPointingDevice> result;
45 result = QPointingDevice::primaryPointingDevice();
56 const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
58 if (!GetPointerType(pointerId, &m_pointerType)) {
59 qWarning() <<
"GetPointerType() failed:" << qt_error_string();
63 switch (m_pointerType) {
66 case QT_PT_TOUCHPAD: {
71 quint32 pointerCount = 0;
72 if (!GetPointerFrameTouchInfo(pointerId, &pointerCount,
nullptr)) {
73 qWarning() <<
"GetPointerFrameTouchInfo() failed:" << qt_error_string();
76 QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
77 if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
78 qWarning() <<
"GetPointerFrameTouchInfo() failed:" << qt_error_string();
86 quint32 historyCount = touchInfo[0].pointerInfo.historyCount;
88 if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
89 touchInfo.resize(pointerCount * historyCount);
90 if (!GetPointerFrameTouchInfoHistory(pointerId,
94 qWarning() <<
"GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
100 for (
auto it = touchInfo.rbegin(), end = touchInfo.rend(); it != end; it += pointerCount) {
101 result &= translateTouchEvent(window, hwnd, et, msg,
102 &(*(it + (pointerCount - 1))), pointerCount);
107 return translateTouchEvent(window, hwnd, et, msg, touchInfo.data(), pointerCount);
110 POINTER_PEN_INFO penInfo;
111 if (!GetPointerPenInfo(pointerId, &penInfo)) {
112 qWarning() <<
"GetPointerPenInfo() failed:" << qt_error_string();
116 quint32 historyCount = penInfo.pointerInfo.historyCount;
119 && (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)
120 || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
121 QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
123 if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) {
124 qWarning() <<
"GetPointerPenInfoHistory() failed:" << qt_error_string();
130 for (
auto it = penInfoHistory.rbegin(), end = penInfoHistory.rend(); it != end; ++it) {
131 result &= translatePenEvent(window, hwnd, et, msg, &(*(it)));
136 return translatePenEvent(window, hwnd, et, msg, &penInfo);
145 Qt::MouseButton button;
151 return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
156 switch (msg.message) {
158 return {QEvent::MouseMove, Qt::NoButton};
160 return {QEvent::MouseButtonPress, Qt::LeftButton};
162 return {QEvent::MouseButtonRelease, Qt::LeftButton};
163 case WM_LBUTTONDBLCLK:
164 return {QEvent::MouseButtonPress, Qt::LeftButton};
166 return {QEvent::MouseButtonPress, Qt::MiddleButton};
168 return {QEvent::MouseButtonRelease, Qt::MiddleButton};
169 case WM_MBUTTONDBLCLK:
170 return {QEvent::MouseButtonPress, Qt::MiddleButton};
172 return {QEvent::MouseButtonPress, Qt::RightButton};
174 return {QEvent::MouseButtonRelease, Qt::RightButton};
175 case WM_RBUTTONDBLCLK:
176 return {QEvent::MouseButtonPress, Qt::RightButton};
178 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
180 return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
181 case WM_XBUTTONDBLCLK:
182 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
184 return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
185 case WM_NCLBUTTONDOWN:
186 return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
188 return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
189 case WM_NCLBUTTONDBLCLK:
190 return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
191 case WM_NCMBUTTONDOWN:
192 return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
194 return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
195 case WM_NCMBUTTONDBLCLK:
196 return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
197 case WM_NCRBUTTONDOWN:
198 return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
200 return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
201 case WM_NCRBUTTONDBLCLK:
202 return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
206 return {QEvent::None, Qt::NoButton};
211 Qt::MouseButtons result = Qt::NoButton;
212 if (keyState & MK_LBUTTON)
213 result |= Qt::LeftButton;
214 if (keyState & MK_RBUTTON)
215 result |= Qt::RightButton;
216 if (keyState & MK_MBUTTON)
217 result |= Qt::MiddleButton;
218 if (keyState & MK_XBUTTON1)
219 result |= Qt::XButton1;
220 if (keyState & MK_XBUTTON2)
221 result |= Qt::XButton2;
227 Qt::MouseButtons result = Qt::NoButton;
228 const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
229 if (GetAsyncKeyState(VK_LBUTTON) < 0)
230 result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
231 if (GetAsyncKeyState(VK_RBUTTON) < 0)
232 result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
233 if (GetAsyncKeyState(VK_MBUTTON) < 0)
234 result |= Qt::MiddleButton;
235 if (GetAsyncKeyState(VK_XBUTTON1) < 0)
236 result |= Qt::XButton1;
237 if (GetAsyncKeyState(VK_XBUTTON2) < 0)
238 result |= Qt::XButton2;
246 QWindow *currentWindowUnderPointer = platformWindow->hasMouseCapture() ?
247 QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window;
249 while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput)
250 currentWindowUnderPointer = currentWindowUnderPointer->parent();
256 if (!currentWindowUnderPointer) {
257 const QRect clientRect(QPoint(0, 0), window->size());
258 if (clientRect.contains(globalPos))
259 currentWindowUnderPointer = window;
261 return currentWindowUnderPointer;
267 tme.cbSize =
sizeof(TRACKMOUSEEVENT);
268 tme.dwFlags = TME_LEAVE;
269 tme.hwndTrack = hwnd;
270 tme.dwHoverTime = HOVER_DEFAULT;
271 return TrackMouseEvent(&tme);
278 if (toplevel->handle() && toplevel->handle()->isForeignWindow())
288 const int digitizers = GetSystemMetrics(SM_DIGITIZER);
289 if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
291 const int tabletPc = GetSystemMetrics(SM_TABLETPC);
292 const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
293 const QPointingDevice::DeviceType type = (digitizers & NID_INTEGRATED_TOUCH)
294 ? QInputDevice::DeviceType::TouchScreen : QInputDevice::DeviceType::TouchPad;
295 QInputDevice::Capabilities capabilities = QInputDevice::Capability::Position
296 | QInputDevice::Capability::Area
297 | QInputDevice::Capability::NormalizedPosition;
298 if (type != QInputDevice::DeviceType::TouchScreen) {
299 capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
300 capabilities.setFlag(QInputDevice::Capability::Scroll);
301 }
else if (mouseEmulation) {
302 capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
305 const int flags = digitizers & ~NID_READY;
306 qCDebug(lcQpaEvents) <<
"Digitizers:" << Qt::hex << Qt::showbase << flags
307 <<
"Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
308 <<
"Tablet PC:" << tabletPc <<
"Max touch points:" << maxTouchPoints <<
"Capabilities:" << capabilities;
310 const int buttonCount = type == QInputDevice::DeviceType::TouchScreen ? 1 : 3;
312 const qint64 systemId = m_nextInputDeviceId++ | (qint64(flags << 2));
313 auto d =
new QPointingDevice(QString(), systemId, type,
314 QPointingDevice::PointerType::Finger,
315 capabilities, maxTouchPoints, buttonCount,
316 QString(), QPointingDeviceUniqueId::fromNumericId(systemId));
317 return QPointingDevicePtr(d);
322 m_lastEventType = QEvent::None;
323 m_lastEventButton = Qt::NoButton;
327 QWindow *currentWindowUnderPointer,
329 QEvent::Type eventType,
330 Qt::MouseButtons mouseButtons)
332 auto *platformWindow =
static_cast<
QWindowsWindow *>(window->handle());
335 if (!platformWindow->hasMouseCapture() && eventType == QEvent::MouseButtonPress) {
337 platformWindow->setMouseGrabEnabled(
true);
339 qCDebug(lcQpaEvents) <<
"Automatic mouse capture " << window;
342 if (!window->isTopLevel() && !window->inherits(
"QWidgetWindow") && QGuiApplication::focusWindow() != window)
343 window->requestActivate();
345 }
else if (platformWindow->hasMouseCapture()
346 && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
347 && eventType == QEvent::MouseButtonRelease
350 platformWindow->setMouseGrabEnabled(
false);
351 qCDebug(lcQpaEvents) <<
"Releasing automatic mouse capture " << window;
357 if (window != m_currentWindow &&
358 (!platformWindow->hasMouseCapture() || currentWindowUnderPointer == window)) {
360 m_currentWindow = window;
365 QWindow *currentWindowUnderPointer,
368 auto *platformWindow =
static_cast<
QWindowsWindow *>(window->handle());
369 const bool hasCapture = platformWindow->hasMouseCapture();
379 if ((m_windowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer
380 && (!hasCapture || window == m_windowUnderPointer))
381 || (hasCapture && m_previousCaptureWindow != window && m_windowUnderPointer
382 && m_windowUnderPointer != window)) {
384 qCDebug(lcQpaEvents) <<
"Leaving window " << m_windowUnderPointer;
385 QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
387 if (hasCapture && currentWindowUnderPointer != window) {
390 m_currentWindow =
nullptr;
393 platformWindow->applyCursor();
401 if ((currentWindowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer
402 && (!hasCapture || currentWindowUnderPointer == window))
403 || (m_previousCaptureWindow && !hasCapture && currentWindowUnderPointer
404 && currentWindowUnderPointer != m_previousCaptureWindow)) {
408 wumLocalPos = wumPlatformWindow->mapFromGlobal(globalPos);
411 qCDebug(lcQpaEvents) <<
"Entering window " << currentWindowUnderPointer;
412 QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, wumLocalPos, globalPos);
417 m_windowUnderPointer = currentWindowUnderPointer;
420 m_previousCaptureWindow = hasCapture ? window :
nullptr;
425 MSG msg, PVOID vTouchInfo, quint32 count)
429 auto *touchInfo =
static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
439 QWindowSystemInterface::handleTouchCancelEvent(window, msg.time, m_touchDevice.data(),
440 keyMapper->queryKeyboardModifiers());
441 m_lastTouchPoints.clear();
446 for (quint32 i = 0; i < count; ++i) {
447 const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
448 int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
450 m_lastTouchPoints.remove(id);
453 QWindowSystemInterface::handleEnterLeaveEvent(
nullptr, window);
460 const QScreen *screen = window->screen();
462 screen = QGuiApplication::primaryScreen();
466 const QRect screenGeometry = screen->geometry();
468 QList<QWindowSystemInterface::TouchPoint> touchPoints;
470 if (QWindowsContext::verbose > 1)
471 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
473 <<
" message=" << Qt::hex << msg.message
474 <<
" count=" << Qt::dec << count;
476 QEventPoint::States allStates;
479 for (quint32 i = 0; i < count; ++i) {
480 if (QWindowsContext::verbose > 1)
481 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
482 <<
" TouchPoint id=" << touchInfo[i].pointerInfo.pointerId
483 <<
" frame=" << touchInfo[i].pointerInfo.frameId
484 <<
" flags=" << Qt::hex << touchInfo[i].pointerInfo.pointerFlags;
486 QWindowSystemInterface::TouchPoint touchPoint;
487 const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
488 int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
491 if ((touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) == 0)
493 id = m_touchInputIDToTouchPointID.size();
494 m_touchInputIDToTouchPointID.insert(pointerId, id);
497 touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
498 touchInfo[i].pressure / 1024.0 : 1.0;
499 if (m_lastTouchPoints.contains(touchPoint.id))
500 touchPoint.normalPosition = m_lastTouchPoints.value(touchPoint.id).normalPosition;
502 const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
503 touchInfo[i].pointerInfo.ptPixelLocation.y);
505 if (touchInfo[i].touchMask & TOUCH_MASK_CONTACTAREA)
506 touchPoint.area.setSize(QSizeF(touchInfo[i].rcContact.right - touchInfo[i].rcContact.left,
507 touchInfo[i].rcContact.bottom - touchInfo[i].rcContact.top));
508 touchPoint.area.moveCenter(screenPos);
509 QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
510 screenPos.y() / screenGeometry.height());
511 const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
512 touchPoint.normalPosition = normalPosition;
514 if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
515 touchPoint.state = QEventPoint::State::Pressed;
516 m_lastTouchPoints.insert(touchPoint.id, touchPoint);
517 }
else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
518 touchPoint.state = QEventPoint::State::Released;
519 m_lastTouchPoints.remove(touchPoint.id);
521 touchPoint.state = stationaryTouchPoint ? QEventPoint::State::Stationary : QEventPoint::State::Updated;
522 m_lastTouchPoints.insert(touchPoint.id, touchPoint);
524 allStates |= touchPoint.state;
526 touchPoints.append(touchPoint);
527 inputIds.insert(touchPoint.id);
530 SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
535 for (
auto tp : std::as_const(m_lastTouchPoints)) {
536 if (!inputIds.contains(tp.id)) {
537 tp.state = QEventPoint::State::Stationary;
538 allStates |= tp.state;
539 touchPoints.append(tp);
543 if (touchPoints.count() == 0)
547 if (allStates == QEventPoint::State::Released)
548 m_touchInputIDToTouchPointID.clear();
551 QWindowSystemInterface::handleTouchEvent(window, msg.time, m_touchDevice.data(), touchPoints,
552 keyMapper->queryKeyboardModifiers());
556#if QT_CONFIG(tabletevent)
557QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::findTabletDevice(QPointingDevice::PointerType pointerType)
const
559 for (
const auto &d : m_tabletDevices) {
560 if (d->pointerType() == pointerType)
568 MSG msg, PVOID vPenInfo)
570#if QT_CONFIG(tabletevent)
571 if (et & QtWindows::NonClientEventFlag)
574 auto *penInfo =
static_cast<POINTER_PEN_INFO *>(vPenInfo);
577 if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
580 const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
581 const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
582 const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
583 const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
584 / (pRect.right - pRect.left) * (dRect.right - dRect.left),
585 dRect.top + qreal(penInfo->pointerInfo.ptHimetricLocation.y - pRect.top)
586 / (pRect.bottom - pRect.top) * (dRect.bottom - dRect.top));
587 const bool hasPressure = (penInfo->penMask & PEN_MASK_PRESSURE) != 0;
588 const bool hasRotation = (penInfo->penMask & PEN_MASK_ROTATION) != 0;
589 const qreal pressure = hasPressure ? qreal(penInfo->pressure) / 1024.0 : 0.5;
590 const qreal rotation = hasRotation ? qreal(penInfo->rotation) : 0.0;
591 const qreal tangentialPressure = 0.0;
592 const bool hasTiltX = (penInfo->penMask & PEN_MASK_TILT_X) != 0;
593 const bool hasTiltY = (penInfo->penMask & PEN_MASK_TILT_Y) != 0;
594 const int xTilt = hasTiltX ? penInfo->tiltX : 0;
595 const int yTilt = hasTiltY ? penInfo->tiltY : 0;
598 if (QWindowsContext::verbose > 1)
599 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
600 <<
__FUNCTION__ <<
" systemId=" << systemId
601 <<
" globalPos=" << globalPos <<
" localPos=" << localPos <<
" hiResGlobalPos=" << hiResGlobalPos
602 <<
" message=" << Qt::hex << msg.message
603 <<
" flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags;
605 QPointingDevice::PointerType type;
608 Qt::MouseButtons mouseButtons = queryMouseButtons();
610 const bool pointerInContact = IS_POINTER_INCONTACT_WPARAM(msg.wParam);
611 if (pointerInContact)
612 mouseButtons = Qt::LeftButton;
614 if (penInfo->penFlags & (PEN_FLAG_ERASER | PEN_FLAG_INVERTED)) {
615 type = QPointingDevice::PointerType::Eraser;
617 type = QPointingDevice::PointerType::Pen;
618 if (pointerInContact && penInfo->penFlags & PEN_FLAG_BARREL)
619 mouseButtons = Qt::RightButton;
622 auto device = findTabletDevice(type);
623 if (device.isNull()) {
624 QInputDevice::Capabilities caps(QInputDevice::Capability::Position
625 | QInputDevice::Capability::MouseEmulation
626 | QInputDevice::Capability::Hover);
628 caps |= QInputDevice::Capability::Pressure;
630 caps |= QInputDevice::Capability::Rotation;
632 caps |= QInputDevice::Capability::XTilt;
634 caps |= QInputDevice::Capability::YTilt;
635 const qint64 uniqueId = systemId | (qint64(type) << 32L);
636 device.reset(
new QPointingDevice(QStringLiteral(
"wmpointer"),
637 systemId, QInputDevice::DeviceType::Stylus,
638 type, caps, 1, 3, QString(),
639 QPointingDeviceUniqueId::fromNumericId(uniqueId)));
640 QWindowSystemInterface::registerInputDevice(device.data());
641 m_tabletDevices.append(device);
644 const auto uniqueId = device->uniqueId().numericId();
645 m_activeTabletDevice = device;
647 switch (msg.message) {
648 case WM_POINTERENTER: {
649 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(),
true);
650 m_windowUnderPointer = window;
653 m_needsEnterOnPointerUpdate =
true;
656 case WM_POINTERLEAVE:
657 if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
658 QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
659 m_windowUnderPointer =
nullptr;
660 m_currentWindow =
nullptr;
662 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(),
false);
666 case WM_POINTERUPDATE: {
667 QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target;
668 if (!target && m_windowUnderPointer)
669 target = m_windowUnderPointer;
673 if (m_needsEnterOnPointerUpdate) {
674 m_needsEnterOnPointerUpdate =
false;
675 if (window != m_currentWindow) {
679 QWindowSystemInterface::handleEnterEvent(window, localPos, globalPos);
680 m_currentWindow = window;
681 if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(target))
682 wumPlatformWindow->applyCursor();
685 const auto *keyMapper = QWindowsContext::instance()->keyMapper();
686 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
688 QWindowSystemInterface::handleTabletEvent(target, msg.time, device.data(),
689 localPos, hiResGlobalPos, mouseButtons,
690 pressure, xTilt, yTilt, tangentialPressure,
691 rotation, z, keyModifiers);
710 const LONG_PTR SIGNATURE_MASK = 0xFFFFFF00;
711 const LONG_PTR MI_WP_SIGNATURE = 0xFF515700;
713 return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE);
717 QWindow *currentWindowUnderPointer,
720 Qt::KeyboardModifiers keyModifiers)
722 QWindow *receiver = currentWindowUnderPointer;
728 int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
731 if (msg.message == WM_MOUSEHWHEEL)
734 const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ?
735 QPoint(delta, 0) : QPoint(0, delta);
737 QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
739 QWindowSystemInterface::handleWheelEvent(receiver, msg.time, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
754 QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
757 globalPos = eventPos;
758 localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
760 if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
762 GetClientRect(hwnd, &clientArea);
763 eventPos.setX(clientArea.right - eventPos.x());
766 globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
767 auto targetHwnd = hwnd;
768 if (
auto *pw = window->handle())
769 targetHwnd = HWND(pw->winId());
770 localPos = targetHwnd == hwnd
772 : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
776 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
777 QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
779 if (et == QtWindows::MouseWheelEvent)
780 return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers);
786 bool discardEvent =
false;
787 if (msg.message == WM_MOUSEMOVE) {
788 Q_CONSTINIT
static QPoint lastMouseMovePos;
789 if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
791 lastMouseMovePos = globalPos;
794 Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
802 switch (m_pointerType) {
804 if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
806 source = Qt::MouseEventSynthesizedBySystem;
807 if (!m_touchDevice.isNull())
808 device = m_touchDevice.data();
811#if QT_CONFIG(tabletevent)
812 qCDebug(lcQpaTablet) <<
"ignoring synth-mouse event for tablet event from" << device;
819 const MouseEvent mouseEvent = eventFromMsg(msg);
820 Qt::MouseButtons mouseButtons;
822 if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
823 mouseButtons = queryMouseButtons();
825 mouseButtons = mouseButtonsFromKeyState(msg.wParam);
833 if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
834 && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
835 && (m_lastEventButton & mouseButtons) == 0) {
836 auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
837 QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
838 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons, m_lastEventButton,
839 releaseType, keyModifiers, source);
841 m_lastEventType = mouseEvent.type;
842 m_lastEventButton = mouseEvent.button;
844 if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
845 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
846 mouseEvent.button, mouseEvent.type, keyModifiers, source);
850 if (msg.message == WM_MOUSELEAVE) {
851 if (window == m_currentWindow) {
852 QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow;
853 qCDebug(lcQpaEvents) <<
"Leaving window " << leaveTarget;
854 QWindowSystemInterface::handleLeaveEvent(leaveTarget);
855 m_windowUnderPointer =
nullptr;
856 m_currentWindow =
nullptr;
861 handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons);
862 handleEnterLeave(window, currentWindowUnderPointer, globalPos);
864 if (!discardEvent && mouseEvent.type != QEvent::None) {
865 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
866 mouseEvent.button, mouseEvent.type, keyModifiers, source);
871 return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
872 || QWindowSystemInterface::flushWindowSystemEvents();
\inmodule QtCore\reentrant
Singleton container for all relevant information.
QPlatformKeyMapper * keyMapper() const
static QWindowsContext * instance()
~QWindowsPointerHandler()
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)
bool testFlag(unsigned f) const
void applyCursor()
Applies to cursor property set on the window to the global cursor.
WindowsEventType
Enumerations for WM_XX events.
#define WM_POINTERCAPTURECHANGED
static bool isValidWheelReceiver(QWindow *candidate)
static bool trackLeave(HWND hwnd)
static QWindow * getWindowUnderPointer(QWindow *window, QPoint globalPos)
static Qt::MouseButton extraButton(WPARAM wParam)
const QPointingDevice * primaryMouse()
static MouseEvent eventFromMsg(const MSG &msg)
static bool isMouseEventSynthesizedFromPenOrTouch()
static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)