1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef UI_EVENTS_TEST_EVENT_GENERATOR_H_
6 #define UI_EVENTS_TEST_EVENT_GENERATOR_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/callback.h"
12 #include "base/macros.h"
13 #include "base/time/time.h"
14 #include "ui/events/event.h"
15 #include "ui/events/event_dispatcher.h"
16 #include "ui/events/keycodes/keyboard_codes.h"
17 #include "ui/gfx/geometry/point.h"
18 #include "ui/gfx/native_widget_types.h"
19 
20 namespace ui {
21 class EventSource;
22 class EventTarget;
23 
24 namespace test {
25 
26 // See EventGenerator::GestureScrollSequenceWithCallback for details.
27 using ScrollStepCallback =
28     base::RepeatingCallback<void(EventType, const gfx::Vector2dF&)>;
29 
30 class TestTickClock;
31 class EventGenerator;
32 
33 // A delegate interface for EventGenerator to abstract platform-specific event
34 // targeting and coordinate conversion.
35 class EventGeneratorDelegate {
36  public:
~EventGeneratorDelegate()37   virtual ~EventGeneratorDelegate() {}
38 
39   // This factory function is used by EventGenerator to create a delegate if an
40   // EventGeneratorDelegate was not supplied to the constructor.
41   //
42   // Note: Implementations for Windows/Linux, ChromeOS and Mac differ in the way
43   // they handle the |root_window| and |target_window|. On Windows/Linux all
44   // events are dispatched through the provided |root_window| and the
45   // |target_window| is ignored. On ChromeOS both the |root_window| and
46   // |target_window| are ignored and all events are dispatched through the root
47   // window deduced using the event's screen coordinates. On Mac the concept of
48   // a |root_window| doesn't exist and events will only be dispatched to the
49   // specified |target_window|.
50   using FactoryFunction =
51       base::RepeatingCallback<std::unique_ptr<EventGeneratorDelegate>(
52           EventGenerator* owner,
53           gfx::NativeWindow root_window,
54           gfx::NativeWindow target_window)>;
55   static void SetFactoryFunction(FactoryFunction factory);
56 
57   // Sets the |root_window| on Windows/Linux, ignored on ChromeOS, sets the
58   // |target_window| on Mac.
59   virtual void SetTargetWindow(gfx::NativeWindow target_window) = 0;
60 
61   // The ui::EventTarget at the given |location|.
62   virtual EventTarget* GetTargetAt(const gfx::Point& location) = 0;
63 
64   // The ui::EventSource for the given |target|.
65   virtual EventSource* GetEventSource(EventTarget* target) = 0;
66 
67   // Helper functions to determine the center point of |target| or |window|.
68   virtual gfx::Point CenterOfTarget(const EventTarget* target) const = 0;
69   virtual gfx::Point CenterOfWindow(gfx::NativeWindow window) const = 0;
70 
71   // Convert a point between screen coordinates and |target|'s coordinates.
72   virtual void ConvertPointFromTarget(const EventTarget* target,
73                                       gfx::Point* point) const = 0;
74   virtual void ConvertPointToTarget(const EventTarget* target,
75                                     gfx::Point* point) const = 0;
76 
77   // Converts |point| from |window|'s coordinates to screen coordinates.
78   virtual void ConvertPointFromWindow(gfx::NativeWindow window,
79                                       gfx::Point* point) const = 0;
80 
81   // Convert a point from the coordinate system in the host that contains
82   // |hosted_target| into the root window's coordinate system.
83   virtual void ConvertPointFromHost(const EventTarget* hosted_target,
84                                     gfx::Point* point) const = 0;
85 
86   // Determines if the input method should be the first to handle key events
87   // before dispatching to Views. If it does, the given |event| will be
88   // dispatched and processed by the input method from the host of |target|.
89   virtual ui::EventDispatchDetails DispatchKeyEventToIME(EventTarget* target,
90                                                          ui::KeyEvent* event)
91       WARN_UNUSED_RESULT = 0;
92 };
93 
94 // ui::test::EventGenerator is a tool that generates and dispatches events.
95 // Unlike |ui_controls| package in ui/base/test, this does not use platform
96 // native message loops. Instead, it sends events to the event dispatcher
97 // synchronously.
98 //
99 // This class is not suited for the following cases:
100 //
101 // 1) If your test depends on native events (ui::Event::native_event()).
102 //   This return is empty/NULL event with EventGenerator.
103 // 2) If your test involves nested run loop, such as
104 //    menu or drag & drop. Because this class directly
105 //    post an event to WindowEventDispatcher, this event will not be
106 //    handled in the nested run loop.
107 // 3) Similarly, |base::MessagePumpObserver| will not be invoked.
108 // 4) Any other code that requires native message loops, such as
109 //    tests for WindowTreeHostWin/WindowTreeHostX11.
110 //
111 // If one of these applies to your test, please use |ui_controls|
112 // package instead.
113 //
114 // Note: The coordinates of the points in API is determined by the
115 // EventGeneratorDelegate.
116 class EventGenerator {
117  public:
118   // Create an EventGenerator with EventGeneratorDelegate,
119   // which uses the coordinates conversions and targeting provided by
120   // |delegate|.
121   explicit EventGenerator(std::unique_ptr<EventGeneratorDelegate> delegate);
122 
123   // Creates an EventGenerator with the mouse/touch location (0,0),
124   // which uses the |root_window|'s coordinates and the default delegate for
125   // this platform.
126   explicit EventGenerator(gfx::NativeWindow root_window);
127 
128   // Creates an EventGenerator with the mouse/touch location
129   // at |initial_location|, which uses the |root_window|'s coordinates.
130   EventGenerator(gfx::NativeWindow root_window,
131                  const gfx::Point& initial_location);
132 
133   // Creates an EventGenerator with the mouse/touch location centered over
134   // |target_window|.
135   EventGenerator(gfx::NativeWindow root_window,
136                  gfx::NativeWindow target_window);
137 
138   virtual ~EventGenerator();
139 
140   // Explicitly sets the location used by mouse/touch events, in screen
141   // coordinates. This is set by the various methods that take a location but
142   // can be manipulated directly, typically for touch.
set_current_screen_location(const gfx::Point & location)143   void set_current_screen_location(const gfx::Point& location) {
144     current_screen_location_ = location;
145   }
current_screen_location()146   const gfx::Point& current_screen_location() const {
147     return current_screen_location_;
148   }
149 
150   // Events could be dispatched using different methods. The choice is a
151   // tradeoff between test robustness and coverage of OS internals that affect
152   // event dispatch.
153   // Currently only supported on Mac.
154   enum class Target {
155     // Dispatch through the application. Least robust.
156     APPLICATION,
157     // Dispatch directly to target NSWindow via -sendEvent:.
158     WINDOW,
159     // Default. Emulates default NSWindow dispatch: calls specific event handler
160     // based on event type. Most robust.
161     WIDGET,
162   };
163 
164   // Updates the |current_screen_location_| to point to the middle of the target
165   // window and sets the appropriate dispatcher target.
166   void SetTargetWindow(gfx::NativeWindow target_window);
167 
168   // Selects dispatch method. Currently only supported on Mac.
set_target(Target target)169   void set_target(Target target) { target_ = target; }
target()170   Target target() const { return target_; }
171 
172   // Resets the event flags bitmask.
set_flags(int flags)173   void set_flags(int flags) { flags_ = flags; }
flags()174   int flags() const { return flags_; }
175 
176   // Many tests assume a window created at (0,0) will remain there when shown.
177   // However, an operating system's window manager may reposition the window
178   // into the work area. This can disrupt the coordinates used on test events,
179   // so an EventGeneratorDelegate may skip the step that remaps coordinates in
180   // the root window to window coordinates when dispatching events.
181   // Setting this to false skips that step, in which case the test must ensure
182   // it correctly maps coordinates in window coordinates to root window (screen)
183   // coordinates when calling, e.g., set_current_screen_location().
184   // Default is true. This only has any effect on Mac.
set_assume_window_at_origin(bool assume_window_at_origin)185   void set_assume_window_at_origin(bool assume_window_at_origin) {
186     assume_window_at_origin_ = assume_window_at_origin;
187   }
assume_window_at_origin()188   bool assume_window_at_origin() { return assume_window_at_origin_; }
189 
190   // Generates a left button press event.
191   void PressLeftButton();
192 
193   // Generates a left button release event.
194   void ReleaseLeftButton();
195 
196   // Generates events to click (press, release) left button.
197   void ClickLeftButton();
198 
199   // Generates events to click (press, release) right button.
200   void ClickRightButton();
201 
202   // Generates a double click event using the left button.
203   void DoubleClickLeftButton();
204 
205   // Generates a right button press event.
206   void PressRightButton();
207 
208   // Generates a right button release event.
209   void ReleaseRightButton();
210 
211   // Moves the mouse wheel by |delta_x|, |delta_y|.
212   void MoveMouseWheel(int delta_x, int delta_y);
213 
214   // Generates a mouse enter event.
215   void SendMouseEnter();
216 
217   // Generates a mouse exit.
218   void SendMouseExit();
219 
220   // Generates events to move mouse to be the given |point| in the
221   // |current_root_window_|'s host window coordinates.
222   void MoveMouseToInHost(const gfx::Point& point_in_host);
MoveMouseToInHost(int x,int y)223   void MoveMouseToInHost(int x, int y) {
224     MoveMouseToInHost(gfx::Point(x, y));
225   }
226 
227 #if defined(OS_CHROMEOS)
228   // Generates a mouse move event at the point given in the host
229   // coordinates, with a native event with |point_for_natve|.
230   void MoveMouseToWithNative(const gfx::Point& point_in_host,
231                              const gfx::Point& point_for_native);
232 #endif
233 
234   // Generates events to move mouse to be the given |point| in screen
235   // coordinates.
236   void MoveMouseTo(const gfx::Point& point_in_screen, int count);
MoveMouseTo(const gfx::Point & point_in_screen)237   void MoveMouseTo(const gfx::Point& point_in_screen) {
238     MoveMouseTo(point_in_screen, 1);
239   }
MoveMouseTo(int x,int y)240   void MoveMouseTo(int x, int y) {
241     MoveMouseTo(gfx::Point(x, y));
242   }
243 
244   // Generates events to move mouse to be the given |point| in |window|'s
245   // coordinates.
246   void MoveMouseRelativeTo(const EventTarget* window, const gfx::Point& point);
MoveMouseRelativeTo(const EventTarget * window,int x,int y)247   void MoveMouseRelativeTo(const EventTarget* window, int x, int y) {
248     MoveMouseRelativeTo(window, gfx::Point(x, y));
249   }
250 
MoveMouseBy(int x,int y)251   void MoveMouseBy(int x, int y) {
252     MoveMouseTo(current_screen_location_ + gfx::Vector2d(x, y));
253   }
254 
255   // Generates events to drag mouse to given |point|.
256   void DragMouseTo(const gfx::Point& point);
257 
DragMouseTo(int x,int y)258   void DragMouseTo(int x, int y) {
259     DragMouseTo(gfx::Point(x, y));
260   }
261 
DragMouseBy(int dx,int dy)262   void DragMouseBy(int dx, int dy) {
263     DragMouseTo(current_screen_location_ + gfx::Vector2d(dx, dy));
264   }
265 
266   // Generates events to move the mouse to the center of the window.
267   void MoveMouseToCenterOf(EventTarget* window);
268 
269   // Enter pen-pointer mode, which will cause any generated mouse events to have
270   // a pointer type ui::EventPointerType::kPen.
271   void EnterPenPointerMode();
272 
273   // Exit pen-pointer mode. Generated mouse events will use the default pointer
274   // type event.
275   void ExitPenPointerMode();
276 
277   // Set radius of touch PointerDetails.
278   void SetTouchRadius(float x, float y);
279 
280   // Set tilt of touch PointerDetails.
281   void SetTouchTilt(float x, float y);
282 
283   // Set pointer type of touch PointerDetails.
SetTouchPointerType(ui::EventPointerType type)284   void SetTouchPointerType(ui::EventPointerType type) {
285     touch_pointer_details_.pointer_type = type;
286   }
287 
288   // Set force of touch PointerDetails.
SetTouchForce(float force)289   void SetTouchForce(float force) { touch_pointer_details_.force = force; }
290 
291   // Generates a touch press event. If |touch_location_in_screen| is not null,
292   // the touch press event will happen at |touch_location_in_screen|. Otherwise,
293   // it will happen at the current event location |current_screen_location_|.
294   void PressTouch(const base::Optional<gfx::Point>& touch_location_in_screen =
295                       base::nullopt);
296 
297   // Generates a touch press event with |touch_id|. See PressTouch() event for
298   // the description of |touch_location_in_screen| parameter.
299   void PressTouchId(int touch_id,
300                     const base::Optional<gfx::Point>& touch_location_in_screen =
301                         base::nullopt);
302 
303   // Generates a ET_TOUCH_MOVED event to |point|.
304   void MoveTouch(const gfx::Point& point);
305 
306   // Generates a ET_TOUCH_MOVED event moving by (x, y) from current location.
MoveTouchBy(int x,int y)307   void MoveTouchBy(int x, int y) {
308     MoveTouch(current_screen_location_ + gfx::Vector2d(x, y));
309   }
310 
311   // Generates a ET_TOUCH_MOVED event to |point| with |touch_id|.
312   void MoveTouchId(const gfx::Point& point, int touch_id);
313 
314   // Generates a ET_TOUCH_MOVED event moving (x, y) from current location with
315   // |touch_id|.
MoveTouchIdBy(int touch_id,int x,int y)316   void MoveTouchIdBy(int touch_id, int x, int y) {
317     MoveTouchId(current_screen_location_ + gfx::Vector2d(x, y), touch_id);
318   }
319 
320   // Generates a touch release event.
321   void ReleaseTouch();
322 
323   // Generates a touch release event with |touch_id|.
324   void ReleaseTouchId(int touch_id);
325 
326   // Generates press, move and release event to move touch
327   // to be the given |point|.
328   void PressMoveAndReleaseTouchTo(const gfx::Point& point);
329 
PressMoveAndReleaseTouchTo(int x,int y)330   void PressMoveAndReleaseTouchTo(int x, int y) {
331     PressMoveAndReleaseTouchTo(gfx::Point(x, y));
332   }
333 
PressMoveAndReleaseTouchBy(int x,int y)334   void PressMoveAndReleaseTouchBy(int x, int y) {
335     PressMoveAndReleaseTouchTo(current_screen_location_ + gfx::Vector2d(x, y));
336   }
337 
338   // Generates press, move and release events to move touch
339   // to the center of the window.
340   void PressMoveAndReleaseTouchToCenterOf(EventTarget* window);
341 
342   // Generates and dispatches touch-events required to generate a TAP gesture.
343   // Note that this can generate a number of other gesture events at the same
344   // time (e.g. GESTURE_BEGIN, TAP_DOWN, END).
345   void GestureTapAt(const gfx::Point& point);
346 
347   // Generates press and release touch-events to generate a TAP_DOWN event, but
348   // without generating any scroll or tap events. This can also generate a few
349   // other gesture events (e.g. GESTURE_BEGIN, END).
350   void GestureTapDownAndUp(const gfx::Point& point);
351 
352   // Calculates a time duration that can be used with the given |start|, |end|,
353   // and |steps| values when calling GestureScrollSequence (or
354   // GestureScrollSequenceWithCallback) to achieve the given |velocity|.
355   base::TimeDelta CalculateScrollDurationForFlingVelocity(
356       const gfx::Point& start,
357       const gfx::Point& end,
358       float velocity,
359       int steps);
360 
361   // Generates press, move, release touch-events to generate a sequence of
362   // scroll events. |duration| and |steps| affect the velocity of the scroll,
363   // and depending on these values, this may also generate FLING scroll
364   // gestures. If velocity/fling is irrelevant for the test, then any non-zero
365   // values for these should be sufficient.
366   void GestureScrollSequence(const gfx::Point& start,
367                              const gfx::Point& end,
368                              const base::TimeDelta& duration,
369                              int steps);
370 
371   // The same as GestureScrollSequence(), with the exception that |callback| is
372   // called at each step of the scroll sequence. |callback| is called at the
373   // start of the sequence with ET_GESTURE_SCROLL_BEGIN, followed by one or more
374   // ET_GESTURE_SCROLL_UPDATE and ends with an ET_GESTURE_SCROLL_END.
375   void GestureScrollSequenceWithCallback(const gfx::Point& start,
376                                          const gfx::Point& end,
377                                          const base::TimeDelta& duration,
378                                          int steps,
379                                          const ScrollStepCallback& callback);
380 
381   // Generates press, move, release touch-events to generate a sequence of
382   // multi-finger scroll events. |count| specifies the number of touch-points
383   // that should generate the scroll events. |start| are the starting positions
384   // of all the touch points. |delta| specifies the moving vectors for all
385   // fingers. |delay_adding_finger_ms| are delays in ms from the starting time
386   // till touching down of each finger. |delay_releasing_finger_ms| are delays
387   // in ms from starting time till touching release of each finger. These two
388   // parameters are useful when testing complex gestures that start with 1 or 2
389   // fingers and add fingers with a delay. |steps| and
390   // |event_separation_time_ms| are relevant when testing velocity/fling/swipe,
391   // otherwise these can be any non-zero value.
392   void GestureMultiFingerScrollWithDelays(int count,
393                                           const gfx::Point start[],
394                                           const gfx::Vector2d delta[],
395                                           const int delay_adding_finger_ms[],
396                                           const int delay_releasing_finger_ms[],
397                                           int event_separation_time_ms,
398                                           int steps);
399 
400   // Similar to GestureMultiFingerScrollWithDelays() above. Generates press,
401   // move, release touch-events to generate a sequence of multi-finger scroll
402   // events. All fingers are released at the end of scrolling together. All
403   // fingers move the same amount specified by |move_x| and |move_y|.
404   void GestureMultiFingerScrollWithDelays(int count,
405                                           const gfx::Point start[],
406                                           const int delay_adding_finger_ms[],
407                                           int event_separation_time_ms,
408                                           int steps,
409                                           int move_x,
410                                           int move_y);
411 
412   // Similar to GestureMultiFingerScrollWithDelays(). Generates press, move,
413   // release touch-events to generate a sequence of multi-finger scroll events.
414   // All fingers are pressed at the beginning together and are released at the
415   // end of scrolling together. All fingers move move the same amount specified
416   // by |move_x| and |move_y|.
417   void GestureMultiFingerScroll(int count,
418                                 const gfx::Point start[],
419                                 int event_separation_time_ms,
420                                 int steps,
421                                 int move_x,
422                                 int move_y);
423 
424   // Generates scroll sequences of a FlingCancel, Scrolls, FlingStart, with
425   // constant deltas to |x_offset| and |y_offset| in |steps|.
426   void ScrollSequence(const gfx::Point& start,
427                       const base::TimeDelta& step_delay,
428                       float x_offset,
429                       float y_offset,
430                       int steps,
431                       int num_fingers);
432 
433   // Generate a TrackPad "rest" event. That is, a user resting fingers on the
434   // trackpad without moving. This may then be followed by a ScrollSequence(),
435   // or a CancelTrackpadRest().
436   void GenerateTrackpadRest();
437 
438   // Cancels a previous GenerateTrackpadRest(). That is, a user lifting fingers
439   // from the trackpad without having moved them in any direction.
440   void CancelTrackpadRest();
441 
442   // Generates a key press event. On platforms except Windows and X11, a key
443   // event without native_event() is generated. Note that ui::EF_ flags should
444   // be passed as |flags|, not the native ones like 'ShiftMask' in <X11/X.h>.
445   // TODO(yusukes): Support native_event() on all platforms.
446   void PressKey(KeyboardCode key_code,
447                 int flags,
448                 int source_device_id = ED_UNKNOWN_DEVICE);
449 
450   // Generates a key release event. On platforms except Windows and X11, a key
451   // event without native_event() is generated. Note that ui::EF_ flags should
452   // be passed as |flags|, not the native ones like 'ShiftMask' in <X11/X.h>.
453   // TODO(yusukes): Support native_event() on all platforms.
454   void ReleaseKey(KeyboardCode key_code,
455                   int flags,
456                   int source_device_id = ED_UNKNOWN_DEVICE);
457 
458   // Dispatch the event to the WindowEventDispatcher.
459   void Dispatch(Event* event);
460 
set_current_target(EventTarget * target)461   void set_current_target(EventTarget* target) {
462     current_target_ = target;
463   }
464 
delegate()465   const EventGeneratorDelegate* delegate() const { return delegate_.get(); }
delegate()466   EventGeneratorDelegate* delegate() { return delegate_.get(); }
467 
468  private:
469   // Set up the test context using the delegate.
470   void Init(gfx::NativeWindow root_window, gfx::NativeWindow target_window);
471 
472   // Dispatch a key event to the WindowEventDispatcher.
473   void DispatchKeyEvent(bool is_press,
474                         KeyboardCode key_code,
475                         int flags,
476                         int source_device_id);
477 
478   void UpdateCurrentDispatcher(const gfx::Point& point);
479   void PressButton(int flag);
480   void ReleaseButton(int flag);
481 
482   gfx::Point GetLocationInCurrentRoot() const;
483   gfx::Point CenterOfWindow(const EventTarget* window) const;
484 
485   std::unique_ptr<EventGeneratorDelegate> delegate_;
486   gfx::Point current_screen_location_;
487   EventTarget* current_target_ = nullptr;
488   int flags_ = 0;
489   bool grab_ = false;
490 
491   ui::PointerDetails touch_pointer_details_;
492 
493   // Whether to skip mapping of coordinates from the root window to a hit window
494   // when dispatching events.
495   bool assume_window_at_origin_ = true;
496 
497   Target target_ = Target::WIDGET;
498 
499   std::unique_ptr<TestTickClock> tick_clock_;
500 
501   DISALLOW_COPY_AND_ASSIGN(EventGenerator);
502 };
503 
504 }  // namespace test
505 }  // namespace ui
506 
507 #endif  // UI_EVENTS_TEST_EVENT_GENERATOR_H_
508