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();
61 const int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
63 m_lastTouchPoints.remove(id);
64 m_touchInputIDToTouchPointID.remove(pointerId);
69 switch (m_pointerType) {
72 case QT_PT_TOUCHPAD: {
77 quint32 pointerCount = 0;
78 if (!GetPointerFrameTouchInfo(pointerId, &pointerCount,
nullptr)) {
79 qWarning() <<
"GetPointerFrameTouchInfo() failed:" << qt_error_string();
82 QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
83 if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
84 qWarning() <<
"GetPointerFrameTouchInfo() failed:" << qt_error_string();
92 quint32 historyCount = touchInfo[0].pointerInfo.historyCount;
94 if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
95 touchInfo.resize(pointerCount * historyCount);
96 if (!GetPointerFrameTouchInfoHistory(pointerId,
100 qWarning() <<
"GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
106 for (
auto it = touchInfo.rbegin(), end = touchInfo.rend(); it != end; it += pointerCount) {
107 result &= translateTouchEvent(window, hwnd, et, msg,
108 &(*(it + (pointerCount - 1))), pointerCount);
113 return translateTouchEvent(window, hwnd, et, msg, touchInfo.data(), pointerCount);
116 POINTER_PEN_INFO penInfo;
117 if (!GetPointerPenInfo(pointerId, &penInfo)) {
118 qWarning() <<
"GetPointerPenInfo() failed:" << qt_error_string();
122 quint32 historyCount = penInfo.pointerInfo.historyCount;
125 && (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)
126 || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
127 QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
129 if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) {
130 qWarning() <<
"GetPointerPenInfoHistory() failed:" << qt_error_string();
136 for (
auto it = penInfoHistory.rbegin(), end = penInfoHistory.rend(); it != end; ++it) {
137 result &= translatePenEvent(window, hwnd, et, msg, &(*(it)));
142 return translatePenEvent(window, hwnd, et, msg, &penInfo);
151 Qt::MouseButton button;
157 return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
162 switch (msg.message) {
164 return {QEvent::MouseMove, Qt::NoButton};
166 return {QEvent::MouseButtonPress, Qt::LeftButton};
168 return {QEvent::MouseButtonRelease, Qt::LeftButton};
169 case WM_LBUTTONDBLCLK:
170 return {QEvent::MouseButtonPress, Qt::LeftButton};
172 return {QEvent::MouseButtonPress, Qt::MiddleButton};
174 return {QEvent::MouseButtonRelease, Qt::MiddleButton};
175 case WM_MBUTTONDBLCLK:
176 return {QEvent::MouseButtonPress, Qt::MiddleButton};
178 return {QEvent::MouseButtonPress, Qt::RightButton};
180 return {QEvent::MouseButtonRelease, Qt::RightButton};
181 case WM_RBUTTONDBLCLK:
182 return {QEvent::MouseButtonPress, Qt::RightButton};
184 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
186 return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
187 case WM_XBUTTONDBLCLK:
188 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
190 return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
191 case WM_NCLBUTTONDOWN:
192 return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
194 return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
195 case WM_NCLBUTTONDBLCLK:
196 return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
197 case WM_NCMBUTTONDOWN:
198 return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
200 return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
201 case WM_NCMBUTTONDBLCLK:
202 return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
203 case WM_NCRBUTTONDOWN:
204 return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
206 return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
207 case WM_NCRBUTTONDBLCLK:
208 return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
212 return {QEvent::None, Qt::NoButton};
217 Qt::MouseButtons result = Qt::NoButton;
218 if (keyState & MK_LBUTTON)
219 result |= Qt::LeftButton;
220 if (keyState & MK_RBUTTON)
221 result |= Qt::RightButton;
222 if (keyState & MK_MBUTTON)
223 result |= Qt::MiddleButton;
224 if (keyState & MK_XBUTTON1)
225 result |= Qt::XButton1;
226 if (keyState & MK_XBUTTON2)
227 result |= Qt::XButton2;
233 Qt::MouseButtons result = Qt::NoButton;
234 const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
235 if (GetAsyncKeyState(VK_LBUTTON) < 0)
236 result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
237 if (GetAsyncKeyState(VK_RBUTTON) < 0)
238 result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
239 if (GetAsyncKeyState(VK_MBUTTON) < 0)
240 result |= Qt::MiddleButton;
241 if (GetAsyncKeyState(VK_XBUTTON1) < 0)
242 result |= Qt::XButton1;
243 if (GetAsyncKeyState(VK_XBUTTON2) < 0)
244 result |= Qt::XButton2;
255 while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput)
256 currentWindowUnderPointer = currentWindowUnderPointer->parent();
262 if (!currentWindowUnderPointer) {
263 const QRect clientRect(QPoint(0, 0), window->size());
264 if (clientRect.contains(globalPos))
265 currentWindowUnderPointer = window;
267 return currentWindowUnderPointer;
273 tme.cbSize =
sizeof(TRACKMOUSEEVENT);
274 tme.dwFlags = TME_LEAVE;
275 tme.hwndTrack = hwnd;
276 tme.dwHoverTime = HOVER_DEFAULT;
277 return TrackMouseEvent(&tme);
284 if (toplevel->handle() && toplevel->handle()->isForeignWindow())
294 const int digitizers = GetSystemMetrics(SM_DIGITIZER);
295 if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
297 const int tabletPc = GetSystemMetrics(SM_TABLETPC);
298 const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
299 const QPointingDevice::DeviceType type = (digitizers & NID_INTEGRATED_TOUCH)
300 ? QInputDevice::DeviceType::TouchScreen : QInputDevice::DeviceType::TouchPad;
301 QInputDevice::Capabilities capabilities = QInputDevice::Capability::Position
302 | QInputDevice::Capability::Area
303 | QInputDevice::Capability::NormalizedPosition;
304 if (type != QInputDevice::DeviceType::TouchScreen) {
305 capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
306 capabilities.setFlag(QInputDevice::Capability::Scroll);
307 }
else if (mouseEmulation) {
308 capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
311 const int flags = digitizers & ~NID_READY;
312 qCDebug(lcQpaEvents) <<
"Digitizers:" << Qt::hex << Qt::showbase << flags
313 <<
"Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
314 <<
"Tablet PC:" << tabletPc <<
"Max touch points:" << maxTouchPoints <<
"Capabilities:" << capabilities;
316 const int buttonCount = type == QInputDevice::DeviceType::TouchScreen ? 1 : 3;
318 const qint64 systemId = m_nextInputDeviceId++ | (qint64(flags << 2));
319 auto d =
new QPointingDevice(QString(), systemId, type,
320 QPointingDevice::PointerType::Finger,
321 capabilities, maxTouchPoints, buttonCount,
322 QString(), QPointingDeviceUniqueId::fromNumericId(systemId));
323 return QPointingDevicePtr(d);
328 m_lastEventType = QEvent::None;
329 m_lastEventButton = Qt::NoButton;
333 QWindow *currentWindowUnderPointer,
335 QEvent::Type eventType,
336 Qt::MouseButtons mouseButtons)
338 auto *platformWindow =
static_cast<
QWindowsWindow *>(window->handle());
341 if (!platformWindow->hasMouseCapture() && eventType == QEvent::MouseButtonPress) {
343 platformWindow->setMouseGrabEnabled(
true);
345 qCDebug(lcQpaEvents) <<
"Automatic mouse capture " << window;
347 }
else if (platformWindow->hasMouseCapture()
348 && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
349 && eventType == QEvent::MouseButtonRelease
352 platformWindow->setMouseGrabEnabled(
false);
353 qCDebug(lcQpaEvents) <<
"Releasing automatic mouse capture " << window;
359 if (window != m_currentWindow &&
360 (!platformWindow->hasMouseCapture() || currentWindowUnderPointer == window)) {
362 m_currentWindow = window;
367 QWindow *currentWindowUnderPointer,
370 auto *platformWindow =
static_cast<
QWindowsWindow *>(window->handle());
371 const bool hasCapture = platformWindow->hasMouseCapture();
381 if ((m_windowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer
382 && (!hasCapture || window == m_windowUnderPointer))
383 || (hasCapture && m_previousCaptureWindow != window && m_windowUnderPointer
384 && m_windowUnderPointer != window)) {
386 qCDebug(lcQpaEvents) <<
"Leaving window " << m_windowUnderPointer;
387 QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
389 if (hasCapture && currentWindowUnderPointer != window) {
392 m_currentWindow =
nullptr;
395 platformWindow->applyCursor();
403 if ((currentWindowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer
404 && (!hasCapture || currentWindowUnderPointer == window))
405 || (m_previousCaptureWindow && !hasCapture && currentWindowUnderPointer
406 && currentWindowUnderPointer != m_previousCaptureWindow)) {
410 wumLocalPos = wumPlatformWindow->mapFromGlobal(globalPos);
413 qCDebug(lcQpaEvents) <<
"Entering window " << currentWindowUnderPointer;
414 QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, wumLocalPos, globalPos);
419 m_windowUnderPointer = currentWindowUnderPointer;
422 m_previousCaptureWindow = hasCapture ? window :
nullptr;
426 QEvent::Type eventType)
428 if (eventType != QEvent::MouseButtonPress)
431 auto *focusWindow = QGuiApplication::focusWindow();
432 if (window->isTopLevel()) {
437 if (focusWindow && window->isAncestorOf(focusWindow))
438 window->requestActivate();
439 }
else if (!window->inherits(
"QWidgetWindow") && focusWindow != window) {
442 window->requestActivate();
448 MSG msg, PVOID vTouchInfo, quint32 count)
452 auto *touchInfo =
static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
462 QWindowSystemInterface::handleTouchCancelEvent(window, msg.time, m_touchDevice.data(),
463 keyMapper->queryKeyboardModifiers());
464 m_lastTouchPoints.clear();
469 for (quint32 i = 0; i < count; ++i) {
470 const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
471 int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
473 m_lastTouchPoints.remove(id);
476 QWindowSystemInterface::handleEnterLeaveEvent(
nullptr, window);
483 const QScreen *screen = window->screen();
485 screen = QGuiApplication::primaryScreen();
489 const QRect screenGeometry = screen->geometry();
491 QList<QWindowSystemInterface::TouchPoint> touchPoints;
493 if (QWindowsContext::verbose > 1)
494 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
496 <<
" message=" << Qt::hex << msg.message
497 <<
" count=" << Qt::dec << count;
499 QEventPoint::States allStates;
502 for (quint32 i = 0; i < count; ++i) {
503 if (QWindowsContext::verbose > 1)
504 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
505 <<
" TouchPoint id=" << touchInfo[i].pointerInfo.pointerId
506 <<
" frame=" << touchInfo[i].pointerInfo.frameId
507 <<
" flags=" << Qt::hex << touchInfo[i].pointerInfo.pointerFlags;
509 QWindowSystemInterface::TouchPoint touchPoint;
510 const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
511 int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
514 if ((touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) == 0)
516 id = m_touchInputIDToTouchPointID.size();
517 m_touchInputIDToTouchPointID.insert(pointerId, id);
520 touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
521 touchInfo[i].pressure / 1024.0 : 1.0;
522 if (m_lastTouchPoints.contains(touchPoint.id))
523 touchPoint.normalPosition = m_lastTouchPoints.value(touchPoint.id).normalPosition;
525 const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
526 touchInfo[i].pointerInfo.ptPixelLocation.y);
528 if (touchInfo[i].touchMask & TOUCH_MASK_CONTACTAREA)
529 touchPoint.area.setSize(QSizeF(touchInfo[i].rcContact.right - touchInfo[i].rcContact.left,
530 touchInfo[i].rcContact.bottom - touchInfo[i].rcContact.top));
531 touchPoint.area.moveCenter(screenPos);
532 QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
533 screenPos.y() / screenGeometry.height());
534 const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
535 touchPoint.normalPosition = normalPosition;
537 if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
538 touchPoint.state = QEventPoint::State::Pressed;
539 m_lastTouchPoints.insert(touchPoint.id, touchPoint);
540 }
else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
541 touchPoint.state = QEventPoint::State::Released;
542 m_lastTouchPoints.remove(touchPoint.id);
544 touchPoint.state = stationaryTouchPoint ? QEventPoint::State::Stationary : QEventPoint::State::Updated;
545 m_lastTouchPoints.insert(touchPoint.id, touchPoint);
547 allStates |= touchPoint.state;
549 touchPoints.append(touchPoint);
550 inputIds.insert(touchPoint.id);
553 SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
558 for (
auto tp : std::as_const(m_lastTouchPoints)) {
559 if (!inputIds.contains(tp.id)) {
560 tp.state = QEventPoint::State::Stationary;
561 allStates |= tp.state;
562 touchPoints.append(tp);
566 if (touchPoints.count() == 0)
570 if (allStates == QEventPoint::State::Released)
571 m_touchInputIDToTouchPointID.clear();
574 QWindowSystemInterface::handleTouchEvent(window, msg.time, m_touchDevice.data(), touchPoints,
575 keyMapper->queryKeyboardModifiers());
579#if QT_CONFIG(tabletevent)
580QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::findTabletDevice(QPointingDevice::PointerType pointerType)
const
582 for (
const auto &d : m_tabletDevices) {
583 if (d->pointerType() == pointerType)
591 MSG msg, PVOID vPenInfo)
593#if QT_CONFIG(tabletevent)
594 if (et & QtWindows::NonClientEventFlag)
597 auto *penInfo =
static_cast<POINTER_PEN_INFO *>(vPenInfo);
600 if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
603 const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
604 const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
605 const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
606 const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
607 / (pRect.right - pRect.left) * (dRect.right - dRect.left),
608 dRect.top + qreal(penInfo->pointerInfo.ptHimetricLocation.y - pRect.top)
609 / (pRect.bottom - pRect.top) * (dRect.bottom - dRect.top));
610 const bool hasPressure = (penInfo->penMask & PEN_MASK_PRESSURE) != 0;
611 const bool hasRotation = (penInfo->penMask & PEN_MASK_ROTATION) != 0;
612 const qreal pressure = hasPressure ? qreal(penInfo->pressure) / 1024.0 : 0.5;
613 const qreal rotation = hasRotation ? qreal(penInfo->rotation) : 0.0;
614 const qreal tangentialPressure = 0.0;
615 const bool hasTiltX = (penInfo->penMask & PEN_MASK_TILT_X) != 0;
616 const bool hasTiltY = (penInfo->penMask & PEN_MASK_TILT_Y) != 0;
617 const int xTilt = hasTiltX ? penInfo->tiltX : 0;
618 const int yTilt = hasTiltY ? penInfo->tiltY : 0;
621 if (QWindowsContext::verbose > 1)
622 qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
623 <<
__FUNCTION__ <<
" systemId=" << systemId
624 <<
" globalPos=" << globalPos <<
" localPos=" << localPos <<
" hiResGlobalPos=" << hiResGlobalPos
625 <<
" message=" << Qt::hex << msg.message
626 <<
" flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags;
628 QPointingDevice::PointerType type;
631 Qt::MouseButtons mouseButtons = queryMouseButtons();
633 const bool pointerInContact = IS_POINTER_INCONTACT_WPARAM(msg.wParam);
634 if (pointerInContact)
635 mouseButtons = Qt::LeftButton;
637 if (penInfo->penFlags & (PEN_FLAG_ERASER | PEN_FLAG_INVERTED)) {
638 type = QPointingDevice::PointerType::Eraser;
640 type = QPointingDevice::PointerType::Pen;
641 if (pointerInContact && penInfo->penFlags & PEN_FLAG_BARREL)
642 mouseButtons = Qt::RightButton;
645 auto device = findTabletDevice(type);
646 if (device.isNull()) {
647 QInputDevice::Capabilities caps(QInputDevice::Capability::Position
648 | QInputDevice::Capability::MouseEmulation
649 | QInputDevice::Capability::Hover);
651 caps |= QInputDevice::Capability::Pressure;
653 caps |= QInputDevice::Capability::Rotation;
655 caps |= QInputDevice::Capability::XTilt;
657 caps |= QInputDevice::Capability::YTilt;
658 const qint64 uniqueId = systemId | (qint64(type) << 32L);
659 device.reset(
new QPointingDevice(QStringLiteral(
"wmpointer"),
660 systemId, QInputDevice::DeviceType::Stylus,
661 type, caps, 1, 3, QString(),
662 QPointingDeviceUniqueId::fromNumericId(uniqueId)));
663 QWindowSystemInterface::registerInputDevice(device.data());
664 m_tabletDevices.append(device);
667 const auto uniqueId = device->uniqueId().numericId();
668 m_activeTabletDevice = device;
670 switch (msg.message) {
671 case WM_POINTERENTER: {
672 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(),
true);
673 m_windowUnderPointer = window;
676 m_needsEnterOnPointerUpdate =
true;
679 case WM_POINTERLEAVE:
680 if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
681 QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
682 m_windowUnderPointer =
nullptr;
683 m_currentWindow =
nullptr;
685 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(),
false);
689 case WM_POINTERUPDATE: {
690 QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target;
691 if (!target && m_windowUnderPointer)
692 target = m_windowUnderPointer;
696 if (m_needsEnterOnPointerUpdate) {
697 m_needsEnterOnPointerUpdate =
false;
698 if (window != m_currentWindow) {
702 QWindowSystemInterface::handleEnterEvent(window, localPos, globalPos);
703 m_currentWindow = window;
704 if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(target))
705 wumPlatformWindow->applyCursor();
708 const auto *keyMapper = QWindowsContext::instance()->keyMapper();
709 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
711 QWindowSystemInterface::handleTabletEvent(target, msg.time, device.data(),
712 localPos, hiResGlobalPos, mouseButtons,
713 pressure, xTilt, yTilt, tangentialPressure,
714 rotation, z, keyModifiers);
733 const LONG_PTR SIGNATURE_MASK = 0xFFFFFF00;
734 const LONG_PTR MI_WP_SIGNATURE = 0xFF515700;
736 return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE);
740 QWindow *currentWindowUnderPointer,
743 Qt::KeyboardModifiers keyModifiers)
745 QWindow *receiver = currentWindowUnderPointer;
751 int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
754 if (msg.message == WM_MOUSEHWHEEL)
757 const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ?
758 QPoint(delta, 0) : QPoint(0, delta);
760 QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
762 QWindowSystemInterface::handleWheelEvent(receiver, msg.time, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
777 QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
780 globalPos = eventPos;
781 localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
783 if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
785 GetClientRect(hwnd, &clientArea);
786 eventPos.setX(clientArea.right - eventPos.x());
789 globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
790 auto targetHwnd = hwnd;
791 if (
auto *pw = window->handle())
792 targetHwnd = HWND(pw->winId());
793 localPos = targetHwnd == hwnd
795 : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
799 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
800 QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
802 if (et == QtWindows::MouseWheelEvent)
803 return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers);
809 bool discardEvent =
false;
810 if (msg.message == WM_MOUSEMOVE) {
811 Q_CONSTINIT
static QPoint lastMouseMovePos;
812 if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
814 lastMouseMovePos = globalPos;
817 Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
825 switch (m_pointerType) {
827 if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
829 source = Qt::MouseEventSynthesizedBySystem;
830 if (!m_touchDevice.isNull())
831 device = m_touchDevice.data();
834#if QT_CONFIG(tabletevent)
835 qCDebug(lcQpaTablet) <<
"ignoring synth-mouse event for tablet event from" << device;
842 const MouseEvent mouseEvent = eventFromMsg(msg);
843 Qt::MouseButtons mouseButtons;
845 if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
846 mouseButtons = queryMouseButtons();
848 mouseButtons = mouseButtonsFromKeyState(msg.wParam);
856 if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
857 && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
858 && (m_lastEventButton & mouseButtons) == 0) {
859 auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
860 QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
861 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons, m_lastEventButton,
862 releaseType, keyModifiers, source);
864 m_lastEventType = mouseEvent.type;
865 m_lastEventButton = mouseEvent.button;
867 if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
868 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
869 mouseEvent.button, mouseEvent.type, keyModifiers, source);
873 if (msg.message == WM_MOUSELEAVE) {
874 if (window == m_currentWindow) {
875 QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow;
876 qCDebug(lcQpaEvents) <<
"Leaving window " << leaveTarget;
877 QWindowSystemInterface::handleLeaveEvent(leaveTarget);
878 m_windowUnderPointer =
nullptr;
879 m_currentWindow =
nullptr;
884 handleWindowActivation(window, mouseEvent.type);
885 handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons);
886 handleEnterLeave(window, currentWindowUnderPointer, globalPos);
888 if (!discardEvent && mouseEvent.type != QEvent::None) {
889 QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
890 mouseEvent.button, mouseEvent.type, keyModifiers, source);
895 return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
896 || 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)