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 ::OH_NativeXComponent_EventSourceType sourceType = ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN;
76 std::int32_t res = ::OH_NativeXComponent_GetTouchEventSourceType(component, pointId, &sourceType);
77 if (res != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
78 qOhosCritical(QtForOhos)
79 <<
"OH_NativeXComponent_GetTouchEventSourceType() failed,"
80 <<
"pointId:" << pointId <<
"result:" << res;
81 return QInputDevice::DeviceType::TouchPad;
84 return sourceType == ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_TOUCHSCREEN
85 ? QInputDevice::DeviceType::TouchScreen
86 : QInputDevice::DeviceType::TouchPad;
92 case OH_NativeXComponent_KeyCode::KEY_SHIFT_LEFT:
93 case OH_NativeXComponent_KeyCode::KEY_SHIFT_RIGHT:
94 case OH_NativeXComponent_KeyCode::KEY_ALT_LEFT:
95 case OH_NativeXComponent_KeyCode::KEY_ALT_RIGHT:
96 case OH_NativeXComponent_KeyCode::KEY_CTRL_LEFT:
97 case OH_NativeXComponent_KeyCode::KEY_CTRL_RIGHT:
98 case OH_NativeXComponent_KeyCode::KEY_META_LEFT:
99 case OH_NativeXComponent_KeyCode::KEY_META_RIGHT:
100 case OH_NativeXComponent_KeyCode::KEY_CAPS_LOCK:
101 case OH_NativeXComponent_KeyCode::KEY_NUM_LOCK:
111 case OH_NATIVEXCOMPONENT_MOUSE_PRESS:
112 return makeQOhosOptional(QEvent::MouseButtonPress);
113 case OH_NATIVEXCOMPONENT_MOUSE_RELEASE:
114 return makeQOhosOptional(QEvent::MouseButtonRelease);
115 case OH_NATIVEXCOMPONENT_MOUSE_MOVE:
116 return makeQOhosOptional(QEvent::MouseMove);
117 case OH_NATIVEXCOMPONENT_MOUSE_NONE:
118 case OH_NATIVEXCOMPONENT_MOUSE_CANCEL:
127 case OH_NATIVEXCOMPONENT_LEFT_BUTTON:
128 return makeQOhosOptional(Qt::LeftButton);
129 case OH_NATIVEXCOMPONENT_MIDDLE_BUTTON:
130 return makeQOhosOptional(Qt::MiddleButton);
131 case OH_NATIVEXCOMPONENT_RIGHT_BUTTON:
132 return makeQOhosOptional(Qt::RightButton);
133 case OH_NATIVEXCOMPONENT_BACK_BUTTON:
134 return makeQOhosOptional(Qt::BackButton);
135 case OH_NATIVEXCOMPONENT_FORWARD_BUTTON:
136 return makeQOhosOptional(Qt::ForwardButton);
137 case OH_NATIVEXCOMPONENT_NONE_BUTTON:
148 QtOhos::QThreadSafeRef<QWindow> qWindowRef,
149 QtOhos::QThreadSafeRef<QOhosInputMethodEventHandler> imEventHandlerRef)
161 OH_NativeXComponent_TouchEvent touchEvent;
162 int32_t retcode = OH_NativeXComponent_GetTouchEvent(m_xComponent.handle(), window, &touchEvent);
163 if (retcode != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
164 qOhosCritical(QtForOhos) <<
"Unable to obtain TouchEvent from XComponent";
168 std::vector<QOhosTouchEventTouchPointData> validTouchPoints;
170 ::OH_NativeXComponent_EventSourceType tool = ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN;
171 std::int32_t res = ::OH_NativeXComponent_GetTouchEventSourceType(m_xComponent.handle(), touchEvent.id, &tool);
172 if (res != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
173 qOhosCritical(QtForOhos)
174 <<
"OH_NativeXComponent_GetTouchEventSourceType() failed,"
175 <<
"touchEvent id:" << touchEvent.id <<
"result:" << res;
176 tool = ::OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN;
179 bool isMouseOrUnknownTouchType =
180 tool == OH_NATIVEXCOMPONENT_SOURCE_TYPE_UNKNOWN
181 || tool == OH_NATIVEXCOMPONENT_SOURCE_TYPE_MOUSE;
182 if (isMouseOrUnknownTouchType)
185 for (
std::uint32_t i = 0; i < touchEvent.numPoints; ++i) {
186 auto touchDisplayPosition = tryGetTouchPointDisplayPosition(m_xComponent, i);
187 if (!touchDisplayPosition.hasValue())
191 .touchPoint = touchEvent.touchPoints[i],
192 .displayPosition = touchDisplayPosition.value(),
196 if (validTouchPoints.empty())
199 if (!m_optTouchEventsHandler) {
200 auto weakSelf = sharedFromThis().toWeakRef();
201 m_optTouchEventsHandler = makeQtOhosSimpleBatchingQtRequestsHandler<TouchEvent>(
202 m_imEventHandlerRef.toQObjectThreadSafeRef(),
203 [weakSelf](std::vector<TouchEvent> &&batch) {
204 auto sharedSelf = weakSelf.toStrongRef();
205 if (!sharedSelf.isNull())
206 sharedSelf->processTouchEventsInQtThread(std::move(batch));
210 m_optTouchEventsHandler(
212 .timestamp = std::chrono::steady_clock::now(),
213 .touchTimeStamp = std::chrono::nanoseconds(touchEvent.timeStamp),
214 .touchPoints = validTouchPoints,
215 .deviceType = getTouchDeviceType(m_xComponent.handle(), touchEvent.id),
223 OH_NativeXComponent_MouseEvent ev;
224 const std::int32_t retcode = OH_NativeXComponent_GetMouseEvent(m_xComponent.handle(), window, &ev);
225 if (retcode != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
226 qOhosCritical(QtForOhos) <<
"Unable to retrieve MouseEvent from XComponent";
230 if (!m_optMouseEventsHandler) {
231 auto weakSelf = sharedFromThis().toWeakRef();
232 m_optMouseEventsHandler = makeQtOhosBatchingQtRequestsHandler<std::vector<MouseEvent>>(
233 m_imEventHandlerRef.toQObjectThreadSafeRef(),
234 [weakSelf](std::vector<MouseEvent> &&batch) {
235 auto sharedSelf = weakSelf.toStrongRef();
236 if (!sharedSelf.isNull())
237 sharedSelf->processMouseEventsInQtThread(std::move(batch));
241 m_optMouseEventsHandler(
242 [&](std::vector<MouseEvent> &batch) {
243 auto now = std::chrono::steady_clock::now();
244 MouseEvent newEvent{now, ev};
245 if (!batch.empty() && mayDropMouseEvent(now, batch.back(), newEvent))
247 batch.push_back(newEvent);
255 auto __dbg = make_QCScopedDebug(
"QOhosNativeXComponentInputDispatcher::dispatchHoverEvent");
259 std::tie(localPoint, globalPoint) = getLocalAndGlobalPointsOrDefault(m_xComponent.handle(), nativeWindow);
261 invokeMethodLaterIfSelfExists(
262 m_imEventHandlerRef.toQObjectThreadSafeRef(),
263 [isHover, localPoint, globalPoint](QOhosNativeXComponentInputHandler &self) {
264 self.m_imEventHandlerRef.data()->onHoverEvent(isHover, localPoint, globalPoint, self.m_qWindowRef.data());
268void QOhosNativeXComponentInputHandler::processMouseEventsInQtThread(std::vector<MouseEvent> &&batch)
270 auto now =
std::chrono::steady_clock::now();
272 QWindow *associatedWindowHandle = m_qWindowRef.data();
273 for (
std::size_t i = 0; i < batch.size(); ++i) {
274 if (i + 1 < batch.size() && mayDropMouseEvent(now, batch[i], batch[i + 1]))
277 auto event = batch[i].event;
278 auto optButton = tryMapXComponentMouseButtonToQt(event.button);
279 if (!optButton.hasValue())
280 qOhosWarning(QtForOhos) <<
"Unexpected mouse button!";
285 QPointF globalPos(event.screenX, event.screenY);
286 QPointF localPos(event.x, event.y);
288 m_imEventHandlerRef.data()->onMouseEvent(
290 .targetWindow = associatedWindowHandle,
291 .timestampMs = std::chrono::duration_cast<std::chrono::milliseconds>(
292 std::chrono::nanoseconds(event.timestamp)),
293 .localPosition = localPos,
294 .globalPosition = globalPos,
295 .button = optButton.valueOr(Qt::NoButton),
296 .eventType = tryMapXComponentMouseEventActionToQEventType(event.action).valueOr(QEvent::None),
297 .modifiers = readKeyModifiersFromKeyState(
298 QSpan(keysToModifiers.data(), keysToModifiers.size())),
303void QOhosNativeXComponentInputHandler::processTouchEventsInQtThread(std::vector<TouchEvent> &&batch)
305 QWindow *window = m_qWindowRef.data();
306 auto now =
std::chrono::steady_clock::now();
307 for (
auto &event : batch) {
308 if (now - event.timestamp >= touchEventMinAgeForDrop) {
309 event.touchPoints.erase(
310 QtOhos::removeMatchingWithLookahead(
311 event.touchPoints.begin(), event.touchPoints.end(),
312 [](
const auto &touchPointData,
const auto &nextTouchPointData) {
314 touchPointData.touchPoint.type == OH_NATIVEXCOMPONENT_MOVE
315 && nextTouchPointData.touchPoint.type == OH_NATIVEXCOMPONENT_MOVE;
317 event.touchPoints.end());
319 m_imEventHandlerRef.data()->onTouchEventFromXComponent(
320 window, event.touchTimeStamp, event.touchPoints, event.deviceType);
324void QOhosNativeXComponentInputHandler::invokeMethodLaterIfSelfExists(
325 QtOhos::QObjectThreadSafeRef ctxRef,
std::function<
void(QOhosNativeXComponentInputHandler &)> callback)
327 auto weakSelf = sharedFromThis().toWeakRef();
328 ctxRef.visitInQtThreadIfAlive(
329 [weakSelf, callback = std::move(callback)](
auto &) {
330 auto sharedSelf = weakSelf.toStrongRef();
331 if (!sharedSelf.isNull()) {
332 callback(*sharedSelf);
337bool QOhosNativeXComponentInputHandler::mayDropMouseEvent(
338 std::chrono::steady_clock::time_point now,
339 const MouseEvent &event,
const MouseEvent &nextEvent)
342 now - event.timestamp >= mouseMotionEventMinAgeForDrop
343 && event.event.action == OH_NATIVEXCOMPONENT_MOUSE_MOVE
344 && nextEvent.event.action == OH_NATIVEXCOMPONENT_MOUSE_MOVE;
351 OH_NativeXComponent_KeyEvent *keyEvent =
nullptr;
352 OH_NativeXComponent_KeyAction keyAction = {};
353 OH_NativeXComponent_KeyCode keyCode = {};
355 if (OH_NativeXComponent_GetKeyEvent(m_xComponent.handle(), &keyEvent) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
356 qOhosCritical(QtForOhos) <<
"Could not obtain correct KeyEvent!";
360 if (OH_NativeXComponent_GetKeyEventAction(keyEvent, &keyAction) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
361 qOhosCritical(QtForOhos) <<
"Could not obtain correct Action for given KeyEvent!";
365 if (OH_NativeXComponent_GetKeyEventCode(keyEvent, &keyCode) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
366 qOhosCritical(QtForOhos) <<
"Could not obtain correct KeyCode for given KeyEvent!";
370 const auto keyModifiers = readKeyModifiersFromKeyState(
371 QSpan(keysToModifiers.data(), keysToModifiers.size()));
373 auto ohosKeyEvent = makeQOhosXComponentKeyEvent(keyAction, keyCode, keyModifiers);
375 if (isModifierKey(keyCode) && m_lastKeyEvent && m_lastKeyEvent->equals(*ohosKeyEvent))
377 m_lastKeyEvent = ohosKeyEvent;
379 invokeMethodLaterIfSelfExists(
380 m_imEventHandlerRef.toQObjectThreadSafeRef(),
381 [ohosKeyEvent](QOhosNativeXComponentInputHandler &self) {
382 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)
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
QOhosOptional< void > makeEmptyQOhosOptional()
QXComponent< QXComponentType::Render > QXComponentRender