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 <QtGui/private/qhighdpiscaling_p.h>
6#include <chrono>
7#include <cstdint>
8#include <functional>
9#include <qarkui/qarkuiutils.h>
10#include <qohoskeymodifiers.h>
11#include <render/qohosbatchingrequestshandler.h>
12#include <render/qohosnativemouseeventshandler.h>
13#include <vector>
14
15namespace ch = std::chrono;
16
17QT_BEGIN_NAMESPACE
18
19namespace {
20
21constexpr auto mouseMotionEventMinAgeForDrop = ch::milliseconds(20);
22
24{
25 switch (button) {
26 case ::UI_MOUSE_EVENT_BUTTON_NONE:
28 case ::UI_MOUSE_EVENT_BUTTON_LEFT:
29 return makeQOhosOptional(Qt::LeftButton);
30 case ::UI_MOUSE_EVENT_BUTTON_RIGHT:
31 return makeQOhosOptional(Qt::RightButton);
32 case ::UI_MOUSE_EVENT_BUTTON_MIDDLE:
33 return makeQOhosOptional(Qt::MiddleButton);
34 case ::UI_MOUSE_EVENT_BUTTON_BACK:
35 return makeQOhosOptional(Qt::BackButton);
36 case ::UI_MOUSE_EVENT_BUTTON_FORWARD:
37 return makeQOhosOptional(Qt::ForwardButton);
38 }
39
41};
42
44{
45 switch (action) {
46 case ::UI_MOUSE_EVENT_ACTION_UNKNOWN:
48 case ::UI_MOUSE_EVENT_ACTION_PRESS:
49 return makeQOhosOptional(QEvent::MouseButtonPress);
50 case ::UI_MOUSE_EVENT_ACTION_RELEASE:
51 return makeQOhosOptional(QEvent::MouseButtonRelease);
52 case ::UI_MOUSE_EVENT_ACTION_MOVE:
53 return makeQOhosOptional(QEvent::MouseMove);
54 }
55
57}
58
59class QOhosNativeNodeMouseInputHandler final : public std::enable_shared_from_this<QOhosNativeNodeMouseInputHandler>
60{
61public:
63 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
64 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef,
65 std::shared_ptr<QOhosHoverEventsGenerator> hoverEventsGenerator);
66
67 void handleMouseEvent(::ArkUI_UIInputEvent *uiInputEvent);
68
69private:
70 struct MouseEvent
71 {
72 ch::steady_clock::time_point timestamp;
73 QOhosMouseEvent mouseEvent;
74 };
75
76 void processMouseEventsInQtThread(std::vector<MouseEvent> &&batch);
77
78 static bool mayDropMouseEvent(
79 ch::steady_clock::time_point now, const MouseEvent &event, const MouseEvent &nextEvent);
80
81 QtOhos::QThreadSafeRef<QWindow> m_qWindowRef;
82 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> m_imEventHandlerRef;
83 std::shared_ptr<QOhosHoverEventsGenerator> m_hoverEventsGenerator;
84
85 std::function<void(std::function<void(std::vector<MouseEvent> &)>)> m_optMouseEventsHandler;
86};
87
88QOhosNativeNodeMouseInputHandler::QOhosNativeNodeMouseInputHandler(
89 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
90 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef,
91 std::shared_ptr<QOhosHoverEventsGenerator> hoverEventsGenerator)
95{
96}
97
98void QOhosNativeNodeMouseInputHandler::handleMouseEvent(::ArkUI_UIInputEvent *uiInputEvent)
99{
100 auto mouseButton = QArkUi::callArkUi(
101 Q_OHOS_NAMED_FUNC(::OH_ArkUI_MouseEvent_GetMouseButton), uiInputEvent);
102 auto mouseAction = QArkUi::callArkUi(
103 Q_OHOS_NAMED_FUNC(::OH_ArkUI_MouseEvent_GetMouseAction), uiInputEvent);
104
105 auto localPosition = QPointF(
106 QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_ArkUI_PointerEvent_GetX), uiInputEvent),
107 QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_ArkUI_PointerEvent_GetY), uiInputEvent));
108
109 auto displayPosition = QPointF(
110 QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_ArkUI_PointerEvent_GetDisplayX), uiInputEvent),
111 QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_ArkUI_PointerEvent_GetDisplayY), uiInputEvent));
112
113 auto eventTime = QArkUi::callArkUi(
114 Q_OHOS_NAMED_FUNC(::OH_ArkUI_UIInputEvent_GetEventTime), uiInputEvent);
115
116 QOhosMouseEvent mouseEvent = {
117 .timestampMs = ch::duration_cast<ch::milliseconds>(ch::nanoseconds(eventTime)),
118 .localPosition = localPosition,
119 .globalPosition = displayPosition,
120 .button = tryMapNativeNodeMouseButtonToQt(mouseButton).valueOr(Qt::NoButton),
121 .eventType = tryMapNativeNodeMouseActionToQt(mouseAction).valueOr(QEvent::None),
122 .modifiers = readKeyModifiersFromOhosUiInputEvent(uiInputEvent),
123 };
124
125 m_hoverEventsGenerator->handleQOhosMouseEvent(mouseEvent);
126
127 if (!m_optMouseEventsHandler) {
128 auto weakSelf = QtOhos::makeWeakPtr(shared_from_this());
129 m_optMouseEventsHandler = makeQtOhosBatchingQtRequestsHandler<std::vector<MouseEvent>>(
130 m_imEventHandlerRef.toQObjectThreadSafeRef(),
131 [weakSelf](std::vector<MouseEvent> &&batch) {
132 auto sharedSelf = weakSelf.lock();
133 if (sharedSelf)
134 sharedSelf->processMouseEventsInQtThread(std::move(batch));
135 });
136 }
137
138 m_optMouseEventsHandler(
139 [&](std::vector<MouseEvent> &batch) {
140 auto now = std::chrono::steady_clock::now();
141 MouseEvent newEvent{now, mouseEvent};
142 if (!batch.empty() && mayDropMouseEvent(now, batch.back(), newEvent))
143 batch.pop_back();
144 batch.push_back(newEvent);
145 });
146}
147
148void QOhosNativeNodeMouseInputHandler::processMouseEventsInQtThread(std::vector<MouseEvent> &&batch)
149{
150 auto now = ch::steady_clock::now();
151
152 QWindow *targetWindow = m_qWindowRef.data();
153 if (targetWindow == nullptr) {
154 qOhosPrintfWarning(
155 "%s: QWindow reference '%s' for node not valid. Rejecting mouse events batch.",
156 Q_FUNC_INFO, m_qWindowRef.refName().c_str());
157 return;
158 }
159
160 QOhosInputMethodEventHandler *eventHandler = m_imEventHandlerRef.data();
161 if (eventHandler == nullptr) {
162 qOhosPrintfWarning(
163 "%s: Input method event handler referece '%s' for node not valid. Rejecting mouse events batch.",
164 Q_FUNC_INFO, m_qWindowRef.refName().c_str());
165 return;
166 }
167
168 for (std::size_t i = 0; i < batch.size(); ++i) {
169 if (i + 1 < batch.size() && mayDropMouseEvent(now, batch[i], batch[i + 1]))
170 continue;
171
172 auto mouseEvent = batch[i].mouseEvent;
173 mouseEvent.targetWindow = targetWindow;
174 auto *platformScreen = static_cast<QOhosPlatformScreen *>(mouseEvent.targetWindow->screen()->handle());
175 mouseEvent.localPosition = QHighDpi::toNative(mouseEvent.localPosition, platformScreen->pixelScalingCoefficient());
176 mouseEvent.globalPosition = QHighDpi::toNative(mouseEvent.globalPosition, platformScreen->pixelScalingCoefficient());
177 eventHandler->onMouseEvent(mouseEvent);
178 }
179}
180
181bool QOhosNativeNodeMouseInputHandler::mayDropMouseEvent(
182 ch::steady_clock::time_point now, const MouseEvent &event, const MouseEvent &nextEvent)
183{
184 return
185 now - event.timestamp >= mouseMotionEventMinAgeForDrop
186 && event.mouseEvent.eventType == QEvent::MouseMove
187 && nextEvent.mouseEvent.eventType == QEvent::MouseMove;
188}
189
190}
191
193 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
194 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef,
195 std::shared_ptr<QOhosHoverEventsGenerator> hoverEventsGenerator)
196{
197 auto mouseInputHandler = std::make_shared<QOhosNativeNodeMouseInputHandler>(qWindowRef, imEventHandlerRef, hoverEventsGenerator);
198 return [mouseInputHandler](::ArkUI_UIInputEvent *uiInputEvent) {
199 mouseInputHandler->handleMouseEvent(uiInputEvent);
200 };
201}
202
203QT_END_NAMESPACE
void onMouseEvent(const QOhosMouseEvent &mouseEvent)
QOhosNativeNodeMouseInputHandler(QtOhos::QThreadSafeRef< QWindow > qWindowRef, QtOhos::QThreadSafeRef< QOhosInputMethodEventHandler > imEventHandlerRef, std::shared_ptr< QOhosHoverEventsGenerator > hoverEventsGenerator)
QOhosOptional< QEvent::Type > tryMapNativeNodeMouseActionToQt(std::int32_t action)
QOhosOptional< Qt::MouseButton > tryMapNativeNodeMouseButtonToQt(std::int32_t button)
QOhosConsumer<::ArkUI_UIInputEvent * > makeQOhosNativeMouseEventsHandler(QtOhos::QThreadSafeRef< QWindow > qWindowRef, QtOhos::QThreadSafeRef< QOhosInputMethodEventHandler > imEventHandlerRef, std::shared_ptr< QOhosHoverEventsGenerator > hoverEventsGenerator)
QOhosOptional< void > makeEmptyQOhosOptional()