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);
98 static QPointer<const QPointingDevice>
result;
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)
272 const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
274 Qt::MouseButtons buttons;
289 && (m_lastEventButton & buttons) == 0) {
293 releaseType, keyModifiers,
source);
295 m_lastEventType = mouseEvent.
type;
296 m_lastEventButton = mouseEvent.button;
300 globalPosition, buttons,
301 mouseEvent.button, mouseEvent.
type,
307 if (msg.message == WM_MOUSELEAVE) {
308 qCDebug(lcQpaEvents) << mouseEvent <<
"for" <<
window <<
"previous window under mouse="
309 << m_windowUnderMouse <<
"tracked window=" << m_trackedWindow;
314 if (
window == m_trackedWindow) {
315 QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow;
316 qCDebug(lcQpaEvents) <<
"Generating leave event for " << leaveTarget;
318 m_trackedWindow =
nullptr;
319 m_windowUnderMouse =
nullptr;
332 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK) {
333 m_leftButtonDown =
true;
336 if (!m_leftButtonDown && actualLeftDown) {
340 if (!platformWindow->hasMouseCapture()) {
341 platformWindow->applyCursor();
342 platformWindow->setMouseGrabEnabled(
true);
344 qCDebug(lcQpaEvents) <<
"Automatic mouse capture for missing buttondown event" <<
window;
346 m_previousCaptureWindow =
window;
349 if (m_leftButtonDown && !actualLeftDown)
350 m_leftButtonDown =
false;
355 QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
358 currentWindowUnderMouse = currentWindowUnderMouse->parent();
363 if (!currentWindowUnderMouse) {
365 if (clientRect.contains(winEventPosition))
366 currentWindowUnderMouse =
window;
372 if (!platformWindow->hasMouseCapture()
374 platformWindow->setMouseGrabEnabled(
true);
376 qCDebug(lcQpaEvents) <<
"Automatic mouse capture " <<
window;
379 window->requestActivate();
380 }
else if (platformWindow->hasMouseCapture()
384 platformWindow->setMouseGrabEnabled(
false);
385 qCDebug(lcQpaEvents) <<
"Releasing automatic mouse capture " <<
window;
388 const bool hasCapture = platformWindow->hasMouseCapture();
389 const bool currentNotCapturing = hasCapture && currentWindowUnderMouse !=
window;
393 if (
window != m_trackedWindow && !currentNotCapturing) {
395 tme.cbSize =
sizeof(TRACKMOUSEEVENT);
396 tme.dwFlags = TME_LEAVE;
397 tme.hwndTrack = hwnd;
398 tme.dwHoverTime = HOVER_DEFAULT;
399 if (!TrackMouseEvent(&tme))
400 qWarning(
"TrackMouseEvent failed.");
411 if ((m_windowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
412 && (!hasCapture ||
window == m_windowUnderMouse))
413 || (hasCapture && m_previousCaptureWindow !=
window && m_windowUnderMouse
414 && m_windowUnderMouse !=
window)) {
415 qCDebug(lcQpaEvents) <<
"Synthetic leave for " << m_windowUnderMouse;
417 if (currentNotCapturing) {
420 m_trackedWindow =
nullptr;
423 platformWindow->applyCursor();
430 if ((currentWindowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
431 && (!hasCapture || currentWindowUnderMouse ==
window))
432 || (m_previousCaptureWindow &&
window != m_previousCaptureWindow && currentWindowUnderMouse
433 && currentWindowUnderMouse != m_previousCaptureWindow)) {
435 qCDebug(lcQpaEvents) <<
"Entering " << currentWindowUnderMouse;
437 localPosition = wumPlatformWindow->mapFromGlobal(globalPosition);
438 wumPlatformWindow->applyCursor();
445 m_windowUnderMouse = currentWindowUnderMouse;
450 mouseEvent.button, mouseEvent.
type,
453 m_previousCaptureWindow = hasCapture ?
window :
nullptr;
456 return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
483 receiver = receiver->parent();
484 bool handleEvent =
true;
496 globalPos,
QPoint(), point, mods);
500bool QWindowsMouseHandler::translateMouseWheelEvent(
QWindow *
window, HWND,
507 delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
509 delta = int(msg.wParam);
522 const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
537 switch (LOWORD(msg.wParam)) {
565 using QTouchPointList = QList<QWindowSystemInterface::TouchPoint>;
568 qWarning(
"Unable to initialize touch handling.");
579 const int winTouchPointCount = int(msg.wParam);
580 const auto winTouchInputs = std::make_unique<TOUCHINPUT[]>(winTouchPointCount);
582 QTouchPointList touchPoints;
583 touchPoints.reserve(winTouchPointCount);
584 QEventPoint::States allStates;
586 GetTouchInputInfo(
reinterpret_cast<HTOUCHINPUT
>(msg.lParam),
587 UINT(msg.wParam), winTouchInputs.get(),
sizeof(TOUCHINPUT));
588 for (
int i = 0;
i < winTouchPointCount; ++
i) {
589 const TOUCHINPUT &winTouchInput = winTouchInputs[
i];
590 int id = m_touchInputIDToTouchPointID.
value(winTouchInput.dwID, -1);
592 id = m_touchInputIDToTouchPointID.
size();
593 m_touchInputIDToTouchPointID.
insert(winTouchInput.dwID,
id);
595 QTouchPoint touchPoint;
596 touchPoint.pressure = 1.0;
598 if (m_lastTouchPositions.
contains(
id))
599 touchPoint.normalPosition = m_lastTouchPositions.
value(
id);
602 if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
603 touchPoint.area.setSize(
QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) /
qreal(100.));
604 touchPoint.area.moveCenter(screenPos);
606 screenPos.
y() / screenGeometry.
height());
607 const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
608 touchPoint.normalPosition = normalPosition;
610 if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
612 m_lastTouchPositions.
insert(
id, touchPoint.normalPosition);
613 }
else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
615 m_lastTouchPositions.
remove(
id);
617 touchPoint.state = (stationaryTouchPoint
620 m_lastTouchPositions.
insert(
id, touchPoint.normalPosition);
623 allStates |= touchPoint.state;
625 touchPoints.append(touchPoint);
628 CloseTouchInputHandle(
reinterpret_cast<HTOUCHINPUT
>(msg.lParam));
632 m_touchInputIDToTouchPointID.
clear();
637 m_touchDevice.
data(),
639 keyMapper->queryKeyboardModifiers());
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
bool isNull() const noexcept
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.
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::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 MouseEvent eventFromMsg(const MSG &msg)
static void redirectWheelEvent(QWindow *window, unsigned long timestamp, const QPoint &globalPos, int delta, Qt::Orientation orientation, Qt::KeyboardModifiers mods)
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 &)