Home | History | Annotate | Download | only in test
      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 #include "ui/events/test/event_generator.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/location.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/single_thread_task_runner.h"
     11 #include "base/thread_task_runner_handle.h"
     12 #include "base/time/default_tick_clock.h"
     13 #include "ui/events/event.h"
     14 #include "ui/events/event_source.h"
     15 #include "ui/events/event_utils.h"
     16 #include "ui/events/test/events_test_utils.h"
     17 #include "ui/gfx/vector2d_conversions.h"
     18 
     19 #if defined(USE_X11)
     20 #include <X11/Xlib.h>
     21 #include "ui/events/test/events_test_utils_x11.h"
     22 #endif
     23 
     24 #if defined(OS_WIN)
     25 #include "ui/events/keycodes/keyboard_code_conversion.h"
     26 #endif
     27 
     28 namespace ui {
     29 namespace test {
     30 namespace {
     31 
     32 void DummyCallback(EventType, const gfx::Vector2dF&) {
     33 }
     34 
     35 class TestKeyEvent : public ui::KeyEvent {
     36  public:
     37   TestKeyEvent(const base::NativeEvent& native_event, int flags)
     38       : KeyEvent(native_event) {
     39     set_flags(flags);
     40   }
     41 };
     42 
     43 class TestTouchEvent : public ui::TouchEvent {
     44  public:
     45   TestTouchEvent(ui::EventType type,
     46                  const gfx::Point& root_location,
     47                  int touch_id,
     48                  int flags,
     49                  base::TimeDelta timestamp)
     50       : TouchEvent(type, root_location, flags, touch_id, timestamp,
     51                    1.0f, 1.0f, 0.0f, 0.0f) {
     52   }
     53 
     54  private:
     55   DISALLOW_COPY_AND_ASSIGN(TestTouchEvent);
     56 };
     57 
     58 const int kAllButtonMask = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON;
     59 
     60 }  // namespace
     61 
     62 EventGeneratorDelegate* EventGenerator::default_delegate = NULL;
     63 
     64 EventGenerator::EventGenerator(gfx::NativeWindow root_window)
     65     : current_target_(NULL),
     66       flags_(0),
     67       grab_(false),
     68       async_(false),
     69       tick_clock_(new base::DefaultTickClock()) {
     70   Init(root_window, NULL);
     71 }
     72 
     73 EventGenerator::EventGenerator(gfx::NativeWindow root_window,
     74                                const gfx::Point& point)
     75     : current_location_(point),
     76       current_target_(NULL),
     77       flags_(0),
     78       grab_(false),
     79       async_(false),
     80       tick_clock_(new base::DefaultTickClock()) {
     81   Init(root_window, NULL);
     82 }
     83 
     84 EventGenerator::EventGenerator(gfx::NativeWindow root_window,
     85                                gfx::NativeWindow window)
     86     : current_target_(NULL),
     87       flags_(0),
     88       grab_(false),
     89       async_(false),
     90       tick_clock_(new base::DefaultTickClock()) {
     91   Init(root_window, window);
     92 }
     93 
     94 EventGenerator::EventGenerator(EventGeneratorDelegate* delegate)
     95     : delegate_(delegate),
     96       current_target_(NULL),
     97       flags_(0),
     98       grab_(false),
     99       async_(false),
    100       tick_clock_(new base::DefaultTickClock()) {
    101   Init(NULL, NULL);
    102 }
    103 
    104 EventGenerator::~EventGenerator() {
    105   for (std::list<ui::Event*>::iterator i = pending_events_.begin();
    106       i != pending_events_.end(); ++i)
    107     delete *i;
    108   pending_events_.clear();
    109   delegate()->SetContext(NULL, NULL, NULL);
    110 }
    111 
    112 void EventGenerator::PressLeftButton() {
    113   PressButton(ui::EF_LEFT_MOUSE_BUTTON);
    114 }
    115 
    116 void EventGenerator::ReleaseLeftButton() {
    117   ReleaseButton(ui::EF_LEFT_MOUSE_BUTTON);
    118 }
    119 
    120 void EventGenerator::ClickLeftButton() {
    121   PressLeftButton();
    122   ReleaseLeftButton();
    123 }
    124 
    125 void EventGenerator::DoubleClickLeftButton() {
    126   flags_ |= ui::EF_IS_DOUBLE_CLICK;
    127   PressLeftButton();
    128   flags_ ^= ui::EF_IS_DOUBLE_CLICK;
    129   ReleaseLeftButton();
    130 }
    131 
    132 void EventGenerator::PressRightButton() {
    133   PressButton(ui::EF_RIGHT_MOUSE_BUTTON);
    134 }
    135 
    136 void EventGenerator::ReleaseRightButton() {
    137   ReleaseButton(ui::EF_RIGHT_MOUSE_BUTTON);
    138 }
    139 
    140 void EventGenerator::MoveMouseWheel(int delta_x, int delta_y) {
    141   gfx::Point location = GetLocationInCurrentRoot();
    142   ui::MouseEvent mouseev(ui::ET_MOUSEWHEEL, location, location, flags_, 0);
    143   ui::MouseWheelEvent wheelev(mouseev, delta_x, delta_y);
    144   Dispatch(&wheelev);
    145 }
    146 
    147 void EventGenerator::SendMouseExit() {
    148   gfx::Point exit_location(current_location_);
    149   delegate()->ConvertPointToTarget(current_target_, &exit_location);
    150   ui::MouseEvent mouseev(ui::ET_MOUSE_EXITED, exit_location, exit_location,
    151                          flags_, 0);
    152   Dispatch(&mouseev);
    153 }
    154 
    155 void EventGenerator::MoveMouseToInHost(const gfx::Point& point_in_host) {
    156   const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
    157       ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
    158   ui::MouseEvent mouseev(event_type, point_in_host, point_in_host, flags_, 0);
    159   Dispatch(&mouseev);
    160 
    161   current_location_ = point_in_host;
    162   delegate()->ConvertPointFromHost(current_target_, &current_location_);
    163 }
    164 
    165 void EventGenerator::MoveMouseTo(const gfx::Point& point_in_screen,
    166                                  int count) {
    167   DCHECK_GT(count, 0);
    168   const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
    169       ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
    170 
    171   gfx::Vector2dF diff(point_in_screen - current_location_);
    172   for (float i = 1; i <= count; i++) {
    173     gfx::Vector2dF step(diff);
    174     step.Scale(i / count);
    175     gfx::Point move_point = current_location_ + gfx::ToRoundedVector2d(step);
    176     if (!grab_)
    177       UpdateCurrentDispatcher(move_point);
    178     delegate()->ConvertPointToTarget(current_target_, &move_point);
    179     ui::MouseEvent mouseev(event_type, move_point, move_point, flags_, 0);
    180     Dispatch(&mouseev);
    181   }
    182   current_location_ = point_in_screen;
    183 }
    184 
    185 void EventGenerator::MoveMouseRelativeTo(const EventTarget* window,
    186                                          const gfx::Point& point_in_parent) {
    187   gfx::Point point(point_in_parent);
    188   delegate()->ConvertPointFromTarget(window, &point);
    189   MoveMouseTo(point);
    190 }
    191 
    192 void EventGenerator::DragMouseTo(const gfx::Point& point) {
    193   PressLeftButton();
    194   MoveMouseTo(point);
    195   ReleaseLeftButton();
    196 }
    197 
    198 void EventGenerator::MoveMouseToCenterOf(EventTarget* window) {
    199   MoveMouseTo(CenterOfWindow(window));
    200 }
    201 
    202 void EventGenerator::PressTouch() {
    203   PressTouchId(0);
    204 }
    205 
    206 void EventGenerator::PressTouchId(int touch_id) {
    207   TestTouchEvent touchev(
    208       ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), touch_id, flags_,
    209       Now());
    210   Dispatch(&touchev);
    211 }
    212 
    213 void EventGenerator::MoveTouch(const gfx::Point& point) {
    214   MoveTouchId(point, 0);
    215 }
    216 
    217 void EventGenerator::MoveTouchId(const gfx::Point& point, int touch_id) {
    218   current_location_ = point;
    219   TestTouchEvent touchev(
    220       ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), touch_id, flags_,
    221       Now());
    222   Dispatch(&touchev);
    223 
    224   if (!grab_)
    225     UpdateCurrentDispatcher(point);
    226 }
    227 
    228 void EventGenerator::ReleaseTouch() {
    229   ReleaseTouchId(0);
    230 }
    231 
    232 void EventGenerator::ReleaseTouchId(int touch_id) {
    233   TestTouchEvent touchev(
    234       ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), touch_id, flags_,
    235       Now());
    236   Dispatch(&touchev);
    237 }
    238 
    239 void EventGenerator::PressMoveAndReleaseTouchTo(const gfx::Point& point) {
    240   PressTouch();
    241   MoveTouch(point);
    242   ReleaseTouch();
    243 }
    244 
    245 void EventGenerator::PressMoveAndReleaseTouchToCenterOf(EventTarget* window) {
    246   PressMoveAndReleaseTouchTo(CenterOfWindow(window));
    247 }
    248 
    249 void EventGenerator::GestureEdgeSwipe() {
    250   ui::GestureEvent gesture(
    251       0, 0, 0, Now(), ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE));
    252   Dispatch(&gesture);
    253 }
    254 
    255 void EventGenerator::GestureTapAt(const gfx::Point& location) {
    256   const int kTouchId = 2;
    257   ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
    258                        location,
    259                        kTouchId,
    260                        Now());
    261   Dispatch(&press);
    262 
    263   ui::TouchEvent release(
    264       ui::ET_TOUCH_RELEASED, location, kTouchId,
    265       press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
    266   Dispatch(&release);
    267 }
    268 
    269 void EventGenerator::GestureTapDownAndUp(const gfx::Point& location) {
    270   const int kTouchId = 3;
    271   ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
    272                        location,
    273                        kTouchId,
    274                        Now());
    275   Dispatch(&press);
    276 
    277   ui::TouchEvent release(
    278       ui::ET_TOUCH_RELEASED, location, kTouchId,
    279       press.time_stamp() + base::TimeDelta::FromMilliseconds(1000));
    280   Dispatch(&release);
    281 }
    282 
    283 void EventGenerator::GestureScrollSequence(const gfx::Point& start,
    284                                            const gfx::Point& end,
    285                                            const base::TimeDelta& step_delay,
    286                                            int steps) {
    287   GestureScrollSequenceWithCallback(start, end, step_delay, steps,
    288                                     base::Bind(&DummyCallback));
    289 }
    290 
    291 void EventGenerator::GestureScrollSequenceWithCallback(
    292     const gfx::Point& start,
    293     const gfx::Point& end,
    294     const base::TimeDelta& step_delay,
    295     int steps,
    296     const ScrollStepCallback& callback) {
    297   const int kTouchId = 5;
    298   base::TimeDelta timestamp = Now();
    299   ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, kTouchId, timestamp);
    300   Dispatch(&press);
    301 
    302   callback.Run(ui::ET_GESTURE_SCROLL_BEGIN, gfx::Vector2dF());
    303 
    304   int dx = (end.x() - start.x()) / steps;
    305   int dy = (end.y() - start.y()) / steps;
    306   gfx::Point location = start;
    307   for (int i = 0; i < steps; ++i) {
    308     location.Offset(dx, dy);
    309     timestamp += step_delay;
    310     ui::TouchEvent move(ui::ET_TOUCH_MOVED, location, kTouchId, timestamp);
    311     Dispatch(&move);
    312     callback.Run(ui::ET_GESTURE_SCROLL_UPDATE, gfx::Vector2dF(dx, dy));
    313   }
    314 
    315   ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, kTouchId, timestamp);
    316   Dispatch(&release);
    317 
    318   callback.Run(ui::ET_GESTURE_SCROLL_END, gfx::Vector2dF());
    319 }
    320 
    321 void EventGenerator::GestureMultiFingerScroll(int count,
    322                                               const gfx::Point start[],
    323                                               int event_separation_time_ms,
    324                                               int steps,
    325                                               int move_x,
    326                                               int move_y) {
    327   const int kMaxTouchPoints = 10;
    328   int delays[kMaxTouchPoints] = { 0 };
    329   GestureMultiFingerScrollWithDelays(
    330       count, start, delays, event_separation_time_ms, steps, move_x, move_y);
    331 }
    332 
    333 void EventGenerator::GestureMultiFingerScrollWithDelays(
    334     int count,
    335     const gfx::Point start[],
    336     const int delay_adding_finger_ms[],
    337     int event_separation_time_ms,
    338     int steps,
    339     int move_x,
    340     int move_y) {
    341   const int kMaxTouchPoints = 10;
    342   gfx::Point points[kMaxTouchPoints];
    343   CHECK_LE(count, kMaxTouchPoints);
    344   CHECK_GT(steps, 0);
    345 
    346   int delta_x = move_x / steps;
    347   int delta_y = move_y / steps;
    348 
    349   for (int i = 0; i < count; ++i) {
    350     points[i] = start[i];
    351   }
    352 
    353   base::TimeDelta press_time_first = Now();
    354   base::TimeDelta press_time[kMaxTouchPoints];
    355   bool pressed[kMaxTouchPoints];
    356   for (int i = 0; i < count; ++i) {
    357     pressed[i] = false;
    358     press_time[i] = press_time_first +
    359         base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]);
    360   }
    361 
    362   int last_id = 0;
    363   for (int step = 0; step < steps; ++step) {
    364     base::TimeDelta move_time = press_time_first +
    365         base::TimeDelta::FromMilliseconds(event_separation_time_ms * step);
    366 
    367     while (last_id < count &&
    368            !pressed[last_id] &&
    369            move_time >= press_time[last_id]) {
    370       ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
    371                            points[last_id],
    372                            last_id,
    373                            press_time[last_id]);
    374       Dispatch(&press);
    375       pressed[last_id] = true;
    376       last_id++;
    377     }
    378 
    379     for (int i = 0; i < count; ++i) {
    380       points[i].Offset(delta_x, delta_y);
    381       if (i >= last_id)
    382         continue;
    383       ui::TouchEvent move(ui::ET_TOUCH_MOVED, points[i], i, move_time);
    384       Dispatch(&move);
    385     }
    386   }
    387 
    388   base::TimeDelta release_time = press_time_first +
    389       base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps);
    390   for (int i = 0; i < last_id; ++i) {
    391     ui::TouchEvent release(
    392         ui::ET_TOUCH_RELEASED, points[i], i, release_time);
    393     Dispatch(&release);
    394   }
    395 }
    396 
    397 void EventGenerator::ScrollSequence(const gfx::Point& start,
    398                                     const base::TimeDelta& step_delay,
    399                                     float x_offset,
    400                                     float y_offset,
    401                                     int steps,
    402                                     int num_fingers) {
    403   base::TimeDelta timestamp = Now();
    404   ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
    405                                start,
    406                                timestamp,
    407                                0,
    408                                0, 0,
    409                                0, 0,
    410                                num_fingers);
    411   Dispatch(&fling_cancel);
    412 
    413   float dx = x_offset / steps;
    414   float dy = y_offset / steps;
    415   for (int i = 0; i < steps; ++i) {
    416     timestamp += step_delay;
    417     ui::ScrollEvent move(ui::ET_SCROLL,
    418                          start,
    419                          timestamp,
    420                          0,
    421                          dx, dy,
    422                          dx, dy,
    423                          num_fingers);
    424     Dispatch(&move);
    425   }
    426 
    427   ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
    428                               start,
    429                               timestamp,
    430                               0,
    431                               x_offset, y_offset,
    432                               x_offset, y_offset,
    433                               num_fingers);
    434   Dispatch(&fling_start);
    435 }
    436 
    437 void EventGenerator::ScrollSequence(const gfx::Point& start,
    438                                     const base::TimeDelta& step_delay,
    439                                     const std::vector<gfx::Point>& offsets,
    440                                     int num_fingers) {
    441   size_t steps = offsets.size();
    442   base::TimeDelta timestamp = Now();
    443   ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
    444                                start,
    445                                timestamp,
    446                                0,
    447                                0, 0,
    448                                0, 0,
    449                                num_fingers);
    450   Dispatch(&fling_cancel);
    451 
    452   for (size_t i = 0; i < steps; ++i) {
    453     timestamp += step_delay;
    454     ui::ScrollEvent scroll(ui::ET_SCROLL,
    455                            start,
    456                            timestamp,
    457                            0,
    458                            offsets[i].x(), offsets[i].y(),
    459                            offsets[i].x(), offsets[i].y(),
    460                            num_fingers);
    461     Dispatch(&scroll);
    462   }
    463 
    464   ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
    465                               start,
    466                               timestamp,
    467                               0,
    468                               offsets[steps - 1].x(), offsets[steps - 1].y(),
    469                               offsets[steps - 1].x(), offsets[steps - 1].y(),
    470                               num_fingers);
    471   Dispatch(&fling_start);
    472 }
    473 
    474 void EventGenerator::PressKey(ui::KeyboardCode key_code, int flags) {
    475   DispatchKeyEvent(true, key_code, flags);
    476 }
    477 
    478 void EventGenerator::ReleaseKey(ui::KeyboardCode key_code, int flags) {
    479   DispatchKeyEvent(false, key_code, flags);
    480 }
    481 
    482 void EventGenerator::Dispatch(ui::Event* event) {
    483   DoDispatchEvent(event, async_);
    484 }
    485 
    486 void EventGenerator::SetTickClock(scoped_ptr<base::TickClock> tick_clock) {
    487   tick_clock_ = tick_clock.Pass();
    488 }
    489 
    490 base::TimeDelta EventGenerator::Now() {
    491   // This is the same as what EventTimeForNow() does, but here we do it
    492   // with a tick clock that can be replaced with a simulated clock for tests.
    493   return base::TimeDelta::FromInternalValue(
    494       tick_clock_->NowTicks().ToInternalValue());
    495 }
    496 
    497 void EventGenerator::Init(gfx::NativeWindow root_window,
    498                           gfx::NativeWindow window_context) {
    499   delegate()->SetContext(this, root_window, window_context);
    500   if (window_context)
    501     current_location_ = delegate()->CenterOfWindow(window_context);
    502   current_target_ = delegate()->GetTargetAt(current_location_);
    503 }
    504 
    505 void EventGenerator::DispatchKeyEvent(bool is_press,
    506                                       ui::KeyboardCode key_code,
    507                                       int flags) {
    508 #if defined(OS_WIN)
    509   UINT key_press = WM_KEYDOWN;
    510   uint16 character = ui::GetCharacterFromKeyCode(key_code, flags);
    511   if (is_press && character) {
    512     MSG native_event = { NULL, WM_KEYDOWN, key_code, 0 };
    513     TestKeyEvent keyev(native_event, flags);
    514     Dispatch(&keyev);
    515     // On Windows, WM_KEYDOWN event is followed by WM_CHAR with a character
    516     // if the key event cooresponds to a real character.
    517     key_press = WM_CHAR;
    518     key_code = static_cast<ui::KeyboardCode>(character);
    519   }
    520   MSG native_event =
    521       { NULL, (is_press ? key_press : WM_KEYUP), key_code, 0 };
    522   TestKeyEvent keyev(native_event, flags);
    523 #elif defined(USE_X11)
    524   ui::ScopedXI2Event xevent;
    525   xevent.InitKeyEvent(is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
    526                       key_code,
    527                       flags);
    528   ui::KeyEvent keyev(xevent);
    529 #else
    530   ui::EventType type = is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
    531   ui::KeyEvent keyev(type, key_code, flags);
    532 #endif  // OS_WIN
    533   Dispatch(&keyev);
    534 }
    535 
    536 void EventGenerator::UpdateCurrentDispatcher(const gfx::Point& point) {
    537   current_target_ = delegate()->GetTargetAt(point);
    538 }
    539 
    540 void EventGenerator::PressButton(int flag) {
    541   if (!(flags_ & flag)) {
    542     flags_ |= flag;
    543     grab_ = (flags_ & kAllButtonMask) != 0;
    544     gfx::Point location = GetLocationInCurrentRoot();
    545     ui::MouseEvent mouseev(ui::ET_MOUSE_PRESSED, location, location, flags_,
    546                            flag);
    547     Dispatch(&mouseev);
    548   }
    549 }
    550 
    551 void EventGenerator::ReleaseButton(int flag) {
    552   if (flags_ & flag) {
    553     gfx::Point location = GetLocationInCurrentRoot();
    554     ui::MouseEvent mouseev(ui::ET_MOUSE_RELEASED, location,
    555                            location, flags_, flag);
    556     Dispatch(&mouseev);
    557     flags_ ^= flag;
    558   }
    559   grab_ = (flags_ & kAllButtonMask) != 0;
    560 }
    561 
    562 gfx::Point EventGenerator::GetLocationInCurrentRoot() const {
    563   gfx::Point p(current_location_);
    564   delegate()->ConvertPointToTarget(current_target_, &p);
    565   return p;
    566 }
    567 
    568 gfx::Point EventGenerator::CenterOfWindow(const EventTarget* window) const {
    569   return delegate()->CenterOfTarget(window);
    570 }
    571 
    572 void EventGenerator::DoDispatchEvent(ui::Event* event, bool async) {
    573   if (async) {
    574     ui::Event* pending_event;
    575     if (event->IsKeyEvent()) {
    576       pending_event = new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event));
    577     } else if (event->IsMouseEvent()) {
    578       pending_event = new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event));
    579     } else if (event->IsTouchEvent()) {
    580       pending_event = new ui::TouchEvent(*static_cast<ui::TouchEvent*>(event));
    581     } else if (event->IsScrollEvent()) {
    582       pending_event =
    583           new ui::ScrollEvent(*static_cast<ui::ScrollEvent*>(event));
    584     } else {
    585       NOTREACHED() << "Invalid event type";
    586       return;
    587     }
    588     if (pending_events_.empty()) {
    589       base::ThreadTaskRunnerHandle::Get()->PostTask(
    590           FROM_HERE,
    591           base::Bind(&EventGenerator::DispatchNextPendingEvent,
    592                      base::Unretained(this)));
    593     }
    594     pending_events_.push_back(pending_event);
    595   } else {
    596     ui::EventSource* event_source = delegate()->GetEventSource(current_target_);
    597     ui::EventSourceTestApi event_source_test(event_source);
    598     ui::EventDispatchDetails details =
    599         event_source_test.SendEventToProcessor(event);
    600     CHECK(!details.dispatcher_destroyed);
    601   }
    602 }
    603 
    604 void EventGenerator::DispatchNextPendingEvent() {
    605   DCHECK(!pending_events_.empty());
    606   ui::Event* event = pending_events_.front();
    607   DoDispatchEvent(event, false);
    608   pending_events_.pop_front();
    609   delete event;
    610   if (!pending_events_.empty()) {
    611     base::ThreadTaskRunnerHandle::Get()->PostTask(
    612         FROM_HERE,
    613         base::Bind(&EventGenerator::DispatchNextPendingEvent,
    614                    base::Unretained(this)));
    615   }
    616 }
    617 
    618 const EventGeneratorDelegate* EventGenerator::delegate() const {
    619   if (delegate_)
    620     return delegate_.get();
    621 
    622   DCHECK(default_delegate);
    623   return default_delegate;
    624 }
    625 
    626 EventGeneratorDelegate* EventGenerator::delegate() {
    627   return const_cast<EventGeneratorDelegate*>(
    628       const_cast<const EventGenerator*>(this)->delegate());
    629 }
    630 
    631 }  // namespace test
    632 }  // namespace ui
    633