Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / events / test / event_generator.cc
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