diff options
author | Kirill Burtsev <kirill.burtsev@qt.io> | 2020-10-16 21:07:10 +0200 |
---|---|---|
committer | Kirill Burtsev <kirill.burtsev@qt.io> | 2020-12-02 23:54:03 +0100 |
commit | 7adea5999b3eb1ac77adeb0580cb98ce35eb6ffd (patch) | |
tree | 81cea99cd79bbebe5f7dc7ac0b68bfa3456da558 /src/core/render_widget_host_view_qt.cpp | |
parent | 2dc642d3f97bf457d7cf57265a35eb8b1bd83a8d (diff) |
Fix handling of more than one finger for touch event
This change addresses following wrong assumptions implemented earlier:
* fix assert condition for custom MotionEventQt: pointer index is only
reserved only for two distinct events POINTER_UP and POINTER_DOWN,
which represent one single non first/last pointer up and down event.
* MotionEvent API doesn't support delivering multiple touch point
changes at once, hence code should send every touch point's up/down
step by step to not confuse gesture detection classes in chromimum
(ultimately fixing arising asserts which old code was triggering before).
* MotionEvent shouldn't contain more touch points then were already
forwarded or reported released, hence every step should contain only
part of all touch points received in handleTouchEvent.
Fixes: QTBUG-86389
Change-Id: I62275dc295494f88a6e44f36fe72f5f8227e37d4
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'src/core/render_widget_host_view_qt.cpp')
-rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index c4a07a70c..36ffbea57 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -66,6 +66,7 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/content_switches_internal.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" +#include "content/browser/renderer_host/ui_events_helper.h" #include "content/common/cursors/webcursor.h" #include "content/common/input_messages.h" #include "third_party/skia/include/core/SkColor.h" @@ -198,8 +199,12 @@ public: , flags(flagsFromModifiers(modifiers)) , index(index) { - // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 - Q_ASSERT((action != Action::DOWN && action != Action::UP) || index == 0); + // index is only valid for ACTION_DOWN and ACTION_UP and should correspond to the point causing it + // see blink_event_util.cc:ToWebTouchPointState for details + Q_ASSERT_X((action != Action::POINTER_DOWN && action != Action::POINTER_UP && index == -1) + || (action == Action::POINTER_DOWN && index >= 0 && touchPoint(index).state() == Qt::TouchPointPressed) + || (action == Action::POINTER_UP && index >= 0 && touchPoint(index).state() == Qt::TouchPointReleased), + "MotionEventQt", qPrintable(QString("action: %1, index: %2, state: %3").arg(int(action)).arg(index).arg(touchPoint(index).state()))); } uint32_t GetUniqueEventId() const override { return eventId; } @@ -1231,7 +1236,8 @@ void RenderWidgetHostViewQt::closePopup() void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, content::InputEventAckState ack_result) { Q_UNUSED(touch); const bool eventConsumed = ack_result == content::INPUT_EVENT_ACK_STATE_CONSUMED; - m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, /*fixme: ?? */false); + const bool isSetNonBlocking = content::InputEventAckStateIsSetNonBlocking(ack_result); + m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, isSetNonBlocking); } void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEvent) @@ -1611,6 +1617,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) m_previousTouchPoints.clear(); m_touchMotionStarted = false; break; + default: m_previousTouchPoints = touchPoints; break; @@ -1648,8 +1655,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) action = ui::MotionEvent::Action::CANCEL; } - MotionEventQt me(touchPoints, eventTimestamp, action, ev->modifiers(), - action == ui::MotionEvent::Action::CANCEL ? -1 : 0); + MotionEventQt me(touchPoints, eventTimestamp, action, ev->modifiers()); if (m_touchSelectionController->WillHandleTouchEvent(me)) return; @@ -1692,31 +1698,49 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) #endif } - for (int i = 0; i < touchPoints.size(); ++i) { - ui::MotionEvent::Action action; - switch (touchPoints[i].second.state()) { - case Qt::TouchPointPressed: - if (m_sendMotionActionDown) { - action = ui::MotionEvent::Action::DOWN; - m_sendMotionActionDown = false; - } else { - action = ui::MotionEvent::Action::POINTER_DOWN; + // MEMO for the basis of this logic look into: + // * blink_event_util.cc:ToWebTouchPointState: which is used later to forward touch event + // composed from motion event after gesture recognition + // * gesture_detector.cc:GestureDetector::OnTouchEvent: contains logic for every motion + // event action and corresponding gesture recognition routines + // * input_router_imp.cc:InputRouterImp::SetMovementXYForTouchPoints: expectation about + // touch event content like number of points for different states + + int lastPressIndex = -1; + while ((lastPressIndex + 1) < touchPoints.size() && touchPoints[lastPressIndex + 1].second.state() == Qt::TouchPointPressed) + ++lastPressIndex; + + switch (ev->type()) { + case QEvent::TouchBegin: + processMotionEvent(MotionEventQt(touchPoints.mid(lastPressIndex), + eventTimestamp, ui::MotionEvent::Action::DOWN, ev->modifiers())); + --lastPressIndex; + Q_FALLTHROUGH(); + + case QEvent::TouchUpdate: + for (; lastPressIndex >= 0; --lastPressIndex) { + Q_ASSERT(touchPoints[lastPressIndex].second.state() == Qt::TouchPointPressed); + MotionEventQt me(touchPoints.mid(lastPressIndex), eventTimestamp, ui::MotionEvent::Action::POINTER_DOWN, ev->modifiers(), 0); + processMotionEvent(me); + } + + if (ev->touchPointStates() & Qt::TouchPointMoved) + processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, ui::MotionEvent::Action::MOVE, ev->modifiers())); + + Q_FALLTHROUGH(); + + case QEvent::TouchEnd: + while (!touchPoints.isEmpty() && touchPoints.back().second.state() == Qt::TouchPointReleased) { + auto action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : ui::MotionEvent::Action::UP; + int index = action == ui::MotionEvent::Action::POINTER_UP ? touchPoints.size() - 1 : -1; + processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, action, ev->modifiers(), index)); + touchPoints.pop_back(); } break; - case Qt::TouchPointMoved: - action = ui::MotionEvent::Action::MOVE; - break; - case Qt::TouchPointReleased: - action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : - ui::MotionEvent::Action::UP; - break; - default: - // Ignore Qt::TouchPointStationary - continue; - } - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); - processMotionEvent(motionEvent); + default: + Q_ASSERT_X(false, __FUNCTION__, "Other event types are expected to be already handled."); + break; } } |