4#include <ace/xcomponent/native_interface_xcomponent.h>
5#include <info/application_target_sdk_version.h>
6#include <multimodalinput/oh_input_manager.h>
7#include <render/qohosnativexcomponentinputhandler.h>
9#include <QtCore/QCoreApplication>
10#include <QtCore/qspan.h>
11#include <native_window/external_window.h>
12#include <qohosinputmethodeventhandler.h>
13#include <qohosjsmain.h>
14#include <qohosxcomponentkeyevent.h>
15#include <qohosplatformintegration.h>
16#include <qohosplatformtheme.h>
17#include <qohosutils.h>
18#include <render/qohosbatchingrequestshandler.h>
19#include <render/qohosview.h>
30constexpr auto mouseMotionEventMinAgeForDrop = std::chrono::milliseconds(20);
35 {OhosKeyboardModifier::CTRL, {::KEYCODE_CTRL_LEFT, ::KEYCODE_CTRL_RIGHT}, &::OH_Input_GetKeyPressed, ::KEY_PRESSED},
36 {OhosKeyboardModifier::ALT, {::KEYCODE_ALT_LEFT, ::KEYCODE_ALT_RIGHT}, &::OH_Input_GetKeyPressed, ::KEY_PRESSED},
37 {OhosKeyboardModifier::SHIFT, {::KEYCODE_SHIFT_LEFT, ::KEYCODE_SHIFT_RIGHT}, &::OH_Input_GetKeyPressed, ::KEY_PRESSED},
38 {OhosKeyboardModifier::LOGO, {::KEYCODE_META_LEFT, ::KEYCODE_META_RIGHT}, &::OH_Input_GetKeyPressed, ::KEY_PRESSED},
39 {OhosKeyboardModifier::CAPS_LOCK, {::KEYCODE_CAPS_LOCK}, &::OH_Input_GetKeySwitch, ::KEY_SWITCH_ON},
40 {OhosKeyboardModifier::NUM_LOCK, {::KEYCODE_NUM_LOCK}, &::OH_Input_GetKeySwitch, ::KEY_SWITCH_ON},
46 return QOhosPlatformIntegration::instance() !=
nullptr
47 && !QCoreApplication::startingUp()
48 && !QCoreApplication::closingDown();
53 OH_NativeXComponent_MouseEvent event;
54 return OH_NativeXComponent_GetMouseEvent(component, window, &event) == OH_NATIVEXCOMPONENT_RESULT_SUCCESS
55 ? std::tuple<QPointF, QPointF>({{event.x, event.y}, {event.screenX, event.screenY}})
56 : std::tuple<QPointF, QPointF>({{}, {}});
65 ::OH_NativeXComponent_GetTouchPointDisplayX(xComponent.handle(), touchPointIndex, &x)
66 == ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS
67 && ::OH_NativeXComponent_GetTouchPointDisplayY(xComponent.handle(), touchPointIndex, &y)
68 == ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS
69 ? makeQOhosOptional(QPointF{x, y})
70 : makeEmptyQOhosOptional();
75 std::uint32_t pointIndex)
77 auto touchDisplayPosition = tryGetTouchPointDisplayPosition(xComponent, pointIndex);
78 if (!touchDisplayPosition.has_value())
81 ::OH_NativeXComponent_TouchPointToolType toolType = ::OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN;
82 std::int32_t resToolType = ::OH_NativeXComponent_GetTouchPointToolType(xComponent.handle(), pointIndex, &toolType);
83 if (resToolType != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
84 qOhosCritical(QtForOhos)
85 <<
"OH_NativeXComponent_GetTouchPointToolType() failed,"
86 <<
"touchPoint id:" << touchEvent.touchPoints[pointIndex].id <<
"result:" << resToolType;
87 toolType = ::OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN;
92 if (toolType == ::OH_NATIVEXCOMPONENT_TOOL_TYPE_PEN) {
93 std::int32_t resTiltX = ::OH_NativeXComponent_GetTouchPointTiltX(xComponent.handle(), pointIndex, &tiltX);
94 if (resTiltX != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
95 qOhosCritical(QtForOhos)
96 <<
"OH_NativeXComponent_GetTouchPointTiltX() failed,"
97 <<
"touchPoint id:" << touchEvent.touchPoints[pointIndex].id <<
"result:" << resTiltX;
101 std::int32_t resTiltY = ::OH_NativeXComponent_GetTouchPointTiltY(xComponent.handle(), pointIndex, &tiltY);
102 if (resTiltY != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
103 qOhosCritical(QtForOhos)
104 <<
"OH_NativeXComponent_GetTouchPointTiltY() failed,"
105 <<
"touchPoint id:" << touchEvent.touchPoints[pointIndex].id <<
"result:" << resTiltY;
110 return makeQOhosOptional(
112 .touchPoint = touchEvent.touchPoints[pointIndex],
113 .toolType = toolType,
114 .displayPosition = touchDisplayPosition.value(),
122 ::OH_NativeXComponent_EventSourceType sourceType = ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN;
123 std::int32_t res = ::OH_NativeXComponent_GetTouchEventSourceType(component, pointId, &sourceType);
124 if (res != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
125 qOhosCritical(QtForOhos)
126 <<
"OH_NativeXComponent_GetTouchEventSourceType() failed,"
127 <<
"pointId:" << pointId <<
"result:" << res;
128 return QInputDevice::DeviceType::TouchPad;
131 return sourceType == ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_TOUCHSCREEN
132 ? QInputDevice::DeviceType::TouchScreen
133 : QInputDevice::DeviceType::TouchPad;
139 case OH_NativeXComponent_KeyCode::KEY_SHIFT_LEFT:
140 case OH_NativeXComponent_KeyCode::KEY_SHIFT_RIGHT:
141 case OH_NativeXComponent_KeyCode::KEY_ALT_LEFT:
142 case OH_NativeXComponent_KeyCode::KEY_ALT_RIGHT:
143 case OH_NativeXComponent_KeyCode::KEY_CTRL_LEFT:
144 case OH_NativeXComponent_KeyCode::KEY_CTRL_RIGHT:
145 case OH_NativeXComponent_KeyCode::KEY_META_LEFT:
146 case OH_NativeXComponent_KeyCode::KEY_META_RIGHT:
147 case OH_NativeXComponent_KeyCode::KEY_CAPS_LOCK:
148 case OH_NativeXComponent_KeyCode::KEY_NUM_LOCK:
158 case OH_NATIVEXCOMPONENT_MOUSE_PRESS:
159 return makeQOhosOptional(QEvent::MouseButtonPress);
160 case OH_NATIVEXCOMPONENT_MOUSE_RELEASE:
161 return makeQOhosOptional(QEvent::MouseButtonRelease);
162 case OH_NATIVEXCOMPONENT_MOUSE_MOVE:
163 return makeQOhosOptional(QEvent::MouseMove);
164 case OH_NATIVEXCOMPONENT_MOUSE_NONE:
165 case OH_NATIVEXCOMPONENT_MOUSE_CANCEL:
174 case OH_NATIVEXCOMPONENT_LEFT_BUTTON:
175 return makeQOhosOptional(Qt::LeftButton);
176 case OH_NATIVEXCOMPONENT_MIDDLE_BUTTON:
177 return makeQOhosOptional(Qt::MiddleButton);
178 case OH_NATIVEXCOMPONENT_RIGHT_BUTTON:
179 return makeQOhosOptional(Qt::RightButton);
180 case OH_NATIVEXCOMPONENT_BACK_BUTTON:
181 return makeQOhosOptional(Qt::BackButton);
182 case OH_NATIVEXCOMPONENT_FORWARD_BUTTON:
183 return makeQOhosOptional(Qt::ForwardButton);
184 case OH_NATIVEXCOMPONENT_NONE_BUTTON:
195 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
196 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef)
208 OH_NativeXComponent_TouchEvent touchEvent;
209 int32_t retcode = OH_NativeXComponent_GetTouchEvent(m_xComponent.handle(), window, &touchEvent);
210 if (retcode != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
211 qOhosCritical(QtForOhos) <<
"Unable to obtain TouchEvent from XComponent";
215 std::vector<QOhosTouchEventTouchPointData> validTouchPoints;
217 ::OH_NativeXComponent_EventSourceType sourceType = ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN;
218 std::int32_t resSourceType = ::OH_NativeXComponent_GetTouchEventSourceType(m_xComponent.handle(), touchEvent.id, &sourceType);
219 if (resSourceType != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
220 qOhosCritical(QtForOhos)
221 <<
"OH_NativeXComponent_GetTouchEventSourceType() failed,"
222 <<
"touchEvent id:" << touchEvent.id <<
"result:" << resSourceType;
223 sourceType = ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN;
226 bool isMouseOrUnknownTouchType =
227 sourceType == OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN
228 || sourceType == OH_NATIVEXCOMPONENT_SOURCE_TYPE_MOUSE;
229 if (isMouseOrUnknownTouchType)
232 for (
std::uint32_t pointIndex = 0; pointIndex < touchEvent.numPoints; ++pointIndex) {
233 auto pointData = tryMakeTouchEventPointData(m_xComponent, touchEvent, pointIndex);
234 if (pointData.has_value())
235 validTouchPoints.push_back(pointData.value());
238 if (validTouchPoints.empty())
241 if (!m_optTouchEventsHandler) {
242 auto weakSelf = sharedFromThis().toWeakRef();
243 m_optTouchEventsHandler = makeQtOhosSimpleBatchingQtRequestsHandler<TouchEvent>(
244 m_imEventHandlerRef.toQObjectThreadSafeRef(),
245 [weakSelf](std::vector<TouchEvent> &&batch) {
246 auto sharedSelf = weakSelf.toStrongRef();
247 if (!sharedSelf.isNull())
248 sharedSelf->processTouchEventsInQtThread(std::move(batch));
252 m_optTouchEventsHandler(
254 .timestamp = std::chrono::steady_clock::now(),
255 .touchTimeStamp = std::chrono::nanoseconds(touchEvent.timeStamp),
256 .touchPoints = validTouchPoints,
257 .deviceType = getTouchDeviceType(m_xComponent.handle(), touchEvent.id),
258 .modifiers = readKeyModifiersFromKeyState(
259 QSpan(keysToModifiers.data(), keysToModifiers.size())),
267 OH_NativeXComponent_MouseEvent ev;
268 const std::int32_t retcode = OH_NativeXComponent_GetMouseEvent(m_xComponent.handle(), window, &ev);
269 if (retcode != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
270 qOhosCritical(QtForOhos) <<
"Unable to retrieve MouseEvent from XComponent";
274 if (!m_optMouseEventsHandler) {
275 auto weakSelf = sharedFromThis().toWeakRef();
276 m_optMouseEventsHandler = makeQtOhosBatchingQtRequestsHandler<std::vector<MouseEvent>>(
277 m_imEventHandlerRef.toQObjectThreadSafeRef(),
278 [weakSelf](std::vector<MouseEvent> &&batch) {
279 auto sharedSelf = weakSelf.toStrongRef();
280 if (!sharedSelf.isNull())
281 sharedSelf->processMouseEventsInQtThread(std::move(batch));
285 m_optMouseEventsHandler(
286 [&](std::vector<MouseEvent> &batch) {
287 auto now = std::chrono::steady_clock::now();
288 MouseEvent newEvent{now, ev};
289 if (!batch.empty() && mayDropMouseEvent(now, batch.back(), newEvent))
291 batch.push_back(newEvent);
299 auto __dbg = make_QCScopedDebug(
"QOhosNativeXComponentInputDispatcher::dispatchHoverEvent");
303 std::tie(localPoint, globalPoint) = getLocalAndGlobalPointsOrDefault(m_xComponent.handle(), nativeWindow);
305 invokeMethodLaterIfSelfExists(
306 m_imEventHandlerRef.toQObjectThreadSafeRef(),
307 [isHover, localPoint, globalPoint](QOhosNativeXComponentInputHandler &self) {
308 self.m_imEventHandlerRef.data()->onHoverEvent(
310 .targetWindow = self.m_qWindowRef.data(),
311 .localPosition = localPoint,
312 .globalPosition = globalPoint,
318void QOhosNativeXComponentInputHandler::processMouseEventsInQtThread(std::vector<MouseEvent> &&batch)
320 auto now =
std::chrono::steady_clock::now();
322 QWindow *associatedWindowHandle = m_qWindowRef.data();
323 for (
std::size_t i = 0; i < batch.size(); ++i) {
324 if (i + 1 < batch.size() && mayDropMouseEvent(now, batch[i], batch[i + 1]))
327 auto event = batch[i].event;
329 auto eventType = tryMapXComponentMouseEventActionToQEventType(event.action);
330 if (!eventType.has_value()) {
332 "%s: got unsupported action in mouse event (%d), ignoring",
333 Q_FUNC_INFO, event.action);
337 auto optButton = tryMapXComponentMouseButtonToQt(event.button);
338 if (!optButton.has_value())
339 qOhosWarning(QtForOhos) <<
"Unexpected mouse button!";
344 QPointF globalPos(event.screenX, event.screenY);
345 QPointF localPos(event.x, event.y);
347 m_imEventHandlerRef.data()->onMouseEvent(
349 .targetWindow = associatedWindowHandle,
350 .timestampMs = std::chrono::duration_cast<std::chrono::milliseconds>(
351 std::chrono::nanoseconds(event.timestamp)),
352 .localPosition = localPos,
353 .globalPosition = globalPos,
354 .button = optButton.value_or(Qt::NoButton),
355 .eventType = eventType.value(),
356 .modifiers = readKeyModifiersFromKeyState(
357 QSpan(keysToModifiers.data(), keysToModifiers.size())),
362void QOhosNativeXComponentInputHandler::processTouchEventsInQtThread(std::vector<TouchEvent> &&batch)
364 QWindow *window = m_qWindowRef.data();
365 auto now =
std::chrono::steady_clock::now();
366 for (
auto &event : batch) {
367 if (now - event.timestamp >= touchEventMinAgeForDrop) {
368 event.touchPoints.erase(
369 QtOhos::removeMatchingWithLookahead(
370 event.touchPoints.begin(), event.touchPoints.end(),
371 [](
const auto &touchPointData,
const auto &nextTouchPointData) {
373 touchPointData.touchPoint.type == OH_NATIVEXCOMPONENT_MOVE
374 && nextTouchPointData.touchPoint.type == OH_NATIVEXCOMPONENT_MOVE;
376 event.touchPoints.end());
378 m_imEventHandlerRef.data()->onTouchEventFromXComponent(
379 window, event.touchTimeStamp, event.touchPoints, event.deviceType, event.modifiers);
383void QOhosNativeXComponentInputHandler::invokeMethodLaterIfSelfExists(
384 QtOhos::QObjectThreadSafeRef ctxRef,
std::function<
void(QOhosNativeXComponentInputHandler &)> callback)
386 auto weakSelf = sharedFromThis().toWeakRef();
387 ctxRef.visitInQtThreadIfAlive(
388 [weakSelf, callback = std::move(callback)](
auto &) {
389 auto sharedSelf = weakSelf.toStrongRef();
390 if (!sharedSelf.isNull()) {
391 callback(*sharedSelf);
396bool QOhosNativeXComponentInputHandler::mayDropMouseEvent(
397 std::chrono::steady_clock::time_point now,
398 const MouseEvent &event,
const MouseEvent &nextEvent)
401 now - event.timestamp >= mouseMotionEventMinAgeForDrop
402 && event.event.action == OH_NATIVEXCOMPONENT_MOUSE_MOVE
403 && nextEvent.event.action == OH_NATIVEXCOMPONENT_MOUSE_MOVE;
410 OH_NativeXComponent_KeyEvent *keyEvent =
nullptr;
411 OH_NativeXComponent_KeyAction keyAction = {};
412 OH_NativeXComponent_KeyCode keyCode = {};
414 if (OH_NativeXComponent_GetKeyEvent(m_xComponent.handle(), &keyEvent) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
415 qOhosCritical(QtForOhos) <<
"Could not obtain correct KeyEvent!";
419 if (OH_NativeXComponent_GetKeyEventAction(keyEvent, &keyAction) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
420 qOhosCritical(QtForOhos) <<
"Could not obtain correct Action for given KeyEvent!";
424 if (OH_NativeXComponent_GetKeyEventCode(keyEvent, &keyCode) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
425 qOhosCritical(QtForOhos) <<
"Could not obtain correct KeyCode for given KeyEvent!";
429 const auto keyModifiers = readKeyModifiersFromKeyState(
430 QSpan(keysToModifiers.data(), keysToModifiers.size()));
432 auto ohosKeyEvent = makeQOhosXComponentKeyEvent(keyAction, keyCode, keyModifiers);
434 if (isModifierKey(keyCode) && m_lastKeyEvent && m_lastKeyEvent->equals(*ohosKeyEvent))
436 m_lastKeyEvent = ohosKeyEvent;
438 invokeMethodLaterIfSelfExists(
439 m_imEventHandlerRef.toQObjectThreadSafeRef(),
440 [ohosKeyEvent](QOhosNativeXComponentInputHandler &self) {
441 self.m_imEventHandlerRef.data()->onKeyEvent(*ohosKeyEvent, self.m_qWindowRef.data());
QOhosOptional< QEvent::Type > tryMapXComponentMouseEventActionToQEventType(::OH_NativeXComponent_MouseEventAction action)
QOhosOptional< QPointF > tryGetTouchPointDisplayPosition(QXComponentRender xComponent, std::int32_t touchPointIndex)
std::tuple< QPointF, QPointF > getLocalAndGlobalPointsOrDefault(OH_NativeXComponent *component, void *window)
QOhosOptional< QOhosTouchEventTouchPointData > tryMakeTouchEventPointData(QXComponentRender xComponent, const OH_NativeXComponent_TouchEvent &touchEvent, std::uint32_t pointIndex)
const std::array< OhosKeyToModifier, 6 > keysToModifiers
QOhosOptional< Qt::MouseButton > tryMapXComponentMouseButtonToQt(::OH_NativeXComponent_MouseEventButton button)
bool isModifierKey(OH_NativeXComponent_KeyCode keyCode)
QInputDevice::DeviceType getTouchDeviceType(::OH_NativeXComponent *component, std::int32_t pointId)
constexpr auto touchEventMinAgeForDrop
std::nullopt_t makeEmptyQOhosOptional()
QXComponent< QXComponentType::Render > QXComponentRender