chromium/ui/events/fuchsia/pointer_events_handler.h

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_EVENTS_FUCHSIA_POINTER_EVENTS_HANDLER_H_
#define UI_EVENTS_FUCHSIA_POINTER_EVENTS_HANDLER_H_

#include <fidl/fuchsia.ui.pointer/cpp/fidl.h>

#include <array>
#include <functional>
#include <optional>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback.h"
#include "ui/events/event.h"
#include "ui/events/events_export.h"

namespace ui {

// Helper class for keying into a map.
struct InteractionLess {
  bool operator()(const fuchsia_ui_pointer::TouchInteractionId& interaction_id,
                  const fuchsia_ui_pointer::TouchInteractionId&
                      other_interaction_id) const {
    return (std::hash<uint32_t>()(interaction_id.device_id()) ^
            std::hash<uint32_t>()(interaction_id.pointer_id()) ^
            std::hash<uint32_t>()(interaction_id.interaction_id())) <
           (std::hash<uint32_t>()(other_interaction_id.device_id()) ^
            std::hash<uint32_t>()(other_interaction_id.pointer_id()) ^
            std::hash<uint32_t>()(other_interaction_id.interaction_id()));
  }
};

// Channel processors for fuchsia.ui.pointer.TouchSource and MouseSource
// protocols. It manages the channel state, collects touch and mouse events, and
// surfaces them to FlatlandWindow as ui::Event events for further processing
// and dispatch. ui::Events have logical coordinates and they might be scaled by
// the view pixel ratio in FlatlandWindow to get physical coordinates.
class EVENTS_EXPORT PointerEventsHandler {
 public:
  PointerEventsHandler(
      fidl::ClientEnd<fuchsia_ui_pointer::TouchSource> touch_source,
      fidl::ClientEnd<fuchsia_ui_pointer::MouseSource> mouse_source);
  ~PointerEventsHandler();

  // This function collects Fuchsia's TouchPointerSample and MousePointerSample
  // data and transforms them into ui::Events. It then calls the supplied
  // callback with a vector of ui::Events, which does last processing
  // (applies metrics).
  void StartWatching(base::RepeatingCallback<void(Event*)> event_callback);

 private:
  using MouseDeviceId = uint32_t;

  void OnTouchSourceWatchResult(
      fidl::Result<fuchsia_ui_pointer::TouchSource::Watch>& result);
  void OnMouseSourceWatchResult(
      fidl::Result<fuchsia_ui_pointer::MouseSource::Watch>& result);

  base::RepeatingCallback<void(Event*)> event_callback_;

  // Touch State ---------------------------------------------------------------
  // Channel for touch events from Scenic.
  fidl::Client<fuchsia_ui_pointer::TouchSource> touch_source_;

  // Receive touch events from Scenic. Must be copyable.
  fit::function<void(std::vector<fuchsia_ui_pointer::TouchEvent>)>
      touch_responder_;

  // Per-interaction buffer of touch events from Scenic. When an interaction
  // starts with event.pointer_sample.phase == ADD, we allocate a buffer and
  // store samples. When interaction ownership becomes
  // event.interaction_result.status == GRANTED, we flush the buffer to client,
  // delete the buffer, and all future events in this interaction are flushed
  // direct to client. When interaction ownership becomes DENIED, we delete the
  // buffer, and the client does not get any previous or future events in this
  // interaction.
  base::flat_map<fuchsia_ui_pointer::TouchInteractionId,
                 std::vector<TouchEvent>,
                 InteractionLess>
      touch_buffer_;

  // The fuchsia.ui.pointer.TouchSource protocol allows one in-flight
  // hanging-get Watch() call to gather touch events, and the client is expected
  // to respond with consumption intent on the following hanging-get Watch()
  // call. Store responses here for the next call.
  std::vector<fuchsia_ui_pointer::TouchResponse> touch_responses_;

  // The fuchsia.ui.pointer.TouchSource protocol issues channel-global view
  // parameters on connection and on change. Events must apply these view
  // parameters to correctly map to logical view coordinates. The "nullopt"
  // state represents the absence of view parameters, early in the protocol
  // lifecycle.
  std::optional<fuchsia_ui_pointer::ViewParameters> touch_view_parameters_;

  // Mouse State ---------------------------------------------------------------
  // Channel for mouse events from Scenic.
  fidl::Client<fuchsia_ui_pointer::MouseSource> mouse_source_;

  // Receive mouse events from Scenic. Must be copyable.
  fit::function<void(std::vector<fuchsia_ui_pointer::MouseEvent>)>
      mouse_responder_;

  // Each MouseDeviceId maps to the bitmap of currently pressed buttons for that
  // mouse. For example, if the 11th bit is set in a given |mouse_down[id]|,
  // then the left mouse button is pressed, since EF_LEFT_MOUSE_BUTTON == 1 <<
  // 11, as defined in ui/events/event_constants.h.
  //
  // The high level algorithm for any given mouse and button is:
  //   if !mouse_down[id] && !button then: change = EventType::kMouseMoved
  //   if !mouse_down[id] &&  button then: change = EventType::kMousePressed;
  //       mouse_down[id] |= button // sets button bit to 1
  //   if  mouse_down[id] &&  button then: change = EventType::kMouseDragged
  //   if  mouse_down[id] && !button then: change = EventType::kMouseReleased;
  //       mouse_down[id] ^= button // sets button bit to 0
  base::flat_map<MouseDeviceId, /*pressed_buttons_flags=*/int> mouse_down_;

  // For each mouse device, its device-specific information, such as mouse
  // button priority order.
  base::flat_map<MouseDeviceId, fuchsia_ui_pointer::MouseDeviceInfo>
      mouse_device_info_;

  // The fuchsia.ui.pointer.MouseSource protocol issues channel-global view
  // parameters on connection and on change. Events must apply these view
  // parameters to correctly map to logical view coordinates. The "nullopt"
  // state represents the absence of view parameters, early in the protocol
  // lifecycle.
  std::optional<fuchsia_ui_pointer::ViewParameters> mouse_view_parameters_;
};

}  // namespace ui

#endif  // UI_EVENTS_FUCHSIA_POINTER_EVENTS_HANDLER_H_