chromium/ash/components/arc/compat_mode/touch_mode_mouse_rewriter.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 ASH_COMPONENTS_ARC_COMPAT_MODE_TOUCH_MODE_MOUSE_REWRITER_H_
#define ASH_COMPONENTS_ARC_COMPAT_MODE_TOUCH_MODE_MOUSE_REWRITER_H_

#include <set>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/time/time.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/events/event_rewriter.h"

namespace aura {
class WindowTreeHost;
}  // namespace aura

namespace arc {

// An EventRewriter which rewrites certain mouse/trackpad events that are sent
// to phone-optimized ARC apps. For example, right click will be converted to
// long press, as in many phone-optimized apps it is normal to use long press
// for a secondary action rather than right click.
class TouchModeMouseRewriter : public aura::WindowObserver,
                               public ui::EventRewriter {
 public:
  TouchModeMouseRewriter();
  TouchModeMouseRewriter(const TouchModeMouseRewriter&) = delete;
  TouchModeMouseRewriter& operator=(const TouchModeMouseRewriter&) = delete;
  ~TouchModeMouseRewriter() override;

  // Starts rewriting events sent to |window|.
  void EnableForWindow(aura::Window* window);

  // Stops rewriting events sent to |window|.
  void DisableForWindow(aura::Window* window);

  // aura::WindowObserver:
  void OnWindowDestroying(aura::Window* window) override;
  void OnWindowAddedToRootWindow(aura::Window* window) override;
  void OnWindowRemovingFromRootWindow(aura::Window* window,
                                      aura::Window* new_root) override;

  // ui::EventRewriter:
  ui::EventDispatchDetails RewriteEvent(
      const ui::Event& event,
      const Continuation continuation) override;

 private:
  void SendReleaseEvent(const ui::MouseEvent& original_event,
                        const Continuation continuation);
  void SendScrollEvent(const ui::MouseWheelEvent& original_event,
                       const Continuation continuation);

  ui::EventDispatchDetails RewriteMouseWheelEvent(
      const ui::MouseWheelEvent& event,
      const Continuation continuation);
  ui::EventDispatchDetails RewriteMouseClickEvent(
      const ui::MouseEvent& event,
      const Continuation continuation);
  bool IsInResizeLockedWindow(const aura::Window* window) const;

  // Used for right click long press.
  bool release_event_scheduled_ = false;
  bool left_pressed_ = false;
  bool discard_next_left_release_ = false;

  // Used for mouse wheel smooth scroll.
  int scroll_y_offset_ = 0;
  int scroll_x_offset_ = 0;
  base::TimeDelta scroll_timeout_;

  std::multiset<aura::WindowTreeHost*> hosts_;
  std::set<raw_ptr<const aura::Window, SetExperimental>> enabled_windows_;

  base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
      window_observations_{this};

  base::WeakPtrFactory<TouchModeMouseRewriter> weak_ptr_factory_{this};
};

}  // namespace arc

#endif  // ASH_COMPONENTS_ARC_COMPAT_MODE_TOUCH_MODE_MOUSE_REWRITER_H_