blob: 75adab1d9b3ffc964cde3211859f3b631ea33ff2 [file] [log] [blame]
// Copyright 2022 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/a11y/lib/gesture_manager/gesture_util_v2/util.h"
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/syslog/cpp/macros.h>
namespace a11y::gesture_util_v2 {
namespace {
// Trivial conversion, just massaging types.
::fuchsia::math::PointF Point2ToPointF(std::array<float, 2> point) { return {point[0], point[1]}; }
::fuchsia::math::PointF Centroid(const std::vector<::fuchsia::math::PointF>& points) {
::fuchsia::math::PointF centroid;
for (const auto& point : points) {
centroid.x += point.x;
centroid.y += point.y;
}
centroid.x /= static_cast<float>(points.size());
centroid.y /= static_cast<float>(points.size());
return centroid;
}
void UpdateLastEventInfo(const fuchsia::ui::pointer::augment::TouchEventWithLocalHit& event,
GestureContext* gesture_context) {
FX_DCHECK(event.touch_event.has_pointer_sample());
const auto& sample = event.touch_event.pointer_sample();
FX_DCHECK(sample.has_interaction());
gesture_context->last_event_pointer_id = sample.interaction().pointer_id;
FX_DCHECK(event.touch_event.has_timestamp());
gesture_context->last_event_time = event.touch_event.timestamp();
FX_DCHECK(sample.has_phase());
gesture_context->last_event_phase = sample.phase();
}
} // namespace
::fuchsia::math::PointF GestureContext::StartingCentroid(bool local) const {
std::vector<::fuchsia::math::PointF> points;
for (const auto& it : starting_pointer_locations) {
points.push_back(local ? it.second.local_point : it.second.ndc_point);
}
return Centroid(points);
}
::fuchsia::math::PointF GestureContext::CurrentCentroid(bool local) const {
std::vector<::fuchsia::math::PointF> points;
for (const auto& it : current_pointer_locations) {
points.push_back(local ? it.second.local_point : it.second.ndc_point);
}
return Centroid(points);
}
void InitializeStartingGestureContext(
const fuchsia::ui::pointer::augment::TouchEventWithLocalHit& event,
GestureContext* gesture_context) {
FX_DCHECK(event.touch_event.has_pointer_sample());
const auto& sample = event.touch_event.pointer_sample();
FX_DCHECK(sample.has_interaction());
uint32_t pointer_id = sample.interaction().pointer_id;
gesture_context->view_ref_koid = event.local_viewref_koid;
FX_DCHECK(sample.has_position_in_viewport());
PointerLocation location = {
.pointer_on_screen = true,
.ndc_point = Point2ToPointF(sample.position_in_viewport()),
.local_point = Point2ToPointF(event.local_point),
};
gesture_context->starting_pointer_locations[pointer_id] =
gesture_context->current_pointer_locations[pointer_id] = location;
UpdateLastEventInfo(event, gesture_context);
}
void UpdateGestureContext(const fuchsia::ui::pointer::augment::TouchEventWithLocalHit& event,
bool pointer_on_screen, GestureContext* gesture_context) {
FX_DCHECK(event.touch_event.has_pointer_sample());
const auto& sample = event.touch_event.pointer_sample();
FX_DCHECK(sample.has_interaction());
uint32_t pointer_id = sample.interaction().pointer_id;
gesture_context->view_ref_koid = event.local_viewref_koid;
FX_DCHECK(sample.has_position_in_viewport());
gesture_context->current_pointer_locations[pointer_id].ndc_point =
Point2ToPointF(sample.position_in_viewport());
gesture_context->current_pointer_locations[pointer_id].local_point =
Point2ToPointF(event.local_point);
gesture_context->current_pointer_locations[pointer_id].pointer_on_screen = pointer_on_screen;
UpdateLastEventInfo(event, gesture_context);
}
uint32_t NumberOfFingersOnScreen(const GestureContext& gesture_context) {
uint32_t num_fingers = 0;
for (const auto& it : gesture_context.current_pointer_locations) {
if (it.second.pointer_on_screen) {
num_fingers++;
}
}
return num_fingers;
}
bool FingerIsOnScreen(const GestureContext& gesture_context, uint32_t pointer_id) {
if (!gesture_context.current_pointer_locations.count(pointer_id)) {
return false;
}
return gesture_context.current_pointer_locations.at(pointer_id).pointer_on_screen;
}
void ResetGestureContext(GestureContext* gesture_context) {
gesture_context->view_ref_koid = ZX_KOID_INVALID;
gesture_context->starting_pointer_locations.clear();
gesture_context->current_pointer_locations.clear();
}
bool ValidateTouchEvent(const GestureContext& gesture_context,
const fuchsia::ui::pointer::augment::TouchEventWithLocalHit& event) {
// Check if `event` has all the required fields.
if (event.touch_event.has_timestamp() && event.touch_event.has_pointer_sample() &&
event.touch_event.pointer_sample().has_interaction()) {
uint32_t pointer_id = event.touch_event.pointer_sample().interaction().pointer_id;
return gesture_context.starting_pointer_locations.count(pointer_id);
}
FX_LOGS(INFO) << "Touch event is missing required information.";
return false;
}
bool TouchEventIsValidTap(const GestureContext& gesture_context,
const fuchsia::ui::pointer::augment::TouchEventWithLocalHit& event) {
FX_DCHECK(event.touch_event.has_pointer_sample());
const auto& sample = event.touch_event.pointer_sample();
FX_DCHECK(sample.has_interaction());
uint32_t pointer_id = sample.interaction().pointer_id;
if (!gesture_context.starting_pointer_locations.count(pointer_id)) {
return false;
}
FX_DCHECK(sample.has_position_in_viewport());
return SquareDistanceBetweenPoints(
Point2ToPointF(sample.position_in_viewport()),
gesture_context.starting_pointer_locations.at(pointer_id).ndc_point) <=
kGestureMoveThreshold * kGestureMoveThreshold;
}
float SquareDistanceBetweenPoints(::fuchsia::math::PointF a, ::fuchsia::math::PointF b) {
auto dx = a.x - b.x;
auto dy = a.y - b.y;
return dx * dx + dy * dy;
}
} // namespace a11y::gesture_util_v2