5#include <QtCore/qt_windows.h>
8#if QT_CONFIG(tabletevent)
9# include "qwindowstabletsupport.h"
17#include <QtGui/qguiapplication.h>
18#include <QtGui/qscreen.h>
19#include <QtGui/qpointingdevice.h>
20#include <QtGui/qwindow.h>
21#include <QtGui/private/qguiapplication_p.h>
22#include <QtCore/qvarlengtharray.h>
23#include <QtCore/qloggingcategory.h>
24#include <QtCore/qqueue.h>
44 static QPointer<
const QPointingDevice> result;
46 result = QPointingDevice::primaryPointingDevice();
57 const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
59 if (!GetPointerType(pointerId, &m_pointerType)) {
60 qWarning() <<
"GetPointerType() failed:" << qt_error_string();
64 switch (m_pointerType) {
67 case QT_PT_TOUCHPAD: {
72 quint32 pointerCount = 0;
73 if (!GetPointerFrameTouchInfo(pointerId, &pointerCount,
nullptr)) {
74 qWarning() <<
"GetPointerFrameTouchInfo() failed:" << qt_error_string();
77 QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
78 if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
79 qWarning() <<
"GetPointerFrameTouchInfo() failed:" << qt_error_string();
87 quint32 historyCount = touchInfo[0].pointerInfo.historyCount;
89 if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
90 touchInfo.resize(pointerCount * historyCount);
91 if (!GetPointerFrameTouchInfoHistory(pointerId,
95 qWarning() <<
"GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
101 for (
auto it = touchInfo.rbegin(), end = touchInfo.rend(); it != end; it += pointerCount) {
102 result &= translateTouchEvent(window, hwnd, et, msg,
103 &(*(it + (pointerCount - 1))), pointerCount);
108 return translateTouchEvent(window, hwnd, et, msg, touchInfo.data(), pointerCount);
111 POINTER_PEN_INFO penInfo;
112 if (!GetPointerPenInfo(pointerId, &penInfo)) {
113 qWarning() <<
"GetPointerPenInfo() failed:" << qt_error_string();
117 quint32 historyCount = penInfo.pointerInfo.historyCount;
120 && (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)
121 || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
122 QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
124 if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) {
125 qWarning() <<
"GetPointerPenInfoHistory() failed:" << qt_error_string();
131 for (
auto it = penInfoHistory.rbegin(), end = penInfoHistory.rend(); it != end; ++it) {
132 result &= translatePenEvent(window, hwnd, et, msg, &(*(it)));
137 return translatePenEvent(window, hwnd, et, msg, &penInfo);
146 Qt::MouseButton button;
152 return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
157 switch (msg.message) {
159 return {QEvent::MouseMove, Qt::NoButton};
161 return {QEvent::MouseButtonPress, Qt::LeftButton};
163 return {QEvent::MouseButtonRelease, Qt::LeftButton};
164 case WM_LBUTTONDBLCLK:
165 return {QEvent::MouseButtonPress, Qt::LeftButton};
167 return {QEvent::MouseButtonPress, Qt::MiddleButton};
169 return {QEvent::MouseButtonRelease, Qt::MiddleButton};
170 case WM_MBUTTONDBLCLK:
171 return {QEvent::MouseButtonPress, Qt::MiddleButton};
173 return {QEvent::MouseButtonPress, Qt::RightButton};
175 return {QEvent::MouseButtonRelease, Qt::RightButton};
176 case WM_RBUTTONDBLCLK:
177 return {QEvent::MouseButtonPress, Qt::RightButton};
179 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
181 return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
182 case WM_XBUTTONDBLCLK:
183 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
185 return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
186 case WM_NCLBUTTONDOWN:
187 return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
189 return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
190 case WM_NCLBUTTONDBLCLK:
191 return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
192 case WM_NCMBUTTONDOWN:
193 return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
195 return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
196 case WM_NCMBUTTONDBLCLK:
197 return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
198 case WM_NCRBUTTONDOWN:
199 return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
201 return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
202 case WM_NCRBUTTONDBLCLK:
203 return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
207 return {QEvent::None, Qt::NoButton};
212 Qt::MouseButtons result = Qt::NoButton;
213 if (keyState & MK_LBUTTON)
214 result |= Qt::LeftButton;
215 if (keyState & MK_RBUTTON)
216 result |= Qt::RightButton;
217 if (keyState & MK_MBUTTON)
218 result |= Qt::MiddleButton;
219 if (keyState & MK_XBUTTON1)
220 result |= Qt::XButton1;
221 if (keyState & MK_XBUTTON2)
222 result |= Qt::XButton2;
228 Qt::MouseButtons result = Qt::NoButton;
229 const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
230 if (GetAsyncKeyState(VK_LBUTTON) < 0)
231 result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
232 if (GetAsyncKeyState(VK_RBUTTON) < 0)
233 result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
234 if (GetAsyncKeyState(VK_MBUTTON) < 0)
235 result |= Qt::MiddleButton;
236 if (GetAsyncKeyState(VK_XBUTTON1) < 0)
237 result |= Qt::XButton1;
238 if (GetAsyncKeyState(VK_XBUTTON2) < 0)
239 result |= Qt::XButton2;
250 while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput)
251 currentWindowUnderPointer = currentWindowUnderPointer->parent();
257 if (!currentWindowUnderPointer) {
258 const QRect clientRect(QPoint(0, 0), window->size());
259 if (clientRect.contains(globalPos))
260 currentWindowUnderPointer = window;
262 return currentWindowUnderPointer;
268 tme.cbSize =
sizeof(TRACKMOUSEEVENT);
269 tme.dwFlags = TME_LEAVE;
270 tme.hwndTrack = hwnd;
271 tme.dwHoverTime = HOVER_DEFAULT;
272 return TrackMouseEvent(&tme);
279 if (toplevel->handle() && toplevel->handle()->isForeignWindow())
289 const int digitizers = GetSystemMetrics(SM_DIGITIZER);
290 if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
292 const int tabletPc = GetSystemMetrics(SM_TABLETPC);
293 const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
294 const QPointingDevice::DeviceType type = (digitizers & NID_INTEGRATED_TOUCH)
295 ? QInputDevice::DeviceType::TouchScreen : QInputDevice::DeviceType::TouchPad;
296 QInputDevice::Capabilities capabilities = QInputDevice::Capability::Position
297 | QInputDevice::Capability::Area
298 | QInputDevice::Capability::NormalizedPosition;
299 if (type != QInputDevice::DeviceType::TouchScreen) {
300 capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
301 capabilities.setFlag(QInputDevice::Capability::Scroll);
302 }
else if (mouseEmulation) {
303 capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
306 const int flags = digitizers & ~NID_READY;
307 qCDebug(lcQpaEvents) <<
"Digitizers:" << Qt::hex << Qt::showbase << flags
308 <<
"Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
309 <<
"Tablet PC:" << tabletPc <<
"Max touch points:" << maxTouchPoints <<
"Capabilities:" << capabilities;
311 const int buttonCount = type == QInputDevice::DeviceType::TouchScreen ? 1 : 3;
313 const qint64 systemId = m_nextInputDeviceId++ | (qint64(flags << 2));
314 auto d =
new QPointingDevice(QString(), systemId, type,
315 QPointingDevice::PointerType::Finger,
316 capabilities, maxTouchPoints, buttonCount,
317 QString(), QPointingDeviceUniqueId::fromNumericId(systemId));
318 return QPointingDevicePtr(d);
323 m_lastEventType = QEvent::None;
324 m_lastEventButton = Qt::NoButton;
328 QWindow *currentWindowUnderPointer,
330 QEvent::Type eventType,
331 Qt::MouseButtons mouseButtons)
333 auto *platformWindow =
static_cast<
QWindowsWindow *>(window->handle());
336 if (!platformWindow->hasMouseCapture() && eventType == QEvent::MouseButtonPress) {
338 platformWindow->setMouseGrabEnabled(
true);
340 qCDebug(lcQpaEvents) <<
"Automatic mouse capture " << window;
343 if (!window->isTopLevel() && !window->inherits(
"QWidgetWindow") && QGuiApplication::focusWindow() != window)
344 window->requestActivate();
346 }
else if (platformWindow->hasMouseCapture()
347 && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
348 && eventType == QEvent::MouseButtonRelease
351 platformWindow->setMouseGrabEnabled(
false);
352 qCDebug(lcQpaEvents) <<
"Releasing automatic mouse capture " << window;
358 if (window != m_currentWindow &&
359 (!platformWindow->hasMouseCapture() || currentWindowUnderPointer == window)) {
361 m_currentWindow = window;
366 QWindow *currentWindowUnderPointer,
369 auto *platformWindow =
static_cast<
QWindowsWindow *>(window->handle());
370 const bool hasCapture = platformWindow->hasMouseCapture();
380 if ((m_windowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer
381 && (!hasCapture || window == m_windowUnderPointer))
382 || (hasCapture && m_previousCaptureWindow != window && m_windowUnderPointer
383 && m_windowUnderPointer != window)) {
385 qCDebug(lcQpaEvents) <<
"Leaving window " << m_windowUnderPointer;
386 QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
388 if (hasCapture && currentWindowUnderPointer != window) {
391 m_currentWindow =
nullptr;
394 platformWindow->applyCursor();
402 if ((currentWindowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer
403 && (!hasCapture || currentWindowUnderPointer == window))
404 || (m_previousCaptureWindow && !hasCapture && currentWindowUnderPointer
405 && currentWindowUnderPointer != m_previousCaptureWindow)) {
409 wumLocalPos = wumPlatformWindow->mapFromGlobal(globalPos);
412 qCDebug(lcQpaEvents) <<
"Entering window " << currentWindowUnderPointer;
413 QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, wumLocalPos, globalPos);
418 m_windowUnderPointer = currentWindowUnderPointer;
421 m_previousCaptureWindow = hasCapture ? window :
nullptr;
426 MSG msg, PVOID vTouchInfo, quint32 count)
430 auto *touchInfo =
static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
440 QWindowSystemInterface::handleTouchCancelEvent(window, msg.time, m_touchDevice.data(),
441 keyMapper->queryKeyboardModifiers());
442 m_lastTouchPoints.clear();
447 for (quint32 i = 0; i < count; ++i) {
448 const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
449 int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
451 m_lastTouchPoints.remove(id);
454 QWindowSystemInterface::handleEnterLeaveEvent(
nullptr, window);
461 const QScreen *screen = window->screen();
463 screen = QGuiApplication::primaryScreen();
467 const QRect screenGeometry = screen->geometry();
469 QList<QWindowSystemInterface::TouchPoint> touchPoints;
471 if (QWindowsContext::verbose > 1)
472 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
474 <<
" message=" << Qt::hex << msg.message
475 <<
" count=" << Qt::dec << count;
477 QEventPoint::States allStates;
480 for (quint32 i = 0; i < count; ++i) {
481 if (QWindowsContext::verbose > 1)
482 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
483 <<
" TouchPoint id=" << touchInfo[i].pointerInfo.pointerId
484 <<
" frame=" << touchInfo[i].pointerInfo.frameId
485 <<
" flags=" << Qt::hex << touchInfo[i].pointerInfo.pointerFlags;
487 QWindowSystemInterface::TouchPoint touchPoint;
488 const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
489 int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
492 if ((touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) == 0)
494 id = m_touchInputIDToTouchPointID.size();
495 m_touchInputIDToTouchPointID.insert(pointerId, id);
498 touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
499 touchInfo[i].pressure / 1024.0 : 1.0;
500 if (m_lastTouchPoints.contains(touchPoint.id))
501 touchPoint.normalPosition = m_lastTouchPoints.value(touchPoint.id).normalPosition;
503 const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
504 touchInfo[i].pointerInfo.ptPixelLocation.y);
506 if (touchInfo[i].touchMask & TOUCH_MASK_CONTACTAREA)
507 touchPoint.area.setSize(QSizeF(touchInfo[i].rcContact.right - touchInfo[i].rcContact.left,
508 touchInfo[i].rcContact.bottom - touchInfo[i].rcContact.top));
509 touchPoint.area.moveCenter(screenPos);
510 QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
511 screenPos.y() / screenGeometry.height());
512 const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
513 touchPoint.normalPosition = normalPosition;
515 if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
516 touchPoint.state = QEventPoint::State::Pressed;
517 m_lastTouchPoints.insert(touchPoint.id, touchPoint);
518 }
else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
519 touchPoint.state = QEventPoint::State::Released;
520 m_lastTouchPoints.remove(touchPoint.id);
522 touchPoint.state = stationaryTouchPoint ? QEventPoint::State::Stationary : QEventPoint::State::Updated;
523 m_lastTouchPoints.insert(touchPoint.id, touchPoint);
525 allStates |= touchPoint.state;
527 touchPoints.append(touchPoint);
528 inputIds.insert(touchPoint.id);
531 SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
536 for (
auto tp : std::as_const(m_lastTouchPoints)) {
537 if (!inputIds.contains(tp.id)) {
538 tp.state = QEventPoint::State::Stationary;
539 allStates |= tp.state;
540 touchPoints.append(tp);
544 if (touchPoints.count() == 0)
548 if (allStates == QEventPoint::State::Released)
549 m_touchInputIDToTouchPointID.clear();
552 QWindowSystemInterface::handleTouchEvent(window, msg.time, m_touchDevice.data(), touchPoints,
553 keyMapper->queryKeyboardModifiers());
557#if QT_CONFIG(tabletevent)
558QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::findTabletDevice(QPointingDevice::PointerType pointerType)
const
560 for (
const auto &d : m_tabletDevices) {
561 if (d->pointerType() == pointerType)
569 MSG msg, PVOID vPenInfo)
571#if QT_CONFIG(tabletevent)
572 if (et & QtWindows::NonClientEventFlag)
575 auto *penInfo =
static_cast<POINTER_PEN_INFO *>(vPenInfo);
578 if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
581 const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
582 const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
583 const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
584 const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
585 / (pRect.right - pRect.left) * (dRect.right - dRect.left),
586 dRect.top + qreal(penInfo->pointerInfo.ptHimetricLocation.y - pRect.top)
587 / (pRect.bottom - pRect.top) * (dRect.bottom - dRect.top));
588 const bool hasPressure = (penInfo->penMask & PEN_MASK_PRESSURE) != 0;
589 const bool hasRotation = (penInfo->penMask & PEN_MASK_ROTATION) != 0;
590 const qreal pressure = hasPressure ? qreal(penInfo->pressure) / 1024.0 : 0.5;
591 const qreal rotation = hasRotation ? qreal(penInfo->rotation) : 0.0;
592 const qreal tangentialPressure = 0.0;
593 const bool hasTiltX = (penInfo->penMask & PEN_MASK_TILT_X) != 0;
594 const bool hasTiltY = (penInfo->penMask & PEN_MASK_TILT_Y) != 0;
595 const int xTilt = hasTiltX ? penInfo->tiltX : 0;
596 const int yTilt = hasTiltY ? penInfo->tiltY : 0;
599 if (QWindowsContext::verbose > 1)
600 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
601 <<
__FUNCTION__ <<
" systemId=" << systemId
602 <<
" globalPos=" << globalPos <<
" localPos=" << localPos <<
" hiResGlobalPos=" << hiResGlobalPos
603 <<
" message=" << Qt::hex << msg.message
604 <<
" flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags;
606 QPointingDevice::PointerType type;
609 Qt::MouseButtons mouseButtons = queryMouseButtons();
611 const bool pointerInContact = IS_POINTER_INCONTACT_WPARAM(msg.wParam);
612 if (pointerInContact)
613 mouseButtons = Qt::LeftButton;
615 if (penInfo->penFlags & (PEN_FLAG_ERASER | PEN_FLAG_INVERTED)) {
616 type = QPointingDevice::PointerType::Eraser;
618 type = QPointingDevice::PointerType::Pen;
619 if (pointerInContact && penInfo->penFlags & PEN_FLAG_BARREL)
620 mouseButtons = Qt::RightButton;
623 auto device = findTabletDevice(type);
624 if (device.isNull()) {
625 QInputDevice::Capabilities caps(QInputDevice::Capability::Position
626 | QInputDevice::Capability::MouseEmulation
627 | QInputDevice::Capability::Hover);
629 caps |= QInputDevice::Capability::Pressure;
631 caps |= QInputDevice::Capability::Rotation;
633 caps |= QInputDevice::Capability::XTilt;
635 caps |= QInputDevice::Capability::YTilt;
636 const qint64 uniqueId = systemId | (qint64(type) << 32L);
637 device.reset(
new QPointingDevice(QStringLiteral(
"wmpointer"),
638 systemId, QInputDevice::DeviceType::Stylus,
639 type, caps, 1, 3, QString(),
640 QPointingDeviceUniqueId::fromNumericId(uniqueId)));
641 QWindowSystemInterface::registerInputDevice(device.data());
642 m_tabletDevices.append(device);
645 const auto uniqueId = device->uniqueId().numericId();
646 m_activeTabletDevice = device;
648 switch (msg.message) {
649 case WM_POINTERENTER: {
650 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(),
true);
651 m_windowUnderPointer = window;
654 m_needsEnterOnPointerUpdate =
true;
657 case WM_POINTERLEAVE:
658 if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
659 QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
660 m_windowUnderPointer =
nullptr;
661 m_currentWindow =
nullptr;
663 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(),
false);
667 case WM_POINTERUPDATE: {
668 QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target;
669 if (!target && m_windowUnderPointer)
670 target = m_windowUnderPointer;
674 if (m_needsEnterOnPointerUpdate) {
675 m_needsEnterOnPointerUpdate =
false;
676 if (window != m_currentWindow) {
680 QWindowSystemInterface::handleEnterEvent(window, localPos, globalPos);
681 m_currentWindow = window;
682 if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(target))
683 wumPlatformWindow->applyCursor();
686 const auto *keyMapper = QWindowsContext::instance()->keyMapper();
687 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
689 QWindowSystemInterface::handleTabletEvent(target, msg.time, device.data(),
690 localPos, hiResGlobalPos, mouseButtons,
691 pressure, xTilt, yTilt, tangentialPressure,
692 rotation, z, keyModifiers);
711 const LONG_PTR SIGNATURE_MASK = 0xFFFFFF00;
712 const LONG_PTR MI_WP_SIGNATURE = 0xFF515700;
714 return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE);
718 QWindow *currentWindowUnderPointer,
721 Qt::KeyboardModifiers keyModifiers)
723 QWindow *receiver = currentWindowUnderPointer;
729 int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
732 if (msg.message == WM_MOUSEHWHEEL)
735 const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ?
736 QPoint(delta, 0) : QPoint(0, delta);
738 QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
740 QWindowSystemInterface::handleWheelEvent(receiver, msg.time, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
755 QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
758 globalPos = eventPos;
759 localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
761 if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
763 GetClientRect(hwnd, &clientArea);
764 eventPos.setX(clientArea.right - eventPos.x());
767 globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
768 auto targetHwnd = hwnd;
769 if (
auto *pw = window->handle())
770 targetHwnd = HWND(pw->winId());
771 localPos = targetHwnd == hwnd
773 : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
777 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
778 QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
780 if (et == QtWindows::MouseWheelEvent)
781 return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers);
787 bool discardEvent =
false;
788 if (msg.message == WM_MOUSEMOVE) {
789 Q_CONSTINIT
static QPoint lastMouseMovePos;
790 if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
792 lastMouseMovePos = globalPos;
795 Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
803 switch (m_pointerType) {
805 if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
807 source = Qt::MouseEventSynthesizedBySystem;
808 if (!m_touchDevice.isNull())
809 device = m_touchDevice.data();
812#if QT_CONFIG(tabletevent)
813 qCDebug(lcQpaTablet) <<
"ignoring synth-mouse event for tablet event from" << device;
820 const MouseEvent mouseEvent = eventFromMsg(msg);
821 Qt::MouseButtons mouseButtons;
823 if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
824 mouseButtons = queryMouseButtons();
826 mouseButtons = mouseButtonsFromKeyState(msg.wParam);
834 if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
835 && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
836 && (m_lastEventButton & mouseButtons) == 0) {
837 auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
838 QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
839 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons, m_lastEventButton,
840 releaseType, keyModifiers, source);
842 m_lastEventType = mouseEvent.type;
843 m_lastEventButton = mouseEvent.button;
845 if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
846 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
847 mouseEvent.button, mouseEvent.type, keyModifiers, source);
851 if (msg.message == WM_MOUSELEAVE) {
852 if (window == m_currentWindow) {
853 QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow;
854 qCDebug(lcQpaEvents) <<
"Leaving window " << leaveTarget;
855 QWindowSystemInterface::handleLeaveEvent(leaveTarget);
856 m_windowUnderPointer =
nullptr;
857 m_currentWindow =
nullptr;
862 handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons);
863 handleEnterLeave(window, currentWindowUnderPointer, globalPos);
865 if (!discardEvent && mouseEvent.type != QEvent::None) {
866 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
867 mouseEvent.button, mouseEvent.type, keyModifiers, source);
872 return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
873 || 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)
static QWindow * windowAt(const QPoint &point, unsigned flags)
bool testFlag(unsigned f) const
void applyCursor()
Applies to cursor property set on the window to the global cursor.
bool hasMouseCapture() const
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)