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