summaryrefslogtreecommitdiffstats
path: root/ui/events/test/event_generator.h
blob: 9a72695355a1bfcd7b1dbad06e5cb15baf601df1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
// Copyright 2014 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_EVENTS_TEST_EVENT_GENERATOR_H_
#define UI_EVENTS_TEST_EVENT_GENERATOR_H_

#include <list>
#include <vector>

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

namespace base {
class TickClock;
}

namespace gfx {
class PointF;
}

namespace ui {
class Event;
class EventProcessor;
class EventSource;
class EventTarget;
class KeyEvent;
class MouseEvent;
class ScrollEvent;
class TouchEvent;

namespace test {

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

class EventGenerator;

// A delegate interface for EventGenerator to abstract platform-specific event
// targeting and coordinate conversion.
class EventGeneratorDelegate {
 public:
  virtual ~EventGeneratorDelegate() {}

  // Set the context of the delegate, whilst it is being used by an active
  // EventGenerator.
  virtual void SetContext(EventGenerator* owner,
                          gfx::NativeWindow root_window,
                          gfx::NativeWindow window) {}

  // The ui::EventTarget at the given |location|.
  virtual EventTarget* GetTargetAt(const gfx::Point& location) = 0;

  // The ui::EventSource for the given |target|.
  virtual EventSource* GetEventSource(EventTarget* target) = 0;

  // Helper functions to determine the center point of |target| or |window|.
  virtual gfx::Point CenterOfTarget(const EventTarget* target) const = 0;
  virtual gfx::Point CenterOfWindow(gfx::NativeWindow window) const = 0;

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

  // Convert a point from the coordinate system in the host that contains
  // |hosted_target| into the root window's coordinate system.
  virtual void ConvertPointFromHost(const EventTarget* hosted_target,
                                    gfx::Point* point) const = 0;
};

// ui::test::EventGenerator is a tool that generates and dispatches events.
// Unlike |ui_controls| package in ui/base/test, this does not use platform
// native message loops. Instead, it sends events to the event dispatcher
// 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 message loops, 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 and the default delegate for
  // this platform.
  explicit EventGenerator(gfx::NativeWindow root_window);

  // Create an EventGenerator with EventGeneratorDelegate,
  // which uses the coordinates conversions and targeting provided 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(gfx::NativeWindow root_window,
                 const gfx::Point& initial_location);

  // Creates an EventGenerator with the mouse/touch location centered over
  // |window|. This is currently the only constructor that works on Mac, since
  // a specific window is required (and there is no root window).
  EventGenerator(gfx::NativeWindow root_window, gfx::NativeWindow 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_; }

  // Dispatch events through the application instead of directly to the
  // target window. Currently only supported on Mac.
  void set_targeting_application(bool targeting_application) {
    targeting_application_ = targeting_application;
  }
  bool targeting_application() const { return targeting_application_; }

  // Resets the event flags bitmask.
  void set_flags(int flags) { flags_ = flags; }
  int flags() const { return 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();

  // Moves the mouse wheel by |delta_x|, |delta_y|.
  void MoveMouseWheel(int delta_x, int delta_y);

  // 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 a mouse move event at the point given in the host
  // coordinates, with a native event with |point_for_natve|.
  void MoveMouseToWithNative(const gfx::Point& point_in_host,
                             const gfx::Point& point_for_native);

  // 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 EventTarget* window, const gfx::Point& point);
  void MoveMouseRelativeTo(const EventTarget* 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(EventTarget* 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(EventTarget* 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);

  // Calculates a time duration that can be used with the given |start|, |end|,
  // and |steps| values when calling GestureScrollSequence (or
  // GestureScrollSequenceWithCallback) to achieve the given |velocity|.
  base::TimeDelta CalculateScrollDurationForFlingVelocity(
      const gfx::Point& start,
      const gfx::Point& end,
      float velocity,
      int steps);

  // 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::PointF>& 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(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(KeyboardCode key_code, int flags);

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

  void set_current_target(EventTarget* target) {
    current_target_ = target;
  }

  // Specify an alternative tick clock to be used for simulating time in tests.
  void SetTickClock(scoped_ptr<base::TickClock> tick_clock);

  // Get the current time from the tick clock.
  base::TimeDelta Now();

  // Default delegate set by a platform-specific GeneratorDelegate singleton.
  static EventGeneratorDelegate* default_delegate;

 private:
  // Set up the test context using the delegate.
  void Init(gfx::NativeWindow root_window, gfx::NativeWindow window_context);

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

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

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

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

  const EventGeneratorDelegate* delegate() const;
  EventGeneratorDelegate* delegate();

  scoped_ptr<EventGeneratorDelegate> delegate_;
  gfx::Point current_location_;
  EventTarget* current_target_;
  int flags_;
  bool grab_;
  std::list<Event*> pending_events_;
  // Set to true to cause events to be posted asynchronously.
  bool async_;
  bool targeting_application_;
  scoped_ptr<base::TickClock> tick_clock_;

  DISALLOW_COPY_AND_ASSIGN(EventGenerator);
};

}  // namespace test
}  // namespace ui

#endif  // UI_EVENTS_TEST_EVENT_GENERATOR_H_