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>
15#include <arkui/ui_input_event.h>
17#include <render/qohosview.h>
20using namespace Qt::Literals::StringLiterals;
22namespace ch =
std::chrono;
33 qOhosDebug(QtForOhos) <<
"Creating 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,
43 auto *touchDeviceRaw = touchDevice.get();
44 QWindowSystemInterface::registerInputDevice(touchDevice.release());
45 return touchDeviceRaw;
49 QObject *object, QObject *context,
std::function<
void()> signalHandler)
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);
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:
76 auto *platformScreen =
static_cast<
QOhosPlatformScreen *>(targetWindow->screen()->handle());
78 QSize screenSizeScaled = QHighDpi::fromNative(
79 platformScreen->geometry().size(),
80 platformScreen->pixelScalingCoefficient());
82 QPointF clickPointNormalized(
83 clickPoint.x() / screenSizeScaled.width(),
84 clickPoint.y() / screenSizeScaled.height());
86 return clickPointNormalized;
101 const std::set<QInputDevice::DeviceType> &deviceTypes)
103 for (
const auto &deviceType : deviceTypes)
104 m_touchDevices.emplace(deviceType, createTouchDevice(deviceType));
110 QWindow *targetWindow, ch::nanoseconds timeStamp,
111 const std::vector<QOhosTouchEventTouchPointData> &touchPoints,
112 QInputDevice::DeviceType deviceType)
114 auto *touchDevice = getTouchDeviceOrCreateIfNeeded(deviceType);
116 QList<QWindowSystemInterface::TouchPoint> wsiTouchPoints;
118 for (
const auto &touchPointData : touchPoints) {
119 const auto &touchPoint = touchPointData.touchPoint;
120 QEventPoint::State state =
121 tryMapXComponentTouchEventTypeToQt(touchPoint.type)
122 .valueOr(QEventPoint::State::Stationary);
124 QPointF clickPoint = touchPointData.displayPosition;
126 QWindowSystemInterface::TouchPoint qwsiTouchPoint;
127 qwsiTouchPoint.id = touchPoint.id;
128 qwsiTouchPoint.pressure = touchPoint.force;
129 qwsiTouchPoint.normalPosition =
130 calculateTouchPointNormalPosition(targetWindow, clickPoint);
131 qwsiTouchPoint.state = state;
132 qwsiTouchPoint.area = calculateTouchPointArea(clickPoint);
133 wsiTouchPoints.push_back(qwsiTouchPoint);
136 QWindowSystemInterfaceTouchEvent touchEvent = {
137 .targetWindow = targetWindow,
138 .touchPoints = wsiTouchPoints,
139 .touchDevice = touchDevice,
140 .timestampMs = ch::duration_cast<ch::milliseconds>(timeStamp),
143 handleTouchEvent(touchEvent);
147 QWindow *targetWindow,
std::int64_t timestamp, qreal value, QPointF localPosition,
148 QPointF screenPosition, Qt::NativeGestureType gestureType,
149 QInputDevice::DeviceType deviceType)
151 auto *touchDevice = getTouchDeviceOrCreateIfNeeded(deviceType);
153 QWindowSystemInterface::handleGestureEventWithRealValue(
154 targetWindow, timestamp,
static_cast<
const QPointingDevice *>(touchDevice), gestureType, value, localPosition, screenPosition);
160 if (!optQOhosQtKeyEvent.hasValue())
162 const auto qOhosQtKeyEvent = optQOhosQtKeyEvent.value();
164 constexpr quint32 nativeScanCode = 0;
165 constexpr quint32 nativeModifiers = 0;
168 if (ohosInputContext !=
nullptr)
169 ohosInputContext->setLastInputTypeToTriggerSoftKeyboard(QOhosInputContext::RequestKeyboardReason::NONE);
171 if (qOhosQtKeyEvent.keyAction == QEvent::KeyPress) {
172 if (m_autoRepeatCountMap[qOhosQtKeyEvent.keyCode] < std::numeric_limits<ushort>::max()) {
173 ++m_autoRepeatCountMap[qOhosQtKeyEvent.keyCode];
176 m_autoRepeatCountMap.remove(qOhosQtKeyEvent.keyCode);
178 const auto count = m_autoRepeatCountMap.value(qOhosQtKeyEvent.keyCode, 1);
180 QWindowSystemInterface::handleExtendedKeyEvent(
181 !m_currentKeyboardGrabbingWindow.isNull()
182 ? m_currentKeyboardGrabbingWindow.data()
184 qOhosQtKeyEvent.keyAction, qOhosQtKeyEvent.keyCode,
185 qOhosQtKeyEvent.guiApplicationKeyboardModifiers, nativeScanCode,
186 qOhosQtKeyEvent.nativeKeyCode, nativeModifiers, qOhosQtKeyEvent.keyText, count > 1, count);
191 Qt::MouseButton button = Qt::NoButton;
193 if (mouseEvent.eventType == QEvent::MouseButtonPress || mouseEvent.eventType == QEvent::MouseButtonRelease) {
194 button = mouseEvent.button;
203 registerOnWindowCloseToResetMouseButtonsState(mouseEvent.targetWindow);
207 .targetWindow = mouseEvent.targetWindow,
208 .timestampMs = mouseEvent.timestampMs,
209 .localPosition = mouseEvent.localPosition,
210 .globalPosition = mouseEvent.globalPosition,
212 .eventType = mouseEvent.eventType,
213 .modifiers = mouseEvent.modifiers,
216 handleMouseEvent(wsiEvent);
221 if (!m_currentMouseGrabbingWindow.isNull() && m_currentMouseGrabbingWindow != window)
225 QWindowSystemInterface::handleEnterEvent(window, local, global);
227 QWindowSystemInterface::handleLeaveEvent(window);
232 constexpr int angleXMin = -120;
233 constexpr int angleXMax = 120;
234 constexpr int xAxisValueMultiplier = -10;
236 constexpr int angleYMin = angleXMin;
237 constexpr int angleYMax = angleXMax;
238 constexpr int yAxisValueMultiplier = xAxisValueMultiplier;
240 constexpr double wheelStepDegree = 15.0;
241 constexpr double wheelStepPixel = 21.0;
243 constexpr double angleBaseValue = 8.0;
244 constexpr double directionMultiplier = -1.0;
249 if (event.axisAction != UI_AXIS_EVENT_ACTION_UPDATE)
252 static_cast<QOhosPlatformTheme *>(QGuiApplicationPrivate::platformTheme())->setWheelScrollLines(
253 static_cast<
int>(event.wheelScrollLines));
257 if (event.eventToolType == UI_INPUT_EVENT_TOOL_TYPE_MOUSE) {
258 angleDelta.setX(qBound(angleXMin,
static_cast<
int>(event
.horizontalValue * xAxisValueMultiplier), angleXMax));
259 angleDelta.setY(qBound(angleYMin,
static_cast<
int>(event
.verticalValue * yAxisValueMultiplier), angleYMax));
261 auto mousePixelDeltaMultiplier = wheelStepPixel / wheelStepDegree / angleBaseValue;
263 qRound(qFabs(angleDelta.x() * mousePixelDeltaMultiplier) * platformScreen->pixelScalingCoefficient()));
265 qRound(qFabs(angleDelta.y() * mousePixelDeltaMultiplier) * platformScreen->pixelScalingCoefficient()));
266 }
else if (event.eventToolType == UI_INPUT_EVENT_TOOL_TYPE_TOUCHPAD) {
267 auto touchpadAngleDeltaMultiplier =
268 wheelStepDegree / wheelStepPixel / platformScreen->pixelScalingCoefficient() * angleBaseValue * directionMultiplier / event
.wheelScrollLines;
269 angleDelta.setX(qRound(event
.horizontalValue * touchpadAngleDeltaMultiplier));
270 angleDelta.setY(qRound(event
.verticalValue * touchpadAngleDeltaMultiplier));
275 qOhosWarning(QtForOhos)
277 <<
"Received unsupported input event tool type =" << event.eventToolType <<
"skipping...";
281 Qt::MouseEventSource source = event.eventToolType == ::UI_INPUT_EVENT_TOOL_TYPE_TOUCHPAD
282 ? Qt::MouseEventSynthesizedBySystem
283 : Qt::MouseEventNotSynthesized;
284 bool inverted =
false;
286 QWindowSystemInterface::handleWheelEvent(
293 convertOhosToQtKeyboardModifiers(event.modifiers),
300 QWindow *targetWindow, std::vector<QOhosWindowProxy::NonClientAreaMouseEvent> eventBatch)
305 QtOhos::removeMatchingWithLookahead(
306 eventBatch.begin(), eventBatch.end(),
307 [](
const NonClientAreaMouseEvent &event,
const NonClientAreaMouseEvent &nextEvent) {
308 return event.action == QEvent::NonClientAreaMouseMove
309 && nextEvent.action == QEvent::NonClientAreaMouseMove;
313 for (
const auto &mouseEvent : eventBatch) {
314 QOhosMouseEvent qtMouseEvent = {
315 .targetWindow = targetWindow,
316 .timestampMs = mouseEvent.timestamp,
317 .localPosition = mouseEvent.localPosition,
318 .globalPosition = mouseEvent.displayPosition,
319 .button = mouseEvent.button,
320 .eventType = mouseEvent.action,
330 if (mouseEvent.action == QEvent::NonClientAreaMouseButtonPress)
331 registerOnWindowCloseToResetMouseButtonsState(targetWindow);
333 handleMouseEvent(qtMouseEvent);
338 QWindow *targetWindow, std::vector<QOhosWindowProxy::NonClientAreaTouchEvent> eventBatch)
343 QtOhos::removeMatchingWithLookahead(
344 eventBatch.begin(), eventBatch.end(),
345 [](
const NonClientAreaTouchEvent &event,
const NonClientAreaTouchEvent &nextEvent) {
347 event.state == QEventPoint::State::Updated
348 && nextEvent.state == QEventPoint::State::Updated;
352 for (
const auto &touchEvent : eventBatch) {
353 QPointF clickPoint = touchEvent.displayPosition;
355 QWindowSystemInterface::TouchPoint qwsiTouchPoint;
356 qwsiTouchPoint.id = touchEvent.id;
357 qwsiTouchPoint.pressure = 1.0;
358 qwsiTouchPoint.normalPosition = calculateTouchPointNormalPosition(targetWindow, clickPoint);
359 qwsiTouchPoint.state = touchEvent.state;
360 qwsiTouchPoint.area = calculateTouchPointArea(clickPoint);
362 QWindowSystemInterfaceTouchEvent qwsiTouchEvent = {
363 .targetWindow = targetWindow,
364 .touchPoints = {qwsiTouchPoint},
365 .touchDevice = getTouchDeviceOrCreateIfNeeded(QInputDevice::DeviceType::TouchScreen),
366 .timestampMs = touchEvent.timestamp,
369 handleTouchEvent(qwsiTouchEvent);
375 auto lastTouchedPair = getLastTouchedWindowWithSeqNoIfPresent();
376 return lastTouchedPair.hasValue()
377 ? lastTouchedPair.value().first
383 auto touchDeviceIter = m_touchDevices.find(deviceType);
384 if (touchDeviceIter == m_touchDevices.end()) {
385 qOhosWarning(QtForOhos) <<
"Trying to get touch device but it isn't registered. Creating and registering one now.";
386 std::tie(touchDeviceIter, std::ignore) = m_touchDevices.emplace(
387 deviceType, createTouchDevice(deviceType));
389 return touchDeviceIter->second;
394 auto maxSeqNoEntryIter =
std::max_element(
395 m_windowsUnderTouchPoints.begin(), m_windowsUnderTouchPoints.end(),
396 [](
const auto &a,
const auto &b) {
397 return a.second.second < b.second.second;
400 return maxSeqNoEntryIter != m_windowsUnderTouchPoints.end()
402 std::make_pair(maxSeqNoEntryIter->first, maxSeqNoEntryIter->second.second))
403 : makeEmptyQOhosOptional();
408 qCDebug(QtForOhos) << Q_FUNC_INFO <<
"window:" << window;
409 m_currentMouseGrabbingWindow = window;
414 qCDebug(QtForOhos) << Q_FUNC_INFO <<
"window:" << window;
415 m_currentKeyboardGrabbingWindow = window;
420 if (!m_currentMouseGrabbingWindow.isNull() && m_lastWsiMouseEvent.hasValue()) {
421 auto lastWsiMouseEventValue = m_lastWsiMouseEvent.value();
422 auto *previousCaptureWindow = m_currentMouseGrabbingWindow.data();
423 auto *optLastWindowUnderCursor = lastWsiMouseEventValue.targetWindow.data();
424 auto *optCurrentWindowUnderCursor = qGuiApp->topLevelAt(
425 QHighDpi::fromNativePixels(
426 lastWsiMouseEventValue.globalPosition.toPoint(),
427 lastWsiMouseEventValue.targetWindow.data()));
429 if (optLastWindowUnderCursor !=
nullptr
430 && optCurrentWindowUnderCursor !=
nullptr
431 && optLastWindowUnderCursor != previousCaptureWindow) {
432 QWindowSystemInterface::handleEnterEvent(
433 optLastWindowUnderCursor, lastWsiMouseEventValue.localPosition,
434 lastWsiMouseEventValue.globalPosition);
437 m_currentMouseGrabbingWindow.clear();
442 m_currentKeyboardGrabbingWindow.clear();
447 static const QSet<QEvent::Type> mouseButtonPressEventTypes = {
448 QEvent::MouseButtonPress,
449 QEvent::NonClientAreaMouseButtonPress,
451 static const QSet<QEvent::Type> mouseButtonReleaseEventTypes = {
452 QEvent::MouseButtonRelease,
453 QEvent::NonClientAreaMouseButtonRelease,
456 bool eventTypeIsPress = mouseButtonPressEventTypes.contains(wsiEvent.eventType);
457 bool eventTypeIsRelease = mouseButtonReleaseEventTypes.contains(wsiEvent.eventType);
459 if (eventTypeIsPress || eventTypeIsRelease) {
460 m_mouseButtonsState.setFlag(wsiEvent.button, eventTypeIsPress);
462 if (ohosInputContext !=
nullptr)
463 ohosInputContext->setLastInputTypeToTriggerSoftKeyboard(QOhosInputContext::RequestKeyboardReason::MOUSE);
466 QEvent::Type targetEventType;
467 QWindow *targetWindow;
468 QPointF localPosition;
469 if (!m_currentMouseGrabbingWindow.isNull()) {
470 targetWindow = m_currentMouseGrabbingWindow;
472 QHighDpi::toNativeLocalPosition(
473 targetWindow->mapFromGlobal(
474 wsiEvent.targetWindow->mapToGlobal(
475 QHighDpi::fromNativePixels(
476 wsiEvent.localPosition.toPoint(), wsiEvent.targetWindow.data()))),
478 switch (wsiEvent.eventType) {
479 case QEvent::NonClientAreaMouseButtonRelease:
480 targetEventType = QEvent::MouseButtonRelease;
482 case QEvent::NonClientAreaMouseButtonPress:
483 targetEventType = QEvent::MouseButtonPress;
485 case QEvent::NonClientAreaMouseMove:
486 targetEventType = QEvent::MouseMove;
489 targetEventType = wsiEvent.eventType;
493 targetWindow = wsiEvent.targetWindow;
494 localPosition = wsiEvent.localPosition;
495 targetEventType = wsiEvent.eventType;
498 m_lastWsiMouseEvent = wsiEvent;
500 if (targetEventType == QEvent::None) {
501 qOhosPrintfDebug(
"%s: targetEventType is QEvent::None!", Q_FUNC_INFO);
505 QWindowSystemInterface::handleMouseEvent(
507 wsiEvent.timestampMs.count(),
509 wsiEvent.globalPosition,
513 convertOhosToQtKeyboardModifiers(wsiEvent.modifiers));
518 if (touchEvent.touchPoints.isEmpty()) {
519 qOhosCritical(QtForOhos) <<
"TouchPoints list is empty, nothing to do";
523 m_lastWsiMouseEvent.reset();
525 bool anyEventPressedOrReleased =
527 touchEvent.touchPoints.begin(),
528 touchEvent.touchPoints.end(),
529 [](
const QWindowSystemInterface::TouchPoint &touchPoint) {
530 return touchPoint.state == QEventPoint::State::Pressed || touchPoint.state == QEventPoint::State::Released;
532 if (anyEventPressedOrReleased) {
534 if (ohosInputContext !=
nullptr)
535 ohosInputContext->setLastInputTypeToTriggerSoftKeyboard(QOhosInputContext::RequestKeyboardReason::TOUCH);
538 updateWindowsUnderTouchPoints(touchEvent);
540 QWindowSystemInterface::handleTouchEvent(
541 touchEvent.targetWindow, touchEvent.timestampMs.count(),
542 static_cast<
const QPointingDevice *>(touchEvent.touchDevice), touchEvent.touchPoints);
547 const auto &touchPoints = touchEvent.touchPoints;
548 auto *targetWindow = touchEvent.targetWindow;
550 const bool allTouchPointsUp =
std::all_of(
551 touchPoints.begin(), touchPoints.end(),
552 [](
const auto &touchPointData) {
553 return touchPointData.state == QEventPoint::State::Released;
556 const bool anyTouchPointDown =
std::any_of(
557 touchPoints.begin(), touchPoints.end(),
558 [](
const auto &touchPointData) {
559 return touchPointData.state == QEventPoint::State::Pressed;
562 if (allTouchPointsUp) {
563 std::ignore = m_windowsUnderTouchPoints.erase(targetWindow);
564 }
else if (anyTouchPointDown) {
565 auto lastTouchedPair = getLastTouchedWindowWithSeqNoIfPresent();
566 auto nextSeqNo = lastTouchedPair.hasValue()
567 ? lastTouchedPair.value().second + 1
569 m_windowsUnderTouchPoints[targetWindow] = std::make_pair(
570 registerObjectDestroyedSignalHandler(
572 [
this, targetWindow]() {
573 std::ignore = m_windowsUnderTouchPoints.erase(targetWindow);
581 auto *eventView = QOhosPlatformWindow::fromQWindow(window)->ownedViewOrNull();
582 if (eventView !=
nullptr) {
583 m_lastMouseEventViewLifetimeTrackerHandle = registerObjectDestroyedSignalHandler(
586 m_mouseButtonsState = Qt::NoButton;
virtual QOhosOptional< QOhosQtKeyEvent > tryConvertToQOhosQtKeyEvent() const =0
QRectF calculateTouchPointArea(const QPointF &clickPoint)
QPointF calculateTouchPointNormalPosition(QWindow *targetWindow, const QPointF &clickPoint)
QInputDevice * createTouchDevice(QInputDevice::DeviceType deviceType)
constexpr double fingerAreaWidth
std::shared_ptr< void > registerObjectDestroyedSignalHandler(QObject *object, QObject *context, std::function< void()> signalHandler)
QOhosOptional< QEventPoint::State > tryMapXComponentTouchEventTypeToQt(::OH_NativeXComponent_TouchEventType eventType)
constexpr double fingerAreaHeight
QOhosOptional< void > makeEmptyQOhosOptional()