7#include <lib/trace/event.h>
8#include <zircon/status.h>
9#include <zircon/types.h>
13#include "flutter/fml/logging.h"
14#include "flutter/fml/trace_event.h"
20bool operator==(
const fuchsia::ui::pointer::TouchInteractionId&
a,
21 const fuchsia::ui::pointer::TouchInteractionId&
b) {
22 return a.device_id ==
b.device_id &&
a.pointer_id ==
b.pointer_id &&
23 a.interaction_id ==
b.interaction_id;
50 if (!
event.has_pointer_sample()) {
53 FML_DCHECK(
event.pointer_sample().has_interaction()) <<
"API guarantee";
61 if (!
event.has_pointer_sample()) {
64 const auto& sample =
event.pointer_sample();
65 FML_DCHECK(sample.has_device_id()) <<
"API guarantee";
66 FML_DCHECK(sample.has_position_in_viewport()) <<
"API guarantee";
67 FML_DCHECK(!sample.has_pressed_buttons() || !sample.pressed_buttons().empty())
73std::array<float, 2> ViewportToViewCoordinates(
74 std::array<float, 2> viewport_coordinates,
75 const std::array<float, 9>& viewport_to_view_transform) {
86 const auto&
M = viewport_to_view_transform;
87 const float x = viewport_coordinates[0];
88 const float y = viewport_coordinates[1];
89 const float xp =
M[0] *
x +
M[3] *
y +
M[6];
90 const float yp =
M[1] *
x +
M[4] *
y +
M[7];
91 const float wp =
M[2] *
x +
M[5] *
y +
M[8];
93 return {xp / wp, yp / wp};
102 case fup_EventPhase::ADD:
104 case fup_EventPhase::CHANGE:
106 case fup_EventPhase::REMOVE:
108 case fup_EventPhase::CANCEL:
115std::array<float, 2> ClampToViewSpace(
const float x,
118 const float min_x = p.view.min[0];
119 const float min_y = p.view.min[1];
120 const float max_x = p.view.max[0];
121 const float max_y = p.view.max[1];
122 if (min_x <=
x &&
x < max_x && min_y <=
y &&
y < max_y) {
128 const float max_x_inclusive = max_x - std::numeric_limits<float>::epsilon();
129 const float max_y_inclusive = max_y - std::numeric_limits<float>::epsilon();
130 const float& clamped_x = std::clamp(
x, min_x, max_x_inclusive);
131 const float& clamped_y = std::clamp(
y, min_y, max_y_inclusive);
132 FML_LOG(INFO) <<
"Clamped (" <<
x <<
", " <<
y <<
") to (" << clamped_x
133 <<
", " << clamped_y <<
").";
134 return {clamped_x, clamped_y};
138 bool any_button_down,
139 std::unordered_set<uint32_t>& mouse_down,
141 if (!mouse_down.count(
id) && !any_button_down) {
143 }
else if (!mouse_down.count(
id) && any_button_down) {
144 mouse_down.insert(
id);
146 }
else if (mouse_down.count(
id) && any_button_down) {
148 }
else if (mouse_down.count(
id) && !any_button_down) {
149 mouse_down.erase(
id);
160uint64_t PackFuchsiaDeviceIdAndPointerId(uint32_t fuchsia_device_id,
161 uint32_t fuchsia_pointer_id) {
162 return (((uint64_t)fuchsia_device_id) << 32) | fuchsia_pointer_id;
177std::pair<flutter::PointerData, std::optional<flutter::PointerData>>
181 const auto& sample =
event.pointer_sample();
182 const auto& ixn = sample.interaction();
187 ptr.
change = GetChangeFromTouchEventPhase(sample.phase());
192 ptr.
device = PackFuchsiaDeviceIdAndPointerId(ixn.device_id, ixn.pointer_id);
195 ViewportToViewCoordinates(sample.position_in_viewport(),
196 view_parameters.viewport_to_view_transform);
211 return {std::move(ptr), std::move(down)};
216 return {std::move(up), std::move(ptr)};
218 return {std::move(ptr), std::nullopt};
249 const auto& sample =
event.pointer_sample();
256 ptr.
device = sample.device_id();
260 ViewportToViewCoordinates(sample.position_in_viewport(),
261 view_parameters.viewport_to_view_transform);
273 if (sample.has_pressed_buttons()) {
274 int64_t flutter_buttons = 0;
275 const auto&
pressed = sample.pressed_buttons();
276 for (
size_t idx = 0; idx <
pressed.size(); ++idx) {
277 const uint8_t button_id =
pressed[idx];
278 FML_DCHECK(device_info.has_buttons()) <<
"API guarantee";
280 for (uint8_t prio = 0; prio < device_info.buttons().size(); ++prio) {
281 if (button_id == device_info.buttons()[prio]) {
282 flutter_buttons |= (1 << prio);
296 const int kScrollOffsetMultiplier = 20;
300 bool is_scroll =
false;
302 if (sample.has_scroll_v_physical_pixel()) {
303 dy = -sample.scroll_v_physical_pixel();
305 }
else if (sample.has_scroll_v()) {
306 dy = -sample.scroll_v() *
307 kScrollOffsetMultiplier;
312 if (sample.has_scroll_h_physical_pixel()) {
313 dx = sample.scroll_h_physical_pixel();
315 }
else if (sample.has_scroll_h()) {
316 dx = sample.scroll_h() * kScrollOffsetMultiplier;
330void InsertIntoBuffer(
332 std::vector<flutter::PointerData>*
buffer) {
334 buffer->emplace_back(std::move(events.first));
335 if (events.second.has_value()) {
336 buffer->emplace_back(std::move(events.second.value()));
342 fuchsia::ui::pointer::TouchSourceHandle touch_source,
343 fuchsia::ui::pointer::MouseSourceHandle mouse_source)
344 : touch_source_(touch_source.Bind()), mouse_source_(mouse_source.Bind()) {
346 touch_source_.set_error_handler([](zx_status_t status) {
348 << zx_status_get_string(status);
352 mouse_source_.set_error_handler([](zx_status_t status) {
354 << zx_status_get_string(status);
361 std::function<
void(std::vector<flutter::PointerData>)>
callback) {
362 FML_LOG(INFO) <<
"Flutter - PointerDelegate started.";
363 if (touch_responder_) {
364 FML_LOG(
ERROR) <<
"PointerDelegate::WatchLoop() must be called once.";
368 touch_responder_ = [
this,
callback](std::vector<fup_TouchEvent> events) {
369 TRACE_EVENT0(
"flutter",
"PointerDelegate::TouchHandler");
370 FML_DCHECK(touch_responses_.empty()) <<
"precondition";
371 std::vector<flutter::PointerData> to_client;
373 IssueTouchTraceEvent(
event);
376 if (
event.has_view_parameters()) {
377 touch_view_parameters_ = std::move(
event.view_parameters());
379 if (HasValidatedTouchSample(
event)) {
380 const auto& sample =
event.pointer_sample();
381 const auto& ixn = sample.interaction();
382 if (sample.phase() == fup_EventPhase::ADD &&
383 !
event.has_interaction_result()) {
384 touch_buffer_.emplace(ixn, std::vector<flutter::PointerData>());
387 FML_DCHECK(touch_view_parameters_.has_value()) <<
"API guarantee";
388 auto events = CreateTouchDraft(
event, touch_view_parameters_.value());
389 if (touch_buffer_.count(ixn) > 0) {
390 InsertIntoBuffer(std::move(events), &touch_buffer_[ixn]);
392 InsertIntoBuffer(std::move(events), &to_client);
395 response.set_response_type(fup_TouchResponseType::YES);
397 if (
event.has_interaction_result()) {
398 const auto&
result =
event.interaction_result();
399 const auto& ixn =
result.interaction;
400 if (
result.status == fup_TouchIxnStatus::GRANTED &&
401 touch_buffer_.count(ixn) > 0) {
403 to_client.insert(to_client.end(), touch_buffer_[ixn].begin(),
404 touch_buffer_[ixn].end());
406 touch_buffer_.erase(ixn);
408 touch_responses_.push_back(std::move(response));
412 touch_source_->Watch(std::move(touch_responses_),
414 touch_responses_.clear();
417 mouse_responder_ = [
this,
callback](std::vector<fup_MouseEvent> events) {
418 TRACE_EVENT0(
"flutter",
"PointerDelegate::MouseHandler");
419 std::vector<flutter::PointerData> to_client;
421 IssueMouseTraceEvent(
event);
422 if (
event.has_device_info()) {
423 const auto&
id =
event.device_info().id();
424 mouse_device_info_[
id] = std::move(*
event.mutable_device_info());
426 if (
event.has_view_parameters()) {
427 mouse_view_parameters_ = std::move(
event.view_parameters());
429 if (HasValidatedMouseSample(
event)) {
430 const auto& sample =
event.pointer_sample();
431 const auto&
id = sample.device_id();
432 const bool any_button_down = sample.has_pressed_buttons();
433 FML_DCHECK(mouse_view_parameters_.has_value()) <<
"API guarantee";
434 FML_DCHECK(mouse_device_info_.count(
id) > 0) <<
"API guarantee";
436 const auto phase = ComputePhase(any_button_down, mouse_down_,
id);
438 CreateMouseDraft(
event, phase, mouse_view_parameters_.value(),
439 mouse_device_info_[
id]);
440 to_client.emplace_back(std::move(data));
444 mouse_source_->Watch( mouse_responder_);
448 touch_source_->Watch(std::move(touch_responses_), touch_responder_);
449 touch_responses_.clear();
451 mouse_source_->Watch( mouse_responder_);
void WatchLoop(std::function< void(std::vector< flutter::PointerData >)> callback)
PointerDelegate(fuchsia::ui::pointer::TouchSourceHandle touch_source, fuchsia::ui::pointer::MouseSourceHandle mouse_source)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static const uint8_t buffer[]
#define FML_LOG(severity)
#define FML_UNREACHABLE()
#define FML_DCHECK(condition)
fuchsia::ui::pointer::MouseEvent fup_MouseEvent
fuchsia::ui::pointer::TouchInteractionStatus fup_TouchIxnStatus
fuchsia::ui::pointer::MouseDeviceInfo fup_MouseDeviceInfo
fuchsia::ui::pointer::TouchResponse fup_TouchResponse
fuchsia::ui::pointer::ViewParameters fup_ViewParameters
fuchsia::ui::pointer::TouchEvent fup_TouchEvent
fuchsia::ui::pointer::TouchResponseType fup_TouchResponseType
fuchsia::ui::pointer::EventPhase fup_EventPhase
bool operator==(const fuchsia::ui::pointer::TouchInteractionId &a, const fuchsia::ui::pointer::TouchInteractionId &b)
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)