• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DummyCallback(ui::EventType,const gfx::Vector2dF &)35 void DummyCallback(ui::EventType, const gfx::Vector2dF&) {
36 }
37 
38 class DefaultEventGeneratorDelegate : public EventGeneratorDelegate {
39  public:
DefaultEventGeneratorDelegate(Window * root_window)40   explicit DefaultEventGeneratorDelegate(Window* root_window)
41       : root_window_(root_window) {}
~DefaultEventGeneratorDelegate()42   virtual ~DefaultEventGeneratorDelegate() {}
43 
44   // EventGeneratorDelegate overrides:
GetHostAt(const gfx::Point & point) const45   virtual WindowTreeHost* GetHostAt(const gfx::Point& point) const OVERRIDE {
46     return root_window_->GetHost();
47   }
48 
GetScreenPositionClient(const aura::Window * window) const49   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:
TestKeyEvent(const base::NativeEvent & native_event,int flags,bool is_char)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:
TestTouchEvent(ui::EventType type,const gfx::Point & root_location,int touch_id,int flags,base::TimeDelta timestamp)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 
EventGenerator(Window * root_window)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 
EventGenerator(Window * root_window,const gfx::Point & point)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 
EventGenerator(Window * root_window,Window * window)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 
EventGenerator(EventGeneratorDelegate * delegate)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 
~EventGenerator()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 
PressLeftButton()132 void EventGenerator::PressLeftButton() {
133   PressButton(ui::EF_LEFT_MOUSE_BUTTON);
134 }
135 
ReleaseLeftButton()136 void EventGenerator::ReleaseLeftButton() {
137   ReleaseButton(ui::EF_LEFT_MOUSE_BUTTON);
138 }
139 
ClickLeftButton()140 void EventGenerator::ClickLeftButton() {
141   PressLeftButton();
142   ReleaseLeftButton();
143 }
144 
DoubleClickLeftButton()145 void EventGenerator::DoubleClickLeftButton() {
146   flags_ |= ui::EF_IS_DOUBLE_CLICK;
147   PressLeftButton();
148   flags_ ^= ui::EF_IS_DOUBLE_CLICK;
149   ReleaseLeftButton();
150 }
151 
PressRightButton()152 void EventGenerator::PressRightButton() {
153   PressButton(ui::EF_RIGHT_MOUSE_BUTTON);
154 }
155 
ReleaseRightButton()156 void EventGenerator::ReleaseRightButton() {
157   ReleaseButton(ui::EF_RIGHT_MOUSE_BUTTON);
158 }
159 
MoveMouseWheel(int delta_x,int delta_y)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 
SendMouseExit()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 
MoveMouseToInHost(const gfx::Point & point_in_host)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 
MoveMouseTo(const gfx::Point & point_in_screen,int count)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 
MoveMouseRelativeTo(const Window * window,const gfx::Point & point_in_parent)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 
DragMouseTo(const gfx::Point & point)212 void EventGenerator::DragMouseTo(const gfx::Point& point) {
213   PressLeftButton();
214   MoveMouseTo(point);
215   ReleaseLeftButton();
216 }
217 
MoveMouseToCenterOf(Window * window)218 void EventGenerator::MoveMouseToCenterOf(Window* window) {
219   MoveMouseTo(CenterOfWindow(window));
220 }
221 
PressTouch()222 void EventGenerator::PressTouch() {
223   PressTouchId(0);
224 }
225 
PressTouchId(int touch_id)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 
MoveTouch(const gfx::Point & point)233 void EventGenerator::MoveTouch(const gfx::Point& point) {
234   MoveTouchId(point, 0);
235 }
236 
MoveTouchId(const gfx::Point & point,int touch_id)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 
ReleaseTouch()248 void EventGenerator::ReleaseTouch() {
249   ReleaseTouchId(0);
250 }
251 
ReleaseTouchId(int touch_id)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 
PressMoveAndReleaseTouchTo(const gfx::Point & point)259 void EventGenerator::PressMoveAndReleaseTouchTo(const gfx::Point& point) {
260   PressTouch();
261   MoveTouch(point);
262   ReleaseTouch();
263 }
264 
PressMoveAndReleaseTouchToCenterOf(Window * window)265 void EventGenerator::PressMoveAndReleaseTouchToCenterOf(Window* window) {
266   PressMoveAndReleaseTouchTo(CenterOfWindow(window));
267 }
268 
GestureEdgeSwipe()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 
GestureTapAt(const gfx::Point & location)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 
GestureTapDownAndUp(const gfx::Point & location)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 
GestureScrollSequence(const gfx::Point & start,const gfx::Point & end,const base::TimeDelta & step_delay,int steps)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 
GestureScrollSequenceWithCallback(const gfx::Point & start,const gfx::Point & end,const base::TimeDelta & step_delay,int steps,const ScrollStepCallback & callback)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 
GestureMultiFingerScroll(int count,const gfx::Point start[],int event_separation_time_ms,int steps,int move_x,int move_y)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 
GestureMultiFingerScrollWithDelays(int count,const gfx::Point start[],const int delay_adding_finger_ms[],int event_separation_time_ms,int steps,int move_x,int move_y)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 
ScrollSequence(const gfx::Point & start,const base::TimeDelta & step_delay,float x_offset,float y_offset,int steps,int num_fingers)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 
ScrollSequence(const gfx::Point & start,const base::TimeDelta & step_delay,const std::vector<gfx::Point> & offsets,int num_fingers)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 
PressKey(ui::KeyboardCode key_code,int flags)500 void EventGenerator::PressKey(ui::KeyboardCode key_code, int flags) {
501   DispatchKeyEvent(true, key_code, flags);
502 }
503 
ReleaseKey(ui::KeyboardCode key_code,int flags)504 void EventGenerator::ReleaseKey(ui::KeyboardCode key_code, int flags) {
505   DispatchKeyEvent(false, key_code, flags);
506 }
507 
Dispatch(ui::Event * event)508 void EventGenerator::Dispatch(ui::Event* event) {
509   DoDispatchEvent(event, async_);
510 }
511 
SetTickClock(scoped_ptr<base::TickClock> tick_clock)512 void EventGenerator::SetTickClock(scoped_ptr<base::TickClock> tick_clock) {
513   tick_clock_ = tick_clock.Pass();
514 }
515 
Now()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 
DispatchKeyEvent(bool is_press,ui::KeyboardCode key_code,int flags)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 
UpdateCurrentDispatcher(const gfx::Point & point)554 void EventGenerator::UpdateCurrentDispatcher(const gfx::Point& point) {
555   current_host_ = delegate_->GetHostAt(point);
556 }
557 
PressButton(int flag)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 
ReleaseButton(int flag)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 
ConvertPointFromTarget(const aura::Window * target,gfx::Point * point) const580 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 
ConvertPointToTarget(const aura::Window * target,gfx::Point * point) const591 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 
GetLocationInCurrentRoot() const602 gfx::Point EventGenerator::GetLocationInCurrentRoot() const {
603   gfx::Point p(current_location_);
604   ConvertPointToTarget(current_host_->window(), &p);
605   return p;
606 }
607 
CenterOfWindow(const Window * window) const608 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 
DoDispatchEvent(ui::Event * event,bool async)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 
DispatchNextPendingEvent()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