blob: be40c374f4cff245a7507e2ea49c168d72550e62 [file] [log] [blame]
// Copyright 2018 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/pointer_event_buffer.h"
namespace scenic_impl {
namespace input {
using AccessibilityPointerEvent = fuchsia::ui::input::accessibility::PointerEvent;
PointerEventBuffer::PointerEventBuffer(DispatchEventFunction dispatch_events,
ReportAccessibilityEventFunction report_to_accessibility)
: dispatch_events_(std::move(dispatch_events)),
report_to_accessibility_(report_to_accessibility) {}
PointerEventBuffer::~PointerEventBuffer() {
// Any remaining pointer events are dispatched to clients to keep a consistent state.
for (auto& pointer_id_and_streams : buffer_) {
for (auto& stream : pointer_id_and_streams.second) {
for (auto& deferred_events : stream.serial_events) {
dispatch_events_(std::move(deferred_events));
}
}
}
}
void PointerEventBuffer::UpdateStream(uint32_t pointer_id,
fuchsia::ui::input::accessibility::EventHandling handled) {
auto it = buffer_.find(pointer_id);
if (it == buffer_.end()) {
// Empty buffer for this pointer id. Simply return.
return;
}
auto& pointer_id_buffer = it->second;
if (pointer_id_buffer.empty()) {
// there are no streams left.
return;
}
auto& stream = pointer_id_buffer.front();
PointerIdStreamStatus status = PointerIdStreamStatus::WAITING_RESPONSE;
switch (handled) {
case fuchsia::ui::input::accessibility::EventHandling::CONSUMED:
status = PointerIdStreamStatus::CONSUMED;
break;
case fuchsia::ui::input::accessibility::EventHandling::REJECTED:
// the accessibility listener rejected this stream of pointer events
// related to this pointer id. They follow their normal flow and are
// sent to views. All buffered (past events), are sent, as well as
// potential future (in case this stream is not done yet).
status = PointerIdStreamStatus::REJECTED;
for (auto& deferred_events : stream.serial_events) {
dispatch_events_(std::move(deferred_events));
}
// Clears the stream -- objects have been moved, but container still holds
// their space.
stream.serial_events.clear();
break;
};
// Remove this stream from the buffer, as it was already processed.
pointer_id_buffer.pop_front();
// If the buffer is now empty, this means that this stream hasn't finished
// yet. Record this so that incoming future pointer events know where to go.
// Please note that if the buffer is not empty, this means that there are
// streams waiting for a response, thus, this is not the active stream
// anymore. If this is the case, |active_stream_info_| will not be updated
// and thus will still have a status of WAITING_RESPONSE.
if (pointer_id_buffer.empty()) {
SetActiveStreamInfo(pointer_id, status);
}
FXL_DCHECK(pointer_id_buffer.empty() ||
active_stream_info_[pointer_id] == PointerIdStreamStatus::WAITING_RESPONSE)
<< "invariant: streams are waiting, so status is waiting";
}
void PointerEventBuffer::AddEvent(uint32_t pointer_id, DeferredPointerEvent views_and_event,
AccessibilityPointerEvent accessibility_pointer_event) {
auto it = active_stream_info_.find(pointer_id);
FXL_DCHECK(it != active_stream_info_.end()) << "Received an invalid pointer id.";
const auto status = it->second;
if (status == PointerIdStreamStatus::WAITING_RESPONSE) {
PointerIdStream& stream = buffer_[pointer_id].back();
stream.serial_events.emplace_back(std::move(views_and_event));
} else if (status == PointerIdStreamStatus::REJECTED) {
// All previous events were already dispatched when this stream was
// rejected. Sends this new incoming events to their normal flow as well.
// There is still the possibility of triggering a focus change event, when
// ADD -> a11y listener rejected -> DOWN event arrived.
dispatch_events_(std::move(views_and_event));
return;
}
// PointerIdStreamStatus::CONSUMED or PointerIdStreamStatus::WAITING_RESPONSE
// follow the same path: accessibility listener needs to see the pointer event
// to consume / decide if it will consume them.
if (status == PointerIdStreamStatus::WAITING_RESPONSE ||
status == PointerIdStreamStatus::CONSUMED) {
report_to_accessibility_(std::move(accessibility_pointer_event));
}
}
void PointerEventBuffer::AddStream(uint32_t pointer_id) {
auto& pointer_id_buffer = buffer_[pointer_id];
pointer_id_buffer.emplace_back();
active_stream_info_[pointer_id] = PointerIdStreamStatus::WAITING_RESPONSE;
}
} // namespace input
} // namespace scenic_impl