Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosnativemouseeventshandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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
4#include <QtCore/private/qohoscommon_p.h>
5#include <chrono>
6#include <cstdint>
7#include <functional>
8#include <optional>
9#include <qarkui/input.h>
10#include <render/qohosbatchingrequestshandler.h>
11#include <render/qohosnativemouseeventshandler.h>
12#include <vector>
13
14namespace ch = std::chrono;
15
16QT_BEGIN_NAMESPACE
17
18namespace {
19
20constexpr auto mouseMotionEventMinAgeForDrop = ch::milliseconds(20);
21
23{
24 switch (button) {
25 case ::UI_MOUSE_EVENT_BUTTON_NONE:
26 return {};
27 case ::UI_MOUSE_EVENT_BUTTON_LEFT:
28 return Qt::LeftButton;
29 case ::UI_MOUSE_EVENT_BUTTON_RIGHT:
30 return Qt::RightButton;
31 case ::UI_MOUSE_EVENT_BUTTON_MIDDLE:
32 return Qt::MiddleButton;
33 case ::UI_MOUSE_EVENT_BUTTON_BACK:
34 return Qt::BackButton;
35 case ::UI_MOUSE_EVENT_BUTTON_FORWARD:
36 return Qt::ForwardButton;
37 }
38
39 return {};
40};
41
43{
44 switch (action) {
45 case ::UI_MOUSE_EVENT_ACTION_UNKNOWN:
46 return {};
47 case ::UI_MOUSE_EVENT_ACTION_PRESS:
48 return QEvent::MouseButtonPress;
49 case ::UI_MOUSE_EVENT_ACTION_RELEASE:
50 return QEvent::MouseButtonRelease;
51 case ::UI_MOUSE_EVENT_ACTION_MOVE:
52 return QEvent::MouseMove;
53 }
54
55 return {};
56}
57
58class QOhosNativeNodeMouseInputHandler final : public std::enable_shared_from_this<QOhosNativeNodeMouseInputHandler>
59{
60public:
62 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
63 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef,
64 std::shared_ptr<QOhosHoverEventsGenerator> hoverEventsGenerator);
65
66 void handleMouseEvent(QArkUi::NativeNodeMouseEvent nativeNodeMouseEvent);
67
68private:
69 struct MouseEvent
70 {
71 ch::steady_clock::time_point timestamp;
72 QOhosMouseEvent mouseEvent;
73 };
74
75 void processMouseEventsInQtThread(std::vector<MouseEvent> &&batch);
76
77 static bool mayDropMouseEvent(
78 ch::steady_clock::time_point now, const MouseEvent &event, const MouseEvent &nextEvent);
79
80 QtOhos::QThreadSafeRef<QWindow> m_qWindowRef;
81 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> m_imEventHandlerRef;
82 std::shared_ptr<QOhosHoverEventsGenerator> m_hoverEventsGenerator;
83
84 std::function<void(std::function<void(std::vector<MouseEvent> &)>)> m_optMouseEventsHandler;
85};
86
87QOhosNativeNodeMouseInputHandler::QOhosNativeNodeMouseInputHandler(
88 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
89 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef,
90 std::shared_ptr<QOhosHoverEventsGenerator> hoverEventsGenerator)
94{
95}
96
97void QOhosNativeNodeMouseInputHandler::handleMouseEvent(QArkUi::NativeNodeMouseEvent nativeNodeMouseEvent)
98{
99 auto eventType = tryMapNativeNodeMouseActionToQt(nativeNodeMouseEvent.action);
100 if (!eventType.has_value()) {
101 qOhosPrintfDebug(
102 "%s: got unsupported action in mouse event (%d), ignoring",
103 Q_FUNC_INFO, nativeNodeMouseEvent.action);
104 return;
105 }
106
107 QOhosMouseEvent mouseEvent = {
108 .targetWindow = {},
109 .timestampMs = nativeNodeMouseEvent.timestampMs,
110 .localPosition = nativeNodeMouseEvent.localPosition,
111 .globalPosition = nativeNodeMouseEvent.globalPosition,
112 .button = tryMapNativeNodeMouseButtonToQt(nativeNodeMouseEvent.button).value_or(Qt::NoButton),
113 .eventType = eventType.value(),
114 .modifiers = nativeNodeMouseEvent.modifiers,
115 .deviceType = nativeNodeMouseEvent.deviceType,
116 };
117
118 m_hoverEventsGenerator->handleQOhosMouseEvent(mouseEvent);
119
120 if (!m_optMouseEventsHandler) {
121 auto weakSelf = QtOhos::makeWeakPtr(shared_from_this());
122 m_optMouseEventsHandler = makeQtOhosBatchingQtRequestsHandler<std::vector<MouseEvent>>(
123 m_imEventHandlerRef.toQObjectThreadSafeRef(),
124 [weakSelf](std::vector<MouseEvent> &&batch) {
125 auto sharedSelf = weakSelf.lock();
126 if (sharedSelf)
127 sharedSelf->processMouseEventsInQtThread(std::move(batch));
128 });
129 }
130
131 m_optMouseEventsHandler(
132 [&](std::vector<MouseEvent> &batch) {
133 auto now = std::chrono::steady_clock::now();
134 MouseEvent newEvent{now, mouseEvent};
135 if (!batch.empty() && mayDropMouseEvent(now, batch.back(), newEvent))
136 batch.pop_back();
137 batch.push_back(newEvent);
138 });
139}
140
141void QOhosNativeNodeMouseInputHandler::processMouseEventsInQtThread(std::vector<MouseEvent> &&batch)
142{
143 auto now = ch::steady_clock::now();
144
145 QWindow *targetWindow = m_qWindowRef.data();
146 if (targetWindow == nullptr) {
147 qOhosPrintfWarning(
148 "%s: QWindow reference '%s' for node not valid. Rejecting mouse events batch.",
149 Q_FUNC_INFO, m_qWindowRef.refName().c_str());
150 return;
151 }
152
153 QOhosInputMethodEventHandler *eventHandler = m_imEventHandlerRef.data();
154 if (eventHandler == nullptr) {
155 qOhosPrintfWarning(
156 "%s: Input method event handler referece '%s' for node not valid. Rejecting mouse events batch.",
157 Q_FUNC_INFO, m_qWindowRef.refName().c_str());
158 return;
159 }
160
161 for (std::size_t i = 0; i < batch.size(); ++i) {
162 if (i + 1 < batch.size() && mayDropMouseEvent(now, batch[i], batch[i + 1]))
163 continue;
164
165 auto mouseEvent = batch[i].mouseEvent;
166 mouseEvent.targetWindow = targetWindow;
167 eventHandler->onMouseEvent(mouseEvent);
168 }
169}
170
171bool QOhosNativeNodeMouseInputHandler::mayDropMouseEvent(
172 ch::steady_clock::time_point now, const MouseEvent &event, const MouseEvent &nextEvent)
173{
174 return
175 now - event.timestamp >= mouseMotionEventMinAgeForDrop
176 && event.mouseEvent.eventType == QEvent::MouseMove
177 && nextEvent.mouseEvent.eventType == QEvent::MouseMove;
178}
179
180}
181
183 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
184 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef,
185 std::shared_ptr<QOhosHoverEventsGenerator> hoverEventsGenerator)
186{
187 auto mouseInputHandler = std::make_shared<QOhosNativeNodeMouseInputHandler>(qWindowRef, imEventHandlerRef, hoverEventsGenerator);
188 return [mouseInputHandler](QArkUi::NativeNodeMouseEvent nativeNodeMouseEvent) {
189 mouseInputHandler->handleMouseEvent(nativeNodeMouseEvent);
190 };
191}
192
193QT_END_NAMESPACE
void onMouseEvent(const QOhosMouseEvent &mouseEvent)
QOhosNativeNodeMouseInputHandler(QtOhos::QThreadSafeRef< QWindow > qWindowRef, QtOhos::QThreadSafeRef< QOhosInputMethodEventHandler > imEventHandlerRef, std::shared_ptr< QOhosHoverEventsGenerator > hoverEventsGenerator)
void handleMouseEvent(QArkUi::NativeNodeMouseEvent nativeNodeMouseEvent)
std::optional< Qt::MouseButton > tryMapNativeNodeMouseButtonToQt(std::int32_t button)
std::optional< QEvent::Type > tryMapNativeNodeMouseActionToQt(std::int32_t action)
QOhosConsumer< QArkUi::NativeNodeMouseEvent > makeQOhosNativeMouseEventsHandler(QtOhos::QThreadSafeRef< QWindow > qWindowRef, QtOhos::QThreadSafeRef< QOhosInputMethodEventHandler > imEventHandlerRef, std::shared_ptr< QOhosHoverEventsGenerator > hoverEventsGenerator)