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