| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/ui/scenic/lib/input/a11y_legacy_contender.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/lib/fxl/macros.h" |
| |
| namespace scenic_impl { |
| namespace input { |
| |
| A11yLegacyContender::A11yLegacyContender( |
| fit::function<void(StreamId, GestureResponse)> respond, |
| fit::function<void(const InternalTouchEvent& event)> deliver_to_client, |
| GestureContenderInspector& inspector) |
| : GestureContender(ZX_KOID_INVALID), |
| respond_(std::move(respond)), |
| deliver_to_client_(std::move(deliver_to_client)), |
| inspector_(inspector) {} |
| |
| void A11yLegacyContender::UpdateStream(StreamId stream_id, const InternalTouchEvent& event, |
| bool is_end_of_stream, view_tree::BoundingBox) { |
| inspector_.OnInjectedEvents(view_ref_koid_, 1); |
| deliver_to_client_(event); |
| |
| const bool is_new_stream = ongoing_streams_.count(stream_id) == 0; |
| FX_DCHECK(!(won_streams_awaiting_first_message_.count(stream_id) != 0 && !is_new_stream)); |
| if (is_new_stream) { |
| AddStream(stream_id, event.pointer_id); |
| if (won_streams_awaiting_first_message_.count(stream_id)) { |
| ongoing_streams_.at(stream_id).awarded_win = true; |
| won_streams_awaiting_first_message_.erase(stream_id); |
| } |
| } |
| |
| // Check whether we're done. |
| auto& stream = ongoing_streams_[stream_id]; |
| ++stream.num_received_events; |
| stream.has_ended = is_end_of_stream; |
| if (stream.has_ended && stream.awarded_win) { |
| RemoveStream(stream_id); |
| return; |
| } |
| |
| // !consumed, we deliberately hold off responding until OnStreamHandled |
| // consumed && awarded_win, no need to respond |
| if (stream.consumed && !stream.awarded_win) { |
| respond_(stream_id, GestureResponse::kYesPrioritize); |
| } |
| } |
| |
| void A11yLegacyContender::EndContest(StreamId stream_id, bool awarded_win) { |
| inspector_.OnContestDecided(view_ref_koid_, awarded_win); |
| auto it = ongoing_streams_.find(stream_id); |
| if (it == ongoing_streams_.end()) { |
| if (!awarded_win) { |
| // Lost the stream before the first message. |
| return; |
| } |
| const auto [_, success] = won_streams_awaiting_first_message_.emplace(stream_id); |
| FX_DCHECK(success) << "Can't have two EndContest() calls for the same stream."; |
| return; |
| } |
| |
| auto& stream = it->second; |
| stream.awarded_win = awarded_win; |
| if (!awarded_win || (awarded_win && stream.has_ended)) { |
| RemoveStream(stream_id); |
| } |
| } |
| |
| void A11yLegacyContender::OnStreamHandled( |
| uint32_t pointer_id, fuchsia::ui::input::accessibility::EventHandling handled) { |
| if (!pointer_id_to_stream_id_map_.count(pointer_id) || |
| pointer_id_to_stream_id_map_.at(pointer_id).empty()) { |
| FX_LOGS(ERROR) << "Event for unknown pointer_id received. Either a11y unexpectedly lost the " |
| "contest, or a11y sent an unexpected event."; |
| return; |
| } |
| |
| const StreamId stream_id = pointer_id_to_stream_id_map_.at(pointer_id).front(); |
| // Stream is handled. Any future responses on this pointer id will be to the next stream. |
| pointer_id_to_stream_id_map_.at(pointer_id).pop_front(); |
| |
| FX_DCHECK(ongoing_streams_.count(stream_id)); |
| switch (handled) { |
| case fuchsia::ui::input::accessibility::EventHandling::CONSUMED: |
| ongoing_streams_.at(stream_id).consumed = true; |
| for (uint64_t i = 0; i < ongoing_streams_.at(stream_id).num_received_events; ++i) { |
| respond_(stream_id, GestureResponse::kYesPrioritize); |
| // respond_() may trigger a call to EndContest(). If that happened we can return (whether we |
| // won or lost). |
| if (ongoing_streams_.count(stream_id) == 0 || ongoing_streams_.at(stream_id).awarded_win) |
| return; |
| } |
| break; |
| case fuchsia::ui::input::accessibility::EventHandling::REJECTED: |
| respond_(stream_id, GestureResponse::kNo); |
| break; |
| default: |
| FX_LOGS(ERROR) << "Unknown fuchsia::ui::input::accessibility::EventHandling enum received. " |
| "Rejecting stream."; |
| respond_(stream_id, GestureResponse::kNo); |
| break; |
| }; |
| } |
| |
| void A11yLegacyContender::AddStream(StreamId stream_id, uint32_t pointer_id) { |
| const auto [it, success] = ongoing_streams_.emplace(stream_id, Stream{.pointer_id = pointer_id}); |
| FX_DCHECK(success); |
| pointer_id_to_stream_id_map_[pointer_id].push_back(stream_id); |
| } |
| |
| void A11yLegacyContender::RemoveStream(StreamId stream_id) { |
| FX_DCHECK(ongoing_streams_.count(stream_id)); |
| const auto pointer_id = ongoing_streams_.at(stream_id).pointer_id; |
| ongoing_streams_.erase(stream_id); |
| |
| auto id_kv = pointer_id_to_stream_id_map_.find(pointer_id); |
| if (id_kv != pointer_id_to_stream_id_map_.end()) { |
| auto& queue = id_kv->second; |
| for (auto it = queue.begin(); it != queue.end(); ++it) { |
| if (*it == stream_id) { |
| queue.erase(it); |
| break; |
| } |
| } |
| if (queue.empty()) { |
| pointer_id_to_stream_id_map_.erase(pointer_id); |
| } |
| } |
| } |
| |
| } // namespace input |
| } // namespace scenic_impl |