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>
18#include <QtCore/qdebug.h>
29 if (msg->message == WM_MOUSEMOVE) {
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
43 while (PeekMessage(&keyMsg,
nullptr, WM_KEYFIRST, WM_KEYLAST,
45 if (keyMsg.time < mouseMsg.time) {
46 if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
47 PeekMessage(&keyMsg,
nullptr, keyMsg.message,
48 keyMsg.message, PM_REMOVE);
63 if (mouseMsg.wParam != msg.wParam)
69 msg->lParam = mouseMsg.lParam;
70 msg->wParam = mouseMsg.wParam;
72 msg->pt.x = GET_X_LPARAM(mouseMsg.lParam);
73 msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
76 PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE,
77 WM_MOUSEMOVE, PM_REMOVE);
113 const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
114 if (GetAsyncKeyState(VK_LBUTTON) < 0)
116 if (GetAsyncKeyState(VK_RBUTTON) < 0)
118 if (GetAsyncKeyState(VK_MBUTTON) < 0)
120 if (GetAsyncKeyState(VK_XBUTTON1) < 0)
122 if (GetAsyncKeyState(VK_XBUTTON2) < 0)
135#ifndef QT_NO_DEBUG_STREAM
140 d <<
"MouseEvent(" <<
e.type <<
", " <<
e.button <<
')';
153 switch (msg.message) {
160 case WM_LBUTTONDBLCLK:
166 case WM_MBUTTONDBLCLK:
172 case WM_RBUTTONDBLCLK:
178 case WM_XBUTTONDBLCLK:
182 case WM_NCLBUTTONDOWN:
186 case WM_NCLBUTTONDBLCLK:
188 case WM_NCMBUTTONDOWN:
192 case WM_NCMBUTTONDBLCLK:
194 case WM_NCRBUTTONDOWN:
198 case WM_NCRBUTTONDBLCLK:
210 enum :
quint64 { signatureMask = 0xffffff00, miWpSignature = 0xff515700 };
213 return translateMouseWheelEvent(
window, hwnd, msg,
result);
215 QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
218 GetClientRect(hwnd, &clientArea);
219 winEventPosition.
setX(clientArea.right - winEventPosition.
x());
225 globalPosition = winEventPosition;
229 auto targetHwnd = hwnd;
230 if (
auto *pw =
window->handle())
231 targetHwnd = HWND(pw->winId());
232 clientPosition = targetHwnd == hwnd
241 bool discardEvent =
false;
242 if (msg.message == WM_MOUSEMOVE) {
245 if (msg.wParam == 0 && (m_windowUnderMouse.
isNull() || samePosition))
254 static const bool passSynthesizedMouseEvents =
260 const auto extraInfo =
quint64(GetMessageExtraInfo());
261 if ((extraInfo & signatureMask) == miWpSignature) {
262 if (extraInfo & 0x80) {
264 if (!m_touchDevice.
isNull())
266 if (!passSynthesizedMouseEvents)
273 Qt::MouseButtons buttons;
288 && (m_lastEventButton & buttons) == 0) {
292 releaseType, keyModifiers,
source);
294 m_lastEventType = mouseEvent.
type;
295 m_lastEventButton = mouseEvent.button;
299 globalPosition, buttons,
300 mouseEvent.button, mouseEvent.
type,
306 if (msg.message == WM_MOUSELEAVE) {
307 qCDebug(lcQpaEvents) << mouseEvent <<
"for" <<
window <<
"previous window under mouse="
308 << m_windowUnderMouse <<
"tracked window=" << m_trackedWindow;
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;
331 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK) {
332 m_leftButtonDown =
true;
335 if (!m_leftButtonDown && actualLeftDown) {
339 if (!platformWindow->hasMouseCapture()) {
340 platformWindow->applyCursor();
341 platformWindow->setMouseGrabEnabled(
true);
343 qCDebug(lcQpaEvents) <<
"Automatic mouse capture for missing buttondown event" <<
window;
345 m_previousCaptureWindow =
window;
348 if (m_leftButtonDown && !actualLeftDown)
349 m_leftButtonDown =
false;
354 QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
357 currentWindowUnderMouse = currentWindowUnderMouse->parent();
362 if (!currentWindowUnderMouse) {
364 if (clientRect.
contains(winEventPosition))
365 currentWindowUnderMouse =
window;
371 if (!platformWindow->hasMouseCapture()
373 platformWindow->setMouseGrabEnabled(
true);
375 qCDebug(lcQpaEvents) <<
"Automatic mouse capture " <<
window;
378 window->requestActivate();
379 }
else if (platformWindow->hasMouseCapture()
383 platformWindow->setMouseGrabEnabled(
false);
384 qCDebug(lcQpaEvents) <<
"Releasing automatic mouse capture " <<
window;
387 const bool hasCapture = platformWindow->hasMouseCapture();
388 const bool currentNotCapturing = hasCapture && currentWindowUnderMouse !=
window;
392 if (
window != m_trackedWindow && !currentNotCapturing) {
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.");
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) {
419 m_trackedWindow =
nullptr;
422 platformWindow->applyCursor();
429 if ((currentWindowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
430 && (!hasCapture || currentWindowUnderMouse ==
window))
431 || (m_previousCaptureWindow &&
window != m_previousCaptureWindow && currentWindowUnderMouse
432 && currentWindowUnderMouse != m_previousCaptureWindow)) {
434 qCDebug(lcQpaEvents) <<
"Entering " << currentWindowUnderMouse;
436 localPosition = wumPlatformWindow->mapFromGlobal(globalPosition);
437 wumPlatformWindow->applyCursor();
444 m_windowUnderMouse = currentWindowUnderMouse;
449 mouseEvent.button, mouseEvent.
type,
452 m_previousCaptureWindow = hasCapture ?
window :
nullptr;
455 return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
482 receiver = receiver->parent();
483 bool handleEvent =
true;
494 globalPos,
QPoint(), point, mods);
498bool QWindowsMouseHandler::translateMouseWheelEvent(
QWindow *
window, HWND,
505 delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
507 delta = int(msg.wParam);
520 const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
535 switch (LOWORD(msg.wParam)) {
566 qWarning(
"Unable to initialize touch handling.");
577 const int winTouchPointCount = int(msg.wParam);
578 const auto winTouchInputs = std::make_unique<TOUCHINPUT[]>(winTouchPointCount);
580 QTouchPointList touchPoints;
581 touchPoints.reserve(winTouchPointCount);
582 QEventPoint::States allStates;
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);
590 id = m_touchInputIDToTouchPointID.
size();
591 m_touchInputIDToTouchPointID.
insert(winTouchInput.dwID,
id);
593 QTouchPoint touchPoint;
594 touchPoint.pressure = 1.0;
596 if (m_lastTouchPositions.
contains(
id))
597 touchPoint.normalPosition = m_lastTouchPositions.
value(
id);
600 if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
601 touchPoint.area.setSize(
QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) /
qreal(100.));
602 touchPoint.area.moveCenter(screenPos);
604 screenPos.
y() / screenGeometry.
height());
605 const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
606 touchPoint.normalPosition = normalPosition;
608 if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
610 m_lastTouchPositions.
insert(
id, touchPoint.normalPosition);
611 }
else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
613 m_lastTouchPositions.
remove(
id);
615 touchPoint.state = (stationaryTouchPoint
618 m_lastTouchPositions.
insert(
id, touchPoint.normalPosition);
621 allStates |= touchPoint.state;
623 touchPoints.append(touchPoint);
626 CloseTouchInputHandle(
reinterpret_cast<HTOUCHINPUT
>(msg.lParam));
630 m_touchInputIDToTouchPointID.
clear();
633 m_touchDevice.
data(),
IOBluetoothDevice * device
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Type
This enum type defines the valid event types in Qt.
@ NonClientAreaMouseButtonDblClick
@ NonClientAreaMouseButtonRelease
@ NonClientAreaMouseButtonPress
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.
qsizetype size() const noexcept
Returns the number of items in the hash.
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
T value(const Key &key) const noexcept
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
\inmodule QtCore\reentrant
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
\inmodule QtCore\reentrant
constexpr int x() const noexcept
Returns the x coordinate of this point.
constexpr void setX(int x) noexcept
Sets the x coordinate of this point to the given x coordinate.
bool isNull() const
Returns true if the referenced object has been destroyed or if there is no referenced object; otherwi...
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
constexpr int height() const noexcept
Returns the height of the rectangle.
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...
constexpr int width() const noexcept
Returns the width of the rectangle.
The QScreen class is used to query screen properties. \inmodule QtGui.
QRect geometry
the screen's geometry in pixels
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.
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)
Qt::WindowFlags flags
the window flags of the window
static bool isRtlLayout(HWND hwnd)
static QWindowsContext * instance()
@ DontPassOsMouseEventsSynthesizedFromTouch
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)
static QWindowsWindow * windowsWindowOf(const QWindow *w)
static QWindow * topLevelOf(QWindow *w)
Combined button and popup list for selecting options.
WindowsEventType
Enumerations for WM_XX events.
@ MouseEventSynthesizedBySystem
@ MouseEventNotSynthesized
@ WindowTransparentForInput
#define qCDebug(category,...)
GLsizei GLsizei GLchar * source
unsigned long long quint64
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)
static QPoint mapToGlobal(HWND hwnd, const QPoint &)
static QPoint mapFromGlobal(const HWND hwnd, const QPoint &)