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