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