root/ui/aura/test/event_generator.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_AURA_TEST_EVENT_GENERATOR_H_
#define UI_AURA_TEST_EVENT_GENERATOR_H_

#include <list>
#include <vector>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/point.h"

namespace base {
class TimeDelta;
}

namespace ui {
class Event;
class EventProcessor;
class KeyEvent;
class MouseEvent;
class ScrollEvent;
class TouchEvent;
}

namespace aura {
class Window;
class WindowTreeHost;

namespace client {
class ScreenPositionClient;
}

namespace test {

typedef base::Callback<void(ui::EventType, const gfx::Vector2dF&)>
        ScrollStepCallback;

// A delegate interface for EventGenerator that provides a way to
// locate aura root window for given point.
class EventGeneratorDelegate {
 public:
  virtual ~EventGeneratorDelegate() {}

  // Returns the host for given point.
  virtual WindowTreeHost* GetHostAt(const gfx::Point& point) const = 0;

  // Returns the screen position client that determines the
  // coordinates used in EventGenerator. EventGenerator uses
  // root Window's coordinate if this returns NULL.
  virtual client::ScreenPositionClient* GetScreenPositionClient(
      const aura::Window* window) const = 0;
};

// EventGenerator is a tool that generates and dispatch events.
// Unlike |ui_controls| package in ui/base/test, this does not generate platform
// native events. Instead, it sends events to |aura::WindowEventDispatcher|
// synchronously.
//
// This class is not suited for the following cases:
//
// 1) If your test depends on native events (ui::Event::native_event()).
//   This return is empty/NULL event with EventGenerator.
// 2) If your test involves nested message loop, such as
//    menu or drag & drop. Because this class directly
//    post an event to WindowEventDispatcher, this event will not be
//    handled in the nested message loop.
// 3) Similarly, |base::MessagePumpObserver| will not be invoked.
// 4) Any other code that requires native events, such as
//    tests for WindowTreeHostWin/WindowTreeHostX11.
//
// If one of these applies to your test, please use |ui_controls|
// package instead.
//
// Note: The coordinates of the points in API is determined by the
// EventGeneratorDelegate.
class EventGenerator {
 public:
  // Creates an EventGenerator with the mouse/touch location (0,0),
  // which uses the |root_window|'s coordinates.
  explicit EventGenerator(Window* root_window);

  // Create an EventGenerator with EventGeneratorDelegate,
  // which uses the coordinates used by |delegate|.
  explicit EventGenerator(EventGeneratorDelegate* delegate);

  // Creates an EventGenerator with the mouse/touch location
  // at |initial_location|, which uses the |root_window|'s coordinates.
  EventGenerator(Window* root_window, const gfx::Point& initial_location);

  // Creates an EventGenerator with the mouse/touch location
  // centered over |window|, which uses the |root_window|'s coordinates.
  EventGenerator(Window* root_window, Window* window);

  virtual ~EventGenerator();

  // Explicitly sets the location used by mouse/touch events. This is set by the
  // various methods that take a location but can be manipulated directly,
  // typically for touch.
  void set_current_location(const gfx::Point& location) {
    current_location_ = location;
  }
  const gfx::Point& current_location() const { return current_location_; }

  void set_async(bool async) { async_ = async; }
  bool async() const { return async_; }

  // Resets the event flags bitmask.
  void set_flags(int flags) { flags_ = flags; }

  // Generates a left button press event.
  void PressLeftButton();

  // Generates a left button release event.
  void ReleaseLeftButton();

  // Generates events to click (press, release) left button.
  void ClickLeftButton();

  // Generates a double click event using the left button.
  void DoubleClickLeftButton();

  // Generates a right button press event.
  void PressRightButton();

  // Generates a right button release event.
  void ReleaseRightButton();

  // Generates a mouse exit.
  void SendMouseExit();

  // Generates events to move mouse to be the given |point| in the
  // |current_root_window_|'s host window coordinates.
  void MoveMouseToInHost(const gfx::Point& point_in_host);
  void MoveMouseToInHost(int x, int y) {
    MoveMouseToInHost(gfx::Point(x, y));
  }

  // Generates events to move mouse to be the given |point| in screen
  // coordinates.
  void MoveMouseTo(const gfx::Point& point_in_screen, int count);
  void MoveMouseTo(const gfx::Point& point_in_screen) {
    MoveMouseTo(point_in_screen, 1);
  }
  void MoveMouseTo(int x, int y) {
    MoveMouseTo(gfx::Point(x, y));
  }

  // Generates events to move mouse to be the given |point| in |window|'s
  // coordinates.
  void MoveMouseRelativeTo(const Window* window, const gfx::Point& point);
  void MoveMouseRelativeTo(const Window* window, int x, int y) {
    MoveMouseRelativeTo(window, gfx::Point(x, y));
  }

  void MoveMouseBy(int x, int y) {
    MoveMouseTo(current_location_ + gfx::Vector2d(x, y));
  }

  // Generates events to drag mouse to given |point|.
  void DragMouseTo(const gfx::Point& point);

  void DragMouseTo(int x, int y) {
    DragMouseTo(gfx::Point(x, y));
  }

  void DragMouseBy(int dx, int dy) {
    DragMouseTo(current_location_ + gfx::Vector2d(dx, dy));
  }

  // Generates events to move the mouse to the center of the window.
  void MoveMouseToCenterOf(Window* window);

  // Generates a touch press event.
  void PressTouch();

  // Generates a touch press event with |touch_id|.
  void PressTouchId(int touch_id);

  // Generates a ET_TOUCH_MOVED event to |point|.
  void MoveTouch(const gfx::Point& point);

  // Generates a ET_TOUCH_MOVED event to |point| with |touch_id|.
  void MoveTouchId(const gfx::Point& point, int touch_id);

  // Generates a touch release event.
  void ReleaseTouch();

  // Generates a touch release event with |touch_id|.
  void ReleaseTouchId(int touch_id);

  // Generates press, move and release event to move touch
  // to be the given |point|.
  void PressMoveAndReleaseTouchTo(const gfx::Point& point);

  void PressMoveAndReleaseTouchTo(int x, int y) {
    PressMoveAndReleaseTouchTo(gfx::Point(x, y));
  }

  void PressMoveAndReleaseTouchBy(int x, int y) {
    PressMoveAndReleaseTouchTo(current_location_ + gfx::Vector2d(x, y));
  }

  // Generates press, move and release events to move touch
  // to the center of the window.
  void PressMoveAndReleaseTouchToCenterOf(Window* window);

  // Generates and dispatches a Win8 edge-swipe event (swipe up from bottom or
  // swipe down from top).  Note that it is not possible to distinguish between
  // the two edges with this event.
  void GestureEdgeSwipe();

  // Generates and dispatches touch-events required to generate a TAP gesture.
  // Note that this can generate a number of other gesture events at the same
  // time (e.g. GESTURE_BEGIN, TAP_DOWN, END).
  void GestureTapAt(const gfx::Point& point);

  // Generates press and release touch-events to generate a TAP_DOWN event, but
  // without generating any scroll or tap events. This can also generate a few
  // other gesture events (e.g. GESTURE_BEGIN, END).
  void GestureTapDownAndUp(const gfx::Point& point);

  // Generates press, move, release touch-events to generate a sequence of
  // scroll events. |duration| and |steps| affect the velocity of the scroll,
  // and depending on these values, this may also generate FLING scroll
  // gestures. If velocity/fling is irrelevant for the test, then any non-zero
  // values for these should be sufficient.
  void GestureScrollSequence(const gfx::Point& start,
                             const gfx::Point& end,
                             const base::TimeDelta& duration,
                             int steps);

  // The same as GestureScrollSequence(), with the exception that |callback| is
  // called at each step of the scroll sequence. |callback| is called at the
  // start of the sequence with ET_GESTURE_SCROLL_BEGIN, followed by one or more
  // ET_GESTURE_SCROLL_UPDATE and ends with an ET_GESTURE_SCROLL_END.
  void GestureScrollSequenceWithCallback(const gfx::Point& start,
                                         const gfx::Point& end,
                                         const base::TimeDelta& duration,
                                         int steps,
                                         const ScrollStepCallback& callback);

  // Generates press, move, release touch-events to generate a sequence of
  // multi-finger scroll events. |count| specifies the number of touch-points
  // that should generate the scroll events. |start| are the starting positions
  // of all the touch points. |steps| and |event_separation_time_ms| are
  // relevant when testing velocity/fling/swipe, otherwise these can be any
  // non-zero value. |delta_x| and |delta_y| are the amount that each finger
  // should be moved. Internally calls GestureMultiFingerScrollWithDelays
  // with zeros as |delay_adding_finger_ms| forcing all touch down events to be
  // immediate.
  void GestureMultiFingerScroll(int count,
                                const gfx::Point start[],
                                int event_separation_time_ms,
                                int steps,
                                int move_x,
                                int move_y);

  // Generates press, move, release touch-events to generate a sequence of
  // multi-finger scroll events. |count| specifies the number of touch-points
  // that should generate the scroll events. |start| are the starting positions
  // of all the touch points. |delay_adding_finger_ms| are delays in ms from the
  // starting time till touching down of each finger. |delay_adding_finger_ms|
  // is useful when testing complex gestures that start with 1 or 2 fingers and
  // add fingers with a delay. |steps| and |event_separation_time_ms| are
  // relevant when testing velocity/fling/swipe, otherwise these can be any
  // non-zero value. |delta_x| and |delta_y| are the amount that each finger
  // should be moved.
  void GestureMultiFingerScrollWithDelays(int count,
                                          const gfx::Point start[],
                                          const int delay_adding_finger_ms[],
                                          int event_separation_time_ms,
                                          int steps,
                                          int move_x,
                                          int move_y);

  // Generates scroll sequences of a FlingCancel, Scrolls, FlingStart, with
  // constant deltas to |x_offset| and |y_offset| in |steps|.
  void ScrollSequence(const gfx::Point& start,
                      const base::TimeDelta& step_delay,
                      float x_offset,
                      float y_offset,
                      int steps,
                      int num_fingers);

  // Generates scroll sequences of a FlingCancel, Scrolls, FlingStart, sending
  // scrolls of each of the values in |offsets|.
  void ScrollSequence(const gfx::Point& start,
                      const base::TimeDelta& step_delay,
                      const std::vector<gfx::Point>& offsets,
                      int num_fingers);

  // Generates a key press event. On platforms except Windows and X11, a key
  // event without native_event() is generated. Note that ui::EF_ flags should
  // be passed as |flags|, not the native ones like 'ShiftMask' in <X11/X.h>.
  // TODO(yusukes): Support native_event() on all platforms.
  void PressKey(ui::KeyboardCode key_code, int flags);

  // Generates a key release event. On platforms except Windows and X11, a key
  // event without native_event() is generated. Note that ui::EF_ flags should
  // be passed as |flags|, not the native ones like 'ShiftMask' in <X11/X.h>.
  // TODO(yusukes): Support native_event() on all platforms.
  void ReleaseKey(ui::KeyboardCode key_code, int flags);

  // Dispatch the event to the WindowEventDispatcher.
  void Dispatch(ui::Event* event);

  void set_current_host(WindowTreeHost* host) {
    current_host_ = host;
  }

 private:
  // Dispatch a key event to the WindowEventDispatcher.
  void DispatchKeyEvent(bool is_press, ui::KeyboardCode key_code, int flags);

  void UpdateCurrentDispatcher(const gfx::Point& point);
  void PressButton(int flag);
  void ReleaseButton(int flag);

  // Convert a point between API's coordinates and
  // |target|'s coordinates.
  void ConvertPointFromTarget(const aura::Window* target,
                              gfx::Point* point) const;
  void ConvertPointToTarget(const aura::Window* target,
                            gfx::Point* point) const;

  gfx::Point GetLocationInCurrentRoot() const;
  gfx::Point CenterOfWindow(const Window* window) const;

  void DispatchNextPendingEvent();
  void DoDispatchEvent(ui::Event* event, bool async);

  scoped_ptr<EventGeneratorDelegate> delegate_;
  gfx::Point current_location_;
  WindowTreeHost* current_host_;
  int flags_;
  bool grab_;
  std::list<ui::Event*> pending_events_;
  // Set to true to cause events to be posted asynchronously.
  bool async_;

  DISALLOW_COPY_AND_ASSIGN(EventGenerator);
};

}  // namespace test
}  // namespace aura

#endif  // UI_AURA_TEST_EVENT_GENERATOR_H_

/* [<][>][^][v][top][bottom][index][help] */