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
qohosinputmethodeventhandler.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
6#include "qohosjsmain.h"
9#include <QtCore/private/qohoslogger_p.h>
10#include <QtCore/qmap.h>
11#include <QtGui/private/qguiapplication_p.h>
12#include <QtGui/private/qhighdpiscaling_p.h>
13#include <QtMath>
14#include <algorithm>
15#include <arkui/ui_input_event.h>
16#include <chrono>
17#include <render/qohosview.h>
18#include <typeinfo>
19
20using namespace Qt::Literals::StringLiterals;
21
22namespace ch = std::chrono;
23
24QT_BEGIN_NAMESPACE
25
26namespace {
27
28constexpr double fingerAreaWidth = 50.0;
29constexpr double fingerAreaHeight = 50.0;
30
31QInputDevice *createTouchDevice(QInputDevice::DeviceType deviceType)
32{
33 qOhosDebug(QtForOhos) << "Creating touchDevice!";
34 auto touchDevice =
35 std::make_unique<QPointingDevice>("OHOS touch device"_L1, 1,
36 deviceType, QPointingDevice::PointerType::Finger,
37 QInputDevice::Capability::Position
38 | QInputDevice::Capability::Area
39 | QInputDevice::Capability::Pressure
40 | QInputDevice::Capability::NormalizedPosition,
41 10, 0);
42
43 auto *touchDeviceRaw = touchDevice.get();
44 QWindowSystemInterface::registerInputDevice(touchDevice.release());
45 return touchDeviceRaw;
46}
47
49 QObject *object, QObject *context, std::function<void()> signalHandler)
50{
51 auto objDestroyedConnection = QObject::connect(object, &QObject::destroyed, context, std::move(signalHandler));
52 return QtOhos::makeDestroyNotifier(
53 [objDestroyedConnection = std::move(objDestroyedConnection)] () mutable {
54 QObject::disconnect(objDestroyedConnection);
55 });
56}
57
58QOhosOptional<QEventPoint::State> tryMapXComponentTouchEventTypeToQt(::OH_NativeXComponent_TouchEventType eventType)
59{
60 switch (eventType) {
61 case OH_NATIVEXCOMPONENT_DOWN:
62 return makeQOhosOptional(QEventPoint::State::Pressed);
63 case OH_NATIVEXCOMPONENT_UP:
64 return makeQOhosOptional(QEventPoint::State::Released);
65 case OH_NATIVEXCOMPONENT_MOVE:
66 return makeQOhosOptional(QEventPoint::State::Updated);
67 case OH_NATIVEXCOMPONENT_CANCEL:
68 case OH_NATIVEXCOMPONENT_UNKNOWN:
69 break;
70 }
72}
73
74QPointF calculateTouchPointNormalPosition(QWindow *targetWindow, const QPointF &clickPoint)
75{
76 auto *platformScreen = static_cast<QOhosPlatformScreen *>(targetWindow->screen()->handle());
77
78 QSize screenSize = platformScreen->geometry().size();
79
80 QPointF clickPointNormalized(
81 clickPoint.x() / screenSize.width(),
82 clickPoint.y() / screenSize.height());
83
84 return clickPointNormalized;
85}
86
87QRectF calculateTouchPointArea(const QPointF &clickPoint)
88{
89 return QRectF(
90 clickPoint.x() - static_cast<double>(fingerAreaWidth/2),
91 clickPoint.y() - static_cast<double>(fingerAreaHeight/2),
94}
95
97{
98 auto *screen = qWindow != nullptr
99 ? qWindow->screen()
100 : QGuiApplication::primaryScreen();
101
102 return screen != nullptr
103 ? screen->handle()->geometry().topLeft()
104 : QPoint();
105}
106
107QPoint makeWindowLocalPosition(const QPoint &globalPosition, QWindow *qWindow)
108{
109 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(qWindow);
110 auto platformWindowGeometry = platformWindow != nullptr
111 ? platformWindow->geometry()
112 : QHighDpi::toNativePixels(qWindow->geometry(), qWindow);
113
114 return globalPosition - platformWindowGeometry.topLeft();
115}
116
117}
118
119QOhosInputMethodEventHandler::QOhosInputMethodEventHandler(
120 const std::set<QInputDevice::DeviceType> &deviceTypes)
121{
122 for (const auto &deviceType : deviceTypes)
123 m_touchDevices.emplace(deviceType, createTouchDevice(deviceType));
124}
125
127
129 QWindow *targetWindow, ch::nanoseconds timeStamp,
130 const std::vector<QOhosTouchEventTouchPointData> &touchPoints,
131 QInputDevice::DeviceType deviceType, QFlags<OhosKeyboardModifier> modifiers)
132{
133 auto *touchDevice = getTouchDeviceOrCreateIfNeeded(deviceType);
134
135 QList<QWindowSystemInterface::TouchPoint> wsiTouchPoints;
136
137 auto timeStampMs = ch::duration_cast<ch::milliseconds>(timeStamp);
138
139 std::vector<QPoint> activeTouchPointDisplayPositions;
140
141 auto displayOffset = targetWindow != nullptr
142 ? determineScreenGlobalDisplayOffset(targetWindow)
143 : QPoint(0, 0);
144
145 for (const auto &touchPointData : touchPoints) {
146 const auto &touchPoint = touchPointData.touchPoint;
147 QPointF clickPoint = touchPointData.displayPosition;
148
149 switch (touchPointData.toolType) {
150 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_FINGER: {
151 QEventPoint::State state =
152 tryMapXComponentTouchEventTypeToQt(touchPoint.type)
153 .value_or(QEventPoint::State::Stationary);
154
155 if (state != QEventPoint::State::Released)
156 activeTouchPointDisplayPositions.push_back(touchPointData.displayPosition.toPoint());
157
158 QWindowSystemInterface::TouchPoint qwsiTouchPoint;
159 qwsiTouchPoint.id = touchPoint.id;
160 qwsiTouchPoint.pressure = touchPoint.force;
161 qwsiTouchPoint.normalPosition =
162 calculateTouchPointNormalPosition(targetWindow, clickPoint);
163 qwsiTouchPoint.state = state;
164 qwsiTouchPoint.area = calculateTouchPointArea(clickPoint + displayOffset);
165 wsiTouchPoints.push_back(qwsiTouchPoint);
166 break;
167 }
168 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_PEN: {
169 Qt::MouseButtons buttons = Qt::NoButton;
170 switch (touchPoint.type) {
171 case OH_NATIVEXCOMPONENT_DOWN:
172 case OH_NATIVEXCOMPONENT_MOVE:
173 buttons = Qt::LeftButton;
174 break;
175 case OH_NATIVEXCOMPONENT_UP:
176 case OH_NATIVEXCOMPONENT_CANCEL:
177 case OH_NATIVEXCOMPONENT_UNKNOWN:
178 buttons = Qt::NoButton;
179 break;
180 }
181 constexpr float tiltDegreesMin = -60.0f;
182 constexpr float tiltDegreesMax = 60.0f;
183 const int xTilt = qRound(qBound(tiltDegreesMin, touchPointData.tiltX, tiltDegreesMax));
184 const int yTilt = qRound(qBound(tiltDegreesMin, touchPointData.tiltY, tiltDegreesMax));
185 constexpr qreal tangentialPressure = 0;
186 constexpr qreal rotation = 0;
187 constexpr int z = 0;
188 QWindowSystemInterface::handleTabletEvent(
189 targetWindow, timeStampMs.count(), {touchPoint.x, touchPoint.y},
190 clickPoint,
191 static_cast<int>(QInputDevice::DeviceType::Stylus),
192 static_cast<int>(QPointingDevice::PointerType::Pen),
193 buttons, touchPoint.force, xTilt, yTilt, tangentialPressure, rotation,
194 z, touchPoint.id, convertOhosToQtKeyboardModifiers(modifiers));
195 break;
196 }
197 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_RUBBER:
198 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_BRUSH:
199 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_PENCIL:
200 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_AIRBRUSH:
201 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_LENS:
202 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN:
203 qOhosWarning(QtForOhos) << "Skipping unsupported tool type =" << touchPointData.toolType;
204 break;
205 case ::OH_NATIVEXCOMPONENT_TOOL_TYPE_MOUSE:
206 qOhosWarning(QtForOhos) << "Skipping mouse tool type in touch event.";
207 break;
208 }
209 }
210
211 if (!wsiTouchPoints.isEmpty()) {
212 auto singleActiveTouchEventGlobalPosition = activeTouchPointDisplayPositions.size() == 1
213 ? makeQOhosOptional(displayOffset + activeTouchPointDisplayPositions.front())
215
216 QWindowSystemInterfaceTouchEvent touchEvent = {
217 .targetWindow = targetWindow,
218 .touchPoints = wsiTouchPoints,
219 .touchDevice = touchDevice,
220 .timestampMs = timeStampMs,
221 .modifiers = modifiers,
222 .singleTouchPointEventGlobalPosition = singleActiveTouchEventGlobalPosition,
223 };
224
225 handleTouchEvent(touchEvent);
226 }
227}
228
230{
231 auto *touchDevice = getTouchDeviceOrCreateIfNeeded(gestureEvent.deviceType);
232 auto *window = gestureEvent.targetWindow.data();
233
234 // NOTE: Contrary to all other QWindowSystemInterface functions, the
235 // QWindowSystemInterface::handleGestureEventWithRealValue requires that the provided positions
236 // are converted to device independent units
237 auto scaledLocalPosition = QHighDpi::fromNativeLocalPosition(gestureEvent.localPosition, window);
238 auto scaledGlobalPosition = QHighDpi::fromNativePixels(gestureEvent.globalPosition, window);
239
240 QWindowSystemInterface::handleGestureEventWithRealValue(
241 gestureEvent.targetWindow,
242 gestureEvent.timestamp,
243 static_cast<const QPointingDevice *>(touchDevice),
244 gestureEvent.gestureType,
245 gestureEvent.value,
246 scaledLocalPosition,
247 scaledGlobalPosition);
248}
249
250void QOhosInputMethodEventHandler::onKeyEvent(const QOhosKeyEvent &keyEvent, QWindow *targetWindow)
251{
252 const auto optQOhosQtKeyEvent = keyEvent.tryConvertToQOhosQtKeyEvent();
253 if (!optQOhosQtKeyEvent.has_value())
254 return;
255 const auto qOhosQtKeyEvent = optQOhosQtKeyEvent.value();
256
257 constexpr quint32 nativeScanCode = 0;
258 constexpr quint32 nativeModifiers = 0;
259
260 auto *ohosInputContext = qobject_cast<QOhosInputContext *>(QOhosPlatformIntegration::instance()->inputContext());
261 if (ohosInputContext != nullptr)
262 ohosInputContext->setLastInputTypeToTriggerSoftKeyboard(QOhosInputContext::RequestKeyboardReason::NONE);
263
264 if (qOhosQtKeyEvent.keyAction == QEvent::KeyPress) {
265 if (m_autoRepeatCountMap[qOhosQtKeyEvent.keyCode] < std::numeric_limits<ushort>::max()) {
266 ++m_autoRepeatCountMap[qOhosQtKeyEvent.keyCode];
267 }
268 } else {
269 m_autoRepeatCountMap.remove(qOhosQtKeyEvent.keyCode);
270 }
271 const auto count = m_autoRepeatCountMap.value(qOhosQtKeyEvent.keyCode, 1);
272
273 QWindowSystemInterface::handleExtendedKeyEvent(
274 !m_currentKeyboardGrabbingWindow.isNull()
275 ? m_currentKeyboardGrabbingWindow.data()
276 : targetWindow,
277 qOhosQtKeyEvent.keyAction, qOhosQtKeyEvent.keyCode,
278 qOhosQtKeyEvent.guiApplicationKeyboardModifiers, nativeScanCode,
279 qOhosQtKeyEvent.nativeKeyCode, nativeModifiers, qOhosQtKeyEvent.keyText, count > 1, count);
280}
281
283{
284 Qt::MouseButton button = Qt::NoButton;
285
286 if (mouseEvent.eventType == QEvent::MouseButtonPress || mouseEvent.eventType == QEvent::MouseButtonRelease) {
287 button = mouseEvent.button;
288
289 // HACK
290 // Destructing QOhosView means loosing QNativeNode, JsStateData and QXComponentCallbackReceiver.
291 // It means no more events will come from the destroyed window.
292 // There is a case when closing window was done via mouse double-click event and second release
293 // button event is not caught due to QNativeNode destruction. It causes issues in
294 // QOhosInputMethodEventHandler state machine after switching to different window.
295 // This workaround allows to clear buttons state.
296 registerOnWindowCloseToResetMouseButtonsState(mouseEvent.targetWindow);
297 }
298
299 QOhosMouseEvent wsiEvent {
300 .targetWindow = mouseEvent.targetWindow,
301 .timestampMs = mouseEvent.timestampMs,
302 .localPosition = mouseEvent.localPosition,
303 .globalPosition = mouseEvent.globalPosition,
304 .button = button,
305 .eventType = mouseEvent.eventType,
306 .modifiers = mouseEvent.modifiers,
307 };
308
309 handleMouseEvent(wsiEvent);
310}
311
313{
314 bool isHover = hoverEvent.isHover;
315 auto local = hoverEvent.localPosition;
316 auto global = hoverEvent.globalPosition;
317 QWindow *window = hoverEvent.targetWindow;
318 if (!m_currentMouseGrabbingWindow.isNull() && m_currentMouseGrabbingWindow != window)
319 return;
320
321 if (isHover)
322 QWindowSystemInterface::handleEnterEvent(window, local, global);
323 else
324 QWindowSystemInterface::handleLeaveEvent(window);
325}
326
328{
329 constexpr int angleXMin = -120;
330 constexpr int angleXMax = 120;
331 constexpr int xAxisValueMultiplier = -10;
332
333 constexpr int angleYMin = angleXMin;
334 constexpr int angleYMax = angleXMax;
335 constexpr int yAxisValueMultiplier = xAxisValueMultiplier;
336
337 constexpr double wheelStepDegree = 15.0;
338 constexpr double wheelStepPixel = 21.0;
339
340 constexpr double angleBaseValue = 8.0;
341 constexpr double directionMultiplier = -1.0;
342
343 QPoint pixelDelta;
344 QPoint angleDelta;
345
346 static_cast<QOhosPlatformTheme *>(QGuiApplicationPrivate::platformTheme())->setWheelScrollLines(
347 static_cast<int>(event.wheelScrollLines));
348
349 auto *platformScreen = static_cast<QOhosPlatformScreen *>(window->screen()->handle());
350
351 if (event.eventToolType == UI_INPUT_EVENT_TOOL_TYPE_MOUSE) {
352 angleDelta.setX(qBound(angleXMin, static_cast<int>(event.horizontalValue * xAxisValueMultiplier), angleXMax));
353 angleDelta.setY(qBound(angleYMin, static_cast<int>(event.verticalValue * yAxisValueMultiplier), angleYMax));
354
355 auto mousePixelDeltaMultiplier = wheelStepPixel / wheelStepDegree / angleBaseValue;
356 pixelDelta.setX(
357 qRound(qFabs(angleDelta.x() * mousePixelDeltaMultiplier) * platformScreen->pixelScalingCoefficient()));
358 pixelDelta.setY(
359 qRound(qFabs(angleDelta.y() * mousePixelDeltaMultiplier) * platformScreen->pixelScalingCoefficient()));
360 } else if (event.eventToolType == UI_INPUT_EVENT_TOOL_TYPE_TOUCHPAD) {
361 auto touchpadAngleDeltaMultiplier =
362 wheelStepDegree / wheelStepPixel / platformScreen->pixelScalingCoefficient() * angleBaseValue * directionMultiplier / event.wheelScrollLines;
363 angleDelta.setX(qRound(event.horizontalValue * touchpadAngleDeltaMultiplier));
364 angleDelta.setY(qRound(event.verticalValue * touchpadAngleDeltaMultiplier));
365
366 pixelDelta.setX(qRound(qFabs(event.horizontalValue)));
367 pixelDelta.setY(qRound(qFabs(event.verticalValue)));
368 } else {
369 qOhosWarning(QtForOhos)
370 << Q_FUNC_INFO
371 << "Received unsupported input event tool type =" << event.eventToolType << "skipping...";
372 return;
373 }
374
375 Qt::MouseEventSource source = event.eventToolType == ::UI_INPUT_EVENT_TOOL_TYPE_TOUCHPAD
376 ? Qt::MouseEventSynthesizedBySystem
377 : Qt::MouseEventNotSynthesized;
378 bool inverted = false;
379
380 QWindowSystemInterface::handleWheelEvent(
381 window,
382 event.timestamp,
383 event.localPoint,
384 event.globalPoint,
385 pixelDelta,
386 angleDelta,
387 convertOhosToQtKeyboardModifiers(event.modifiers),
388 event.scrollPhase,
389 source,
390 inverted);
391}
392
394 QWindow *targetWindow, std::vector<QOhosWindowProxy::NonClientAreaMouseEvent> eventBatch)
395{
396 using NonClientAreaMouseEvent = QOhosWindowProxy::NonClientAreaMouseEvent;
397
398 eventBatch.erase(
399 QtOhos::removeMatchingWithLookahead(
400 eventBatch.begin(), eventBatch.end(),
401 [](const NonClientAreaMouseEvent &event, const NonClientAreaMouseEvent &nextEvent) {
402 return event.action == QEvent::NonClientAreaMouseMove
403 && nextEvent.action == QEvent::NonClientAreaMouseMove;
404 }),
405 eventBatch.end());
406
407 for (const auto &mouseEvent : eventBatch) {
408 QOhosMouseEvent qtMouseEvent = {
409 .targetWindow = targetWindow,
410 .timestampMs = mouseEvent.timestamp,
411 .localPosition = mouseEvent.localPosition,
412 .globalPosition = mouseEvent.displayPosition,
413 .button = mouseEvent.button,
414 .eventType = mouseEvent.action,
415 };
416
417 // HACK
418 // When a window is being closed by clicking close button on title bar we should receive two events:
419 // NonClientAreaMouseButtonPress and NonClientAreaMouseButtonRelease, but sometimes we receive only
420 // NonClientAreaMouseButtonPress event without NonClientAreaMouseButtonRelease, because the window
421 // sending this event is alredy destroyed. It leaves us with invalid mouse state with a button
422 // that has not been released.
423 // This workaround resets mouse buttons state when a window is closed.
424 if (mouseEvent.action == QEvent::NonClientAreaMouseButtonPress)
425 registerOnWindowCloseToResetMouseButtonsState(targetWindow);
426
427 handleMouseEvent(qtMouseEvent);
428 }
429}
430
432 QWindow *targetWindow, std::vector<QOhosWindowProxy::NonClientAreaTouchEvent> eventBatch)
433{
434 using NonClientAreaTouchEvent = QOhosWindowProxy::NonClientAreaTouchEvent;
435
436 eventBatch.erase(
437 QtOhos::removeMatchingWithLookahead(
438 eventBatch.begin(), eventBatch.end(),
439 [](const NonClientAreaTouchEvent &event, const NonClientAreaTouchEvent &nextEvent) {
440 return
441 event.state == QEventPoint::State::Updated
442 && nextEvent.state == QEventPoint::State::Updated;
443 }),
444 eventBatch.end());
445
446 for (const auto &touchEvent : eventBatch) {
447 QPointF clickPoint = touchEvent.displayPosition;
448
449 QWindowSystemInterface::TouchPoint qwsiTouchPoint;
450 qwsiTouchPoint.id = touchEvent.id;
451 qwsiTouchPoint.pressure = 1.0;
452 qwsiTouchPoint.normalPosition = calculateTouchPointNormalPosition(targetWindow, clickPoint);
453 qwsiTouchPoint.state = touchEvent.state;
454 qwsiTouchPoint.area = calculateTouchPointArea(clickPoint);
455
456 QWindowSystemInterfaceTouchEvent qwsiTouchEvent = {
457 .targetWindow = targetWindow,
458 .touchPoints = {qwsiTouchPoint},
459 .touchDevice = getTouchDeviceOrCreateIfNeeded(QInputDevice::DeviceType::TouchScreen),
460 .timestampMs = touchEvent.timestamp,
461 };
462
463 handleTouchEvent(qwsiTouchEvent);
464 }
465}
466
468{
469 auto lastTouchedPair = getLastTouchedWindowWithSeqNoIfPresent();
470 return lastTouchedPair.has_value()
471 ? lastTouchedPair.value().first
472 : nullptr;
473}
474
475QInputDevice *QOhosInputMethodEventHandler::getTouchDeviceOrCreateIfNeeded(QInputDevice::DeviceType deviceType)
476{
477 auto touchDeviceIter = m_touchDevices.find(deviceType);
478 if (touchDeviceIter == m_touchDevices.end()) {
479 qOhosWarning(QtForOhos) << "Trying to get touch device but it isn't registered. Creating and registering one now.";
480 std::tie(touchDeviceIter, std::ignore) = m_touchDevices.emplace(
481 deviceType, createTouchDevice(deviceType));
482 }
483 return touchDeviceIter->second;
484}
485
486QOhosOptional<std::pair<QWindow *, std::uint64_t>> QOhosInputMethodEventHandler::getLastTouchedWindowWithSeqNoIfPresent() const
487{
488 auto maxSeqNoEntryIter = std::max_element(
489 m_windowsUnderTouchPoints.begin(), m_windowsUnderTouchPoints.end(),
490 [](const auto &a, const auto &b) {
491 return a.second.second < b.second.second;
492 });
493
494 return maxSeqNoEntryIter != m_windowsUnderTouchPoints.end()
495 ? makeQOhosOptional(
496 std::make_pair(maxSeqNoEntryIter->first, maxSeqNoEntryIter->second.second))
497 : makeEmptyQOhosOptional();
498}
499
501{
502 qCDebug(QtForOhos) << Q_FUNC_INFO << "window:" << window;
503 m_currentMouseGrabbingWindow = window;
504}
505
507{
508 qCDebug(QtForOhos) << Q_FUNC_INFO << "window:" << window;
509 m_currentKeyboardGrabbingWindow = window;
510}
511
513{
514 if (!m_currentMouseGrabbingWindow.isNull() && m_lastWsiMouseEvent.has_value()) {
515 auto lastWsiMouseEventValue = m_lastWsiMouseEvent.value();
516 auto *previousCaptureWindow = m_currentMouseGrabbingWindow.data();
517 auto *optLastWindowUnderCursor = lastWsiMouseEventValue.targetWindow.data();
518 auto *optCurrentWindowUnderCursor = qGuiApp->topLevelAt(
519 QHighDpi::fromNativePixels(
520 lastWsiMouseEventValue.globalPosition.toPoint(),
521 lastWsiMouseEventValue.targetWindow.data()));
522
523 if (optLastWindowUnderCursor != nullptr
524 && optCurrentWindowUnderCursor != nullptr
525 && optLastWindowUnderCursor != previousCaptureWindow) {
526 QWindowSystemInterface::handleEnterEvent(
527 optLastWindowUnderCursor, lastWsiMouseEventValue.localPosition,
528 lastWsiMouseEventValue.globalPosition);
529 }
530 }
531 m_currentMouseGrabbingWindow.clear();
532}
533
535{
536 if (m_lastWsiMouseEvent.has_value())
537 return m_lastWsiMouseEvent.value().globalPosition.toPoint();
538
539 auto optLastTouchPosition = qAndThen(
540 m_lastWsiTouchEvent,
541 [](const QWindowSystemInterfaceTouchEvent &touchEvent) {
542 return touchEvent.singleTouchPointEventGlobalPosition;
543 });
544 if (optLastTouchPosition.has_value())
545 return optLastTouchPosition.value();
546
547 auto lastScaledPositionFromApp = QGuiApplicationPrivate::lastCursorPosition.toPoint();
548 auto *screen = qGuiApp->screenAt(lastScaledPositionFromApp);
549 return QHighDpi::toNativePixels(
550 lastScaledPositionFromApp,
551 screen != nullptr
552 ? screen
553 : QGuiApplication::primaryScreen());
554}
555
557{
558 m_currentKeyboardGrabbingWindow.clear();
559}
560
561void QOhosInputMethodEventHandler::handleMouseEvent(const QOhosMouseEvent &wsiEvent)
562{
563 static const QSet<QEvent::Type> mouseButtonPressEventTypes = {
564 QEvent::MouseButtonPress,
565 QEvent::NonClientAreaMouseButtonPress,
566 };
567 static const QSet<QEvent::Type> mouseButtonReleaseEventTypes = {
568 QEvent::MouseButtonRelease,
569 QEvent::NonClientAreaMouseButtonRelease,
570 };
571
572 bool eventTypeIsPress = mouseButtonPressEventTypes.contains(wsiEvent.eventType);
573 bool eventTypeIsRelease = mouseButtonReleaseEventTypes.contains(wsiEvent.eventType);
574
575 if (eventTypeIsPress || eventTypeIsRelease) {
576 m_mouseButtonsState.setFlag(wsiEvent.button, eventTypeIsPress);
577 auto *ohosInputContext = qobject_cast<QOhosInputContext *>(QOhosPlatformIntegration::instance()->inputContext());
578 if (ohosInputContext != nullptr)
579 ohosInputContext->setLastInputTypeToTriggerSoftKeyboard(QOhosInputContext::RequestKeyboardReason::MOUSE);
580 }
581
582 QEvent::Type targetEventType;
583 QWindow *targetWindow;
584 QPointF localPosition;
585 if (!m_currentMouseGrabbingWindow.isNull()) {
586 targetWindow = m_currentMouseGrabbingWindow;
587 localPosition = makeWindowLocalPosition(wsiEvent.globalPosition.toPoint(), targetWindow);
588 switch (wsiEvent.eventType) {
589 case QEvent::NonClientAreaMouseButtonRelease:
590 targetEventType = QEvent::MouseButtonRelease;
591 break;
592 case QEvent::NonClientAreaMouseButtonPress:
593 targetEventType = QEvent::MouseButtonPress;
594 break;
595 case QEvent::NonClientAreaMouseMove:
596 targetEventType = QEvent::MouseMove;
597 break;
598 default:
599 targetEventType = wsiEvent.eventType;
600 break;
601 }
602 } else {
603 targetWindow = wsiEvent.targetWindow;
604 localPosition = wsiEvent.localPosition;
605 targetEventType = wsiEvent.eventType;
606 }
607
608 m_lastWsiMouseEvent = wsiEvent;
609
610 if (targetEventType == QEvent::None) {
611 qOhosPrintfDebug("%s: targetEventType is QEvent::None!", Q_FUNC_INFO);
612 return;
613 }
614
615 QWindowSystemInterface::handleMouseEvent(
616 targetWindow,
617 wsiEvent.timestampMs.count(),
618 localPosition,
619 wsiEvent.globalPosition,
620 m_mouseButtonsState,
621 wsiEvent.button,
622 targetEventType,
623 convertOhosToQtKeyboardModifiers(wsiEvent.modifiers));
624}
625
626void QOhosInputMethodEventHandler::handleTouchEvent(const QWindowSystemInterfaceTouchEvent &touchEvent)
627{
628 if (touchEvent.touchPoints.isEmpty()) {
629 qOhosCritical(QtForOhos) << "TouchPoints list is empty, nothing to do";
630 return;
631 }
632
633 m_lastWsiMouseEvent.reset();
634
635 bool anyEventPressedOrReleased =
636 std::any_of(
637 touchEvent.touchPoints.begin(),
638 touchEvent.touchPoints.end(),
639 [](const QWindowSystemInterface::TouchPoint &touchPoint) {
640 return touchPoint.state == QEventPoint::State::Pressed || touchPoint.state == QEventPoint::State::Released;
641 });
642 if (anyEventPressedOrReleased) {
643 auto *ohosInputContext = qobject_cast<QOhosInputContext *>(QOhosPlatformIntegration::instance()->inputContext());
644 if (ohosInputContext != nullptr)
645 ohosInputContext->setLastInputTypeToTriggerSoftKeyboard(QOhosInputContext::RequestKeyboardReason::TOUCH);
646 }
647
648 updateWindowsUnderTouchPoints(touchEvent);
649
650 m_lastWsiTouchEvent = touchEvent;
651 QWindowSystemInterface::handleTouchEvent(
652 touchEvent.targetWindow, touchEvent.timestampMs.count(),
653 static_cast<const QPointingDevice *>(touchEvent.touchDevice), touchEvent.touchPoints,
654 convertOhosToQtKeyboardModifiers(touchEvent.modifiers));
655}
656
657void QOhosInputMethodEventHandler::updateWindowsUnderTouchPoints(const QWindowSystemInterfaceTouchEvent &touchEvent)
658{
659 const auto &touchPoints = touchEvent.touchPoints;
660 auto *targetWindow = touchEvent.targetWindow;
661
662 const bool allTouchPointsUp = std::all_of(
663 touchPoints.begin(), touchPoints.end(),
664 [](const auto &touchPointData) {
665 return touchPointData.state == QEventPoint::State::Released;
666 });
667
668 const bool anyTouchPointDown = std::any_of(
669 touchPoints.begin(), touchPoints.end(),
670 [](const auto &touchPointData) {
671 return touchPointData.state == QEventPoint::State::Pressed;
672 });
673
674 if (allTouchPointsUp) {
675 std::ignore = m_windowsUnderTouchPoints.erase(targetWindow);
676 } else if (anyTouchPointDown) {
677 auto lastTouchedPair = getLastTouchedWindowWithSeqNoIfPresent();
678 auto nextSeqNo = lastTouchedPair.has_value()
679 ? lastTouchedPair.value().second + 1
680 : 0;
681 m_windowsUnderTouchPoints[targetWindow] = std::make_pair(
682 registerObjectDestroyedSignalHandler(
683 targetWindow, this,
684 [this, targetWindow]() {
685 std::ignore = m_windowsUnderTouchPoints.erase(targetWindow);
686 }),
687 nextSeqNo);
688 }
689}
690
691void QOhosInputMethodEventHandler::registerOnWindowCloseToResetMouseButtonsState(QWindow *window)
692{
693 auto *eventView = QOhosPlatformWindow::fromQWindow(window)->ownedViewOrNull();
694 if (eventView != nullptr) {
695 m_lastMouseEventViewLifetimeTrackerHandle = registerObjectDestroyedSignalHandler(
696 eventView, this,
697 [this]() {
698 m_mouseButtonsState = Qt::NoButton;
699 });
700 }
701}
702
703QT_END_NAMESPACE
void onMouseWheelEvent(const QOhosWheelEvent &event, QWindow *window)
void onNonClientAreaTouchEvents(QWindow *targetWindow, std::vector< QOhosWindowProxy::NonClientAreaTouchEvent > eventBatch)
void onHoverEvent(const QOhosHoverEvent &hoverEvent)
void onMouseEvent(const QOhosMouseEvent &mouseEvent)
void onGestureEventFromNativeNode(const QOhosGestureEvent &gestureEvent)
void onTouchEventFromXComponent(QWindow *targetWindow, std::chrono::nanoseconds timeStamp, const std::vector< QOhosTouchEventTouchPointData > &touchPoints, QInputDevice::DeviceType deviceType, QFlags< OhosKeyboardModifier > modifiers)
void onNonClientAreaMouseEvents(QWindow *targetWindow, std::vector< QOhosWindowProxy::NonClientAreaMouseEvent > eventBatch)
void onKeyEvent(const QOhosKeyEvent &keyEvent, QWindow *targetWindow)
static QOhosPlatformIntegration * instance()
QRectF calculateTouchPointArea(const QPointF &clickPoint)
QPoint determineScreenGlobalDisplayOffset(QWindow *qWindow)
QPoint makeWindowLocalPosition(const QPoint &globalPosition, QWindow *qWindow)
QPointF calculateTouchPointNormalPosition(QWindow *targetWindow, const QPointF &clickPoint)
QInputDevice * createTouchDevice(QInputDevice::DeviceType deviceType)
std::shared_ptr< void > registerObjectDestroyedSignalHandler(QObject *object, QObject *context, std::function< void()> signalHandler)
QOhosOptional< QEventPoint::State > tryMapXComponentTouchEventTypeToQt(::OH_NativeXComponent_TouchEventType eventType)
std::nullopt_t makeEmptyQOhosOptional()