Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwindowsmousehandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qwindowskeymapper.h"
6#include "qwindowscontext.h"
7#include "qwindowswindow.h"
9#include "qwindowsscreen.h"
10
11#include <qpa/qwindowsysteminterface.h>
12#include <QtGui/qguiapplication.h>
13#include <QtGui/qscreen.h>
14#include <QtGui/qpointingdevice.h>
15#include <QtGui/qwindow.h>
16#include <QtGui/qcursor.h>
17
18#include <QtCore/qdebug.h>
19
20#include <memory>
21
22#include <windowsx.h>
23
25
26static inline void compressMouseMove(MSG *msg)
27{
28 // Compress mouse move events
29 if (msg->message == WM_MOUSEMOVE) {
30 MSG mouseMsg;
31 while (PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEFIRST,
32 WM_MOUSELAST, PM_NOREMOVE)) {
33 if (mouseMsg.message == WM_MOUSEMOVE) {
34#define PEEKMESSAGE_IS_BROKEN 1
35#ifdef PEEKMESSAGE_IS_BROKEN
36 // Since the Windows PeekMessage() function doesn't
37 // correctly return the wParam for WM_MOUSEMOVE events
38 // if there is a key release event in the queue
39 // _before_ the mouse event, we have to also consider
40 // key release events (kls 2003-05-13):
41 MSG keyMsg;
42 bool done = false;
43 while (PeekMessage(&keyMsg, nullptr, WM_KEYFIRST, WM_KEYLAST,
44 PM_NOREMOVE)) {
45 if (keyMsg.time < mouseMsg.time) {
46 if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
47 PeekMessage(&keyMsg, nullptr, keyMsg.message,
48 keyMsg.message, PM_REMOVE);
49 } else {
50 done = true;
51 break;
52 }
53 } else {
54 break; // no key event before the WM_MOUSEMOVE event
55 }
56 }
57 if (done)
58 break;
59#else
60 // Actually the following 'if' should work instead of
61 // the above key event checking, but apparently
62 // PeekMessage() is broken :-(
63 if (mouseMsg.wParam != msg.wParam)
64 break; // leave the message in the queue because
65 // the key state has changed
66#endif
67 // Update the passed in MSG structure with the
68 // most recent one.
69 msg->lParam = mouseMsg.lParam;
70 msg->wParam = mouseMsg.wParam;
71 // Extract the x,y coordinates from the lParam as we do in the WndProc
72 msg->pt.x = GET_X_LPARAM(mouseMsg.lParam);
73 msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
74 clientToScreen(msg->hwnd, &(msg->pt));
75 // Remove the mouse move message
76 PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE,
77 WM_MOUSEMOVE, PM_REMOVE);
78 } else {
79 break; // there was no more WM_MOUSEMOVE event
80 }
81 }
82 }
83}
84
95
97{
99 if (!result)
101 return result;
102}
103
105{
106 m_lastEventType = QEvent::None;
107 m_lastEventButton = Qt::NoButton;
108}
109
111{
112 Qt::MouseButtons result;
113 const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
114 if (GetAsyncKeyState(VK_LBUTTON) < 0)
115 result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
116 if (GetAsyncKeyState(VK_RBUTTON) < 0)
117 result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
118 if (GetAsyncKeyState(VK_MBUTTON) < 0)
120 if (GetAsyncKeyState(VK_XBUTTON1) < 0)
122 if (GetAsyncKeyState(VK_XBUTTON2) < 0)
124 return result;
125}
126
127Q_CONSTINIT static QPoint lastMouseMovePos;
128
129namespace {
130struct MouseEvent {
133};
134
135#ifndef QT_NO_DEBUG_STREAM
137{
138 QDebugStateSaver saver(d);
139 d.nospace();
140 d << "MouseEvent(" << e.type << ", " << e.button << ')';
141 return d;
142}
143#endif // QT_NO_DEBUG_STREAM
144} // namespace
145
146static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON...
147{
148 return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
149}
150
151static inline MouseEvent eventFromMsg(const MSG &msg)
152{
153 switch (msg.message) {
154 case WM_MOUSEMOVE:
156 case WM_LBUTTONDOWN:
158 case WM_LBUTTONUP:
160 case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
162 case WM_MBUTTONDOWN:
164 case WM_MBUTTONUP:
166 case WM_MBUTTONDBLCLK:
168 case WM_RBUTTONDOWN:
170 case WM_RBUTTONUP:
172 case WM_RBUTTONDBLCLK:
174 case WM_XBUTTONDOWN:
175 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
176 case WM_XBUTTONUP:
177 return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
178 case WM_XBUTTONDBLCLK:
179 return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
180 case WM_NCMOUSEMOVE:
182 case WM_NCLBUTTONDOWN:
184 case WM_NCLBUTTONUP:
186 case WM_NCLBUTTONDBLCLK:
188 case WM_NCMBUTTONDOWN:
190 case WM_NCMBUTTONUP:
192 case WM_NCMBUTTONDBLCLK:
194 case WM_NCRBUTTONDOWN:
196 case WM_NCRBUTTONUP:
198 case WM_NCRBUTTONDBLCLK:
200 default: // WM_MOUSELEAVE
201 break;
202 }
203 return {QEvent::None, Qt::NoButton};
204}
205
208 MSG msg, LRESULT *result)
209{
210 enum : quint64 { signatureMask = 0xffffff00, miWpSignature = 0xff515700 };
211
213 return translateMouseWheelEvent(window, hwnd, msg, result);
214
215 QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
217 RECT clientArea;
218 GetClientRect(hwnd, &clientArea);
219 winEventPosition.setX(clientArea.right - winEventPosition.x());
220 }
221
222 QPoint clientPosition;
223 QPoint globalPosition;
225 globalPosition = winEventPosition;
226 clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
227 } else {
228 globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
229 auto targetHwnd = hwnd;
230 if (auto *pw = window->handle())
231 targetHwnd = HWND(pw->winId());
232 clientPosition = targetHwnd == hwnd
233 ? winEventPosition
234 : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPosition);
235 }
236
237 // Windows sends a mouse move with no buttons pressed to signal "Enter"
238 // when a window is shown over the cursor. Discard the event and only use
239 // it for generating QEvent::Enter to be consistent with other platforms -
240 // X11 and macOS.
241 bool discardEvent = false;
242 if (msg.message == WM_MOUSEMOVE) {
243 const bool samePosition = globalPosition == lastMouseMovePos;
244 lastMouseMovePos = globalPosition;
245 if (msg.wParam == 0 && (m_windowUnderMouse.isNull() || samePosition))
246 discardEvent = true;
247 }
248
250
252
253 // Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
254 static const bool passSynthesizedMouseEvents =
256 // Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch.
257 // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem
258 // since we do not want to ignore mouse events coming from a tablet.
259 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx
260 const auto extraInfo = quint64(GetMessageExtraInfo());
261 if ((extraInfo & signatureMask) == miWpSignature) {
262 if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen.
264 if (!m_touchDevice.isNull())
265 device = m_touchDevice.data();
266 if (!passSynthesizedMouseEvents)
267 return false;
268 }
269 }
270
271 const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
272 const MouseEvent mouseEvent = eventFromMsg(msg);
273 Qt::MouseButtons buttons;
274
276 buttons = queryMouseButtons();
277 else
278 buttons = keyStateToMouseButtons(msg.wParam);
279
280 // When the left/right mouse buttons are pressed over the window title bar
281 // WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP
282 // messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE.
283 // We detect it and generate the missing release events here. (QTBUG-75678)
284 // The last event vars are cleared on QWindowsContext::handleExitSizeMove()
285 // to avoid generating duplicated release events.
286 if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
287 && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
288 && (m_lastEventButton & buttons) == 0) {
289 auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
291 QWindowSystemInterface::handleMouseEvent(window, device, clientPosition, globalPosition, buttons, m_lastEventButton,
292 releaseType, keyModifiers, source);
293 }
294 m_lastEventType = mouseEvent.type;
295 m_lastEventButton = mouseEvent.button;
296
299 globalPosition, buttons,
300 mouseEvent.button, mouseEvent.type,
301 keyModifiers, source);
302 return false; // Allow further event processing (dragging of windows).
303 }
304
305 *result = 0;
306 if (msg.message == WM_MOUSELEAVE) {
307 qCDebug(lcQpaEvents) << mouseEvent << "for" << window << "previous window under mouse="
308 << m_windowUnderMouse << "tracked window=" << m_trackedWindow;
309
310 // When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first,
311 // so if m_trackedWindow is not the window here, it means the cursor has left the
312 // application.
313 if (window == m_trackedWindow) {
314 QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow;
315 qCDebug(lcQpaEvents) << "Generating leave event for " << leaveTarget;
317 m_trackedWindow = nullptr;
318 m_windowUnderMouse = nullptr;
319 }
320 return true;
321 }
322
323 auto *platformWindow = static_cast<QWindowsWindow *>(window->handle());
324
325 // If the window was recently resized via mouse double-click on the frame or title bar,
326 // we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click,
327 // but we will get at least one WM_MOUSEMOVE with left button down and the WM_LBUTTONUP,
328 // which will result undesired mouse press and release events.
329 // To avoid those, we ignore any events with left button down if we didn't
330 // get the original WM_LBUTTONDOWN/WM_LBUTTONDBLCLK.
331 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK) {
332 m_leftButtonDown = true;
333 } else {
334 const bool actualLeftDown = buttons & Qt::LeftButton;
335 if (!m_leftButtonDown && actualLeftDown) {
336 // Autocapture the mouse for current window to and ignore further events until release.
337 // Capture is necessary so we don't get WM_MOUSELEAVEs to confuse matters.
338 // This autocapture is released normally when button is released.
339 if (!platformWindow->hasMouseCapture()) {
340 platformWindow->applyCursor();
341 platformWindow->setMouseGrabEnabled(true);
342 platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
343 qCDebug(lcQpaEvents) << "Automatic mouse capture for missing buttondown event" << window;
344 }
345 m_previousCaptureWindow = window;
346 return true;
347 }
348 if (m_leftButtonDown && !actualLeftDown)
349 m_leftButtonDown = false;
350 }
351
352 // In this context, neither an invisible nor a transparent window (transparent regarding mouse
353 // events, "click-through") can be considered as the window under mouse.
354 QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
355 QWindowsScreen::windowAt(globalPosition, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window;
356 while (currentWindowUnderMouse && currentWindowUnderMouse->flags() & Qt::WindowTransparentForInput)
357 currentWindowUnderMouse = currentWindowUnderMouse->parent();
358 // QTBUG-44332: When Qt is running at low integrity level and
359 // a Qt Window is parented on a Window of a higher integrity process
360 // using QWindow::fromWinId() (for example, Qt running in a browser plugin)
361 // ChildWindowFromPointEx() may not find the Qt window (failing with ERROR_ACCESS_DENIED)
362 if (!currentWindowUnderMouse) {
363 const QRect clientRect(QPoint(0, 0), window->size());
364 if (clientRect.contains(winEventPosition))
365 currentWindowUnderMouse = window;
366 }
367
368 compressMouseMove(&msg);
369 // Qt expects the platform plugin to capture the mouse on
370 // any button press until release.
371 if (!platformWindow->hasMouseCapture()
372 && (mouseEvent.type == QEvent::MouseButtonPress || mouseEvent.type == QEvent::MouseButtonDblClick)) {
373 platformWindow->setMouseGrabEnabled(true);
374 platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
375 qCDebug(lcQpaEvents) << "Automatic mouse capture " << window;
376 // Implement "Click to focus" for native child windows (unless it is a native widget window).
377 if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window)
378 window->requestActivate();
379 } else if (platformWindow->hasMouseCapture()
380 && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
381 && mouseEvent.type == QEvent::MouseButtonRelease
382 && !buttons) {
383 platformWindow->setMouseGrabEnabled(false);
384 qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window;
385 }
386
387 const bool hasCapture = platformWindow->hasMouseCapture();
388 const bool currentNotCapturing = hasCapture && currentWindowUnderMouse != window;
389 // Enter new window: track to generate leave event.
390 // If there is an active capture, only track if the current window is capturing,
391 // so we don't get extra leave when cursor leaves the application.
392 if (window != m_trackedWindow && !currentNotCapturing) {
393 TRACKMOUSEEVENT tme;
394 tme.cbSize = sizeof(TRACKMOUSEEVENT);
395 tme.dwFlags = TME_LEAVE;
396 tme.hwndTrack = hwnd;
397 tme.dwHoverTime = HOVER_DEFAULT; //
398 if (!TrackMouseEvent(&tme))
399 qWarning("TrackMouseEvent failed.");
400 m_trackedWindow = window;
401 }
402
403 // No enter or leave events are sent as long as there is an autocapturing window.
404 if (!hasCapture || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) {
405 // Leave is needed if:
406 // 1) There is no capture and we move from a window to another window.
407 // Note: Leaving the application entirely is handled in WM_MOUSELEAVE case.
408 // 2) There is capture and we move out of the capturing window.
409 // 3) There is a new capture and we were over another window.
410 if ((m_windowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
411 && (!hasCapture || window == m_windowUnderMouse))
412 || (hasCapture && m_previousCaptureWindow != window && m_windowUnderMouse
413 && m_windowUnderMouse != window)) {
414 qCDebug(lcQpaEvents) << "Synthetic leave for " << m_windowUnderMouse;
416 if (currentNotCapturing) {
417 // Clear tracking if capturing and current window is not the capturing window
418 // to avoid leave when mouse actually leaves the application.
419 m_trackedWindow = nullptr;
420 // We are not officially in any window, but we need to set some cursor to clear
421 // whatever cursor the left window had, so apply the cursor of the capture window.
422 platformWindow->applyCursor();
423 }
424 }
425 // Enter is needed if:
426 // 1) There is no capture and we move to a new window.
427 // 2) There is capture and we move into the capturing window.
428 // 3) The capture just ended and we are over non-capturing window.
429 if ((currentWindowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
430 && (!hasCapture || currentWindowUnderMouse == window))
431 || (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse
432 && currentWindowUnderMouse != m_previousCaptureWindow)) {
433 QPoint localPosition;
434 qCDebug(lcQpaEvents) << "Entering " << currentWindowUnderMouse;
435 if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderMouse)) {
436 localPosition = wumPlatformWindow->mapFromGlobal(globalPosition);
437 wumPlatformWindow->applyCursor();
438 }
439 QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse, localPosition, globalPosition);
440 }
441 // We need to track m_windowUnderMouse separately from m_trackedWindow, as
442 // Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when
443 // mouse capture is set.
444 m_windowUnderMouse = currentWindowUnderMouse;
445 }
446
447 if (!discardEvent && mouseEvent.type != QEvent::None) {
448 QWindowSystemInterface::handleMouseEvent(window, device, clientPosition, globalPosition, buttons,
449 mouseEvent.button, mouseEvent.type,
450 keyModifiers, source);
451 }
452 m_previousCaptureWindow = hasCapture ? window : nullptr;
453 // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
454 // is sent for unhandled WM_XBUTTONDOWN.
455 return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
457}
458
459static bool isValidWheelReceiver(QWindow *candidate)
460{
461 if (candidate) {
462 const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate);
463 if (toplevel->handle() && toplevel->handle()->isForeignWindow())
464 return true;
465 if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel))
466 return !ww->testFlag(QWindowsWindow::BlockedByModal);
467 }
468
469 return false;
470}
471
472static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int delta,
473 Qt::Orientation orientation, Qt::KeyboardModifiers mods)
474{
475 // Redirect wheel event to one of the following, in order of preference:
476 // 1) The window under mouse
477 // 2) The window receiving the event
478 // If a window is blocked by modality, it can't get the event.
479
480 QWindow *receiver = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE);
481 while (receiver && receiver->flags().testFlag(Qt::WindowTransparentForInput))
482 receiver = receiver->parent();
483 bool handleEvent = true;
484 if (!isValidWheelReceiver(receiver)) {
485 receiver = window;
486 if (!isValidWheelReceiver(receiver))
487 handleEvent = false;
488 }
489
490 if (handleEvent) {
491 const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0);
493 QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
494 globalPos, QPoint(), point, mods);
495 }
496}
497
498bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
499 MSG msg, LRESULT *)
500{
501 const Qt::KeyboardModifiers mods = keyStateToModifiers(int(msg.wParam));
502
503 int delta;
504 if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
505 delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
506 else
507 delta = int(msg.wParam);
508
509 Qt::Orientation orientation = (msg.message == WM_MOUSEHWHEEL
510 || (mods & Qt::AltModifier)) ?
512
513 // according to the MSDN documentation on WM_MOUSEHWHEEL:
514 // a positive value indicates that the wheel was rotated to the right;
515 // a negative value indicates that the wheel was rotated to the left.
516 // Qt defines this value as the exact opposite, so we have to flip the value!
517 if (msg.message == WM_MOUSEHWHEEL)
518 delta = -delta;
519
520 const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
521 redirectWheelEvent(window, globalPos, delta, orientation, mods);
522
523 return true;
524}
525
527 MSG msg, LRESULT *)
528{
529 // This is a workaround against some touchpads that send WM_HSCROLL instead of WM_MOUSEHWHEEL.
530 // We could also handle vertical scroll here but there's no reason to, there's no bug for vertical
531 // (broken vertical scroll would have been noticed long time ago), so lets keep the change small
532 // and minimize the chance for regressions.
533
534 int delta = 0;
535 switch (LOWORD(msg.wParam)) {
536 case SB_LINELEFT:
537 delta = 120;
538 break;
539 case SB_LINERIGHT:
540 delta = -120;
541 break;
542 case SB_PAGELEFT:
543 delta = 240;
544 break;
545 case SB_PAGERIGHT:
546 delta = -240;
547 break;
548 default:
549 return false;
550 }
551
553
554 return true;
555}
556
557// from bool QApplicationPrivate::translateTouchEvent()
560 MSG msg, LRESULT *)
561{
562 using QTouchPoint = QWindowSystemInterface::TouchPoint;
563 using QTouchPointList = QList<QWindowSystemInterface::TouchPoint>;
564
565 if (!QWindowsContext::instance()->initTouch()) {
566 qWarning("Unable to initialize touch handling.");
567 return true;
568 }
569
570 const QScreen *screen = window->screen();
571 if (!screen)
573 if (!screen)
574 return true;
575 const QRect screenGeometry = screen->geometry();
576
577 const int winTouchPointCount = int(msg.wParam);
578 const auto winTouchInputs = std::make_unique<TOUCHINPUT[]>(winTouchPointCount);
579
580 QTouchPointList touchPoints;
581 touchPoints.reserve(winTouchPointCount);
582 QEventPoint::States allStates;
583
584 GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(msg.lParam),
585 UINT(msg.wParam), winTouchInputs.get(), sizeof(TOUCHINPUT));
586 for (int i = 0; i < winTouchPointCount; ++i) {
587 const TOUCHINPUT &winTouchInput = winTouchInputs[i];
588 int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1);
589 if (id == -1) {
590 id = m_touchInputIDToTouchPointID.size();
591 m_touchInputIDToTouchPointID.insert(winTouchInput.dwID, id);
592 }
593 QTouchPoint touchPoint;
594 touchPoint.pressure = 1.0;
595 touchPoint.id = id;
596 if (m_lastTouchPositions.contains(id))
597 touchPoint.normalPosition = m_lastTouchPositions.value(id);
598
599 const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) / qreal(100.);
600 if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
601 touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) / qreal(100.));
602 touchPoint.area.moveCenter(screenPos);
603 QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
604 screenPos.y() / screenGeometry.height());
605 const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
606 touchPoint.normalPosition = normalPosition;
607
608 if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
609 touchPoint.state = QEventPoint::State::Pressed;
610 m_lastTouchPositions.insert(id, touchPoint.normalPosition);
611 } else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
612 touchPoint.state = QEventPoint::State::Released;
613 m_lastTouchPositions.remove(id);
614 } else {
615 touchPoint.state = (stationaryTouchPoint
618 m_lastTouchPositions.insert(id, touchPoint.normalPosition);
619 }
620
621 allStates |= touchPoint.state;
622
623 touchPoints.append(touchPoint);
624 }
625
626 CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(msg.lParam));
627
628 // all touch points released, forget the ids we've seen, they may not be reused
629 if (allStates == QEventPoint::State::Released)
630 m_touchInputIDToTouchPointID.clear();
631
633 m_touchDevice.data(),
634 touchPoints,
636 return true;
637}
638
641 MSG msg, LRESULT *)
642{
644 Q_UNUSED(hwnd);
645 Q_UNUSED(msg);
646 return false;
647}
648
IOBluetoothDevice * device
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
\inmodule QtCore
\inmodule QtCore
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ NonClientAreaMouseButtonDblClick
Definition qcoreevent.h:215
@ MouseMove
Definition qcoreevent.h:63
@ MouseButtonPress
Definition qcoreevent.h:60
@ NonClientAreaMouseMove
Definition qcoreevent.h:212
@ NonClientAreaMouseButtonRelease
Definition qcoreevent.h:214
@ MouseButtonDblClick
Definition qcoreevent.h:62
@ NonClientAreaMouseButtonPress
Definition qcoreevent.h:213
@ MouseButtonRelease
Definition qcoreevent.h:61
QScreen * primaryScreen
the primary (or default) screen of the application.
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
T value(const Key &key) const noexcept
Definition qhash.h:1044
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
Definition qlist.h:74
virtual bool isForeignWindow() const
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr void setX(int x) noexcept
Sets the x coordinate of this point to the given x coordinate.
Definition qpoint.h:137
\inmodule QtCore
Definition qpointer.h:18
bool isNull() const
Returns true if the referenced object has been destroyed or if there is no referenced object; otherwi...
Definition qpointer.h:67
The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
static const QPointingDevice * primaryPointingDevice(const QString &seatName=QString())
Returns the primary pointing device (the core pointer, traditionally assumed to be a mouse) on the gi...
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
\inmodule QtCore
Definition qsize.h:207
static bool handleTouchEvent(QWindow *window, const QPointingDevice *device, const QList< struct TouchPoint > &points, Qt::KeyboardModifiers mods=Qt::NoModifier)
static bool flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Make Qt Gui process all events on the event queue immediately.
static void handleLeaveEvent(QWindow *window)
static bool handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods=Qt::NoModifier, Qt::MouseEventSource source=Qt::MouseEventNotSynthesized)
static void handleEnterEvent(QWindow *window, const QPointF &local=QPointF(), const QPointF &global=QPointF())
static bool handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods=Qt::NoModifier, Qt::ScrollPhase phase=Qt::NoScrollPhase, Qt::MouseEventSource source=Qt::MouseEventNotSynthesized)
\inmodule QtGui
Definition qwindow.h:63
Qt::WindowFlags flags
the window flags of the window
Definition qwindow.h:79
static bool isRtlLayout(HWND hwnd)
static QWindowsContext * instance()
static QWindowsIntegration * instance()
static Qt::KeyboardModifiers queryKeyboardModifiers()
static Qt::MouseButtons queryMouseButtons()
bool translateScrollEvent(QWindow *window, HWND hwnd, MSG msg, LRESULT *result)
bool translateTouchEvent(QWindow *widget, HWND hwnd, QtWindows::WindowsEventType t, MSG msg, LRESULT *result)
static Qt::KeyboardModifiers keyStateToModifiers(int)
static Qt::MouseButtons keyStateToMouseButtons(WPARAM)
bool translateGestureEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType, MSG msg, LRESULT *)
static const QPointingDevice * primaryMouse()
bool translateMouseEvent(QWindow *widget, HWND hwnd, QtWindows::WindowsEventType t, MSG msg, LRESULT *result)
static QWindow * windowAt(const QPoint &point, unsigned flags)
Raster or OpenGL Window.
static QWindowsWindow * windowsWindowOf(const QWindow *w)
static QWindow * topLevelOf(QWindow *w)
QPushButton * button
[2]
double e
Combined button and popup list for selecting options.
WindowsEventType
Enumerations for WM_XX events.
MouseButton
Definition qnamespace.h:55
@ LeftButton
Definition qnamespace.h:57
@ BackButton
Definition qnamespace.h:60
@ RightButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:59
@ ForwardButton
Definition qnamespace.h:63
@ XButton2
Definition qnamespace.h:64
@ NoButton
Definition qnamespace.h:56
@ XButton1
Definition qnamespace.h:61
Orientation
Definition qnamespace.h:97
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
MouseEventSource
@ MouseEventSynthesizedBySystem
@ MouseEventNotSynthesized
@ NoModifier
@ AltModifier
@ WindowTransparentForInput
Definition qnamespace.h:233
#define qWarning
Definition qlogging.h:162
#define qCDebug(category,...)
GLenum GLuint id
[7]
GLsizei GLsizei GLchar * source
GLuint64EXT * result
[6]
#define WM_MOUSEHWHEEL
Definition qt_windows.h:80
#define WM_MOUSEWHEEL
Definition qt_windows.h:77
QScreen * screen
[1]
Definition main.cpp:29
#define Q_UNUSED(x)
unsigned long long quint64
Definition qtypes.h:56
double qreal
Definition qtypes.h:92
struct tagMSG MSG
static bool isValidWheelReceiver(QWindow *candidate)
static Q_CONSTINIT QPoint lastMouseMovePos
static Qt::MouseButton extraButton(WPARAM wParam)
static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int delta, Qt::Orientation orientation, Qt::KeyboardModifiers mods)
static MouseEvent eventFromMsg(const MSG &msg)
static QT_BEGIN_NAMESPACE void compressMouseMove(MSG *msg)
static void clientToScreen(HWND hwnd, POINT *wP)
QDataStream & operator<<(QDataStream &out, const MyClass &myObj)
[4]
aWidget window() -> setWindowTitle("New Window Title")
[2]
EventType type
Definition qwasmevent.h:129
static QPoint mapToGlobal(HWND hwnd, const QPoint &)
static QPoint mapFromGlobal(const HWND hwnd, const QPoint &)