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