base: Change DCHECK_IS_ON to a macro DCHECK_IS_ON().
[chromium-blink-merge.git] / ui / events / test / event_generator.cc
blob9142d5c0c6ed661c9b68bcc03136743ecc3e555f
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.
5 #include "ui/events/test/event_generator.h"
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/geometry/vector2d_conversions.h"
19 #if defined(USE_X11)
20 #include <X11/Xlib.h>
21 #include "ui/events/test/events_test_utils_x11.h"
22 #endif
24 #if defined(OS_WIN)
25 #include "ui/events/keycodes/keyboard_code_conversion.h"
26 #endif
28 namespace ui {
29 namespace test {
30 namespace {
32 void DummyCallback(EventType, const gfx::Vector2dF&) {
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);
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) {
54 private:
55 DISALLOW_COPY_AND_ASSIGN(TestTouchEvent);
58 const int kAllButtonMask = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON;
60 } // namespace
62 EventGeneratorDelegate* EventGenerator::default_delegate = NULL;
64 EventGenerator::EventGenerator(gfx::NativeWindow root_window)
65 : current_target_(NULL),
66 flags_(0),
67 grab_(false),
68 async_(false),
69 targeting_application_(false),
70 tick_clock_(new base::DefaultTickClock()) {
71 Init(root_window, NULL);
74 EventGenerator::EventGenerator(gfx::NativeWindow root_window,
75 const gfx::Point& point)
76 : current_location_(point),
77 current_target_(NULL),
78 flags_(0),
79 grab_(false),
80 async_(false),
81 targeting_application_(false),
82 tick_clock_(new base::DefaultTickClock()) {
83 Init(root_window, NULL);
86 EventGenerator::EventGenerator(gfx::NativeWindow root_window,
87 gfx::NativeWindow window)
88 : current_target_(NULL),
89 flags_(0),
90 grab_(false),
91 async_(false),
92 targeting_application_(false),
93 tick_clock_(new base::DefaultTickClock()) {
94 Init(root_window, window);
97 EventGenerator::EventGenerator(EventGeneratorDelegate* delegate)
98 : delegate_(delegate),
99 current_target_(NULL),
100 flags_(0),
101 grab_(false),
102 async_(false),
103 targeting_application_(false),
104 tick_clock_(new base::DefaultTickClock()) {
105 Init(NULL, NULL);
108 EventGenerator::~EventGenerator() {
109 for (std::list<ui::Event*>::iterator i = pending_events_.begin();
110 i != pending_events_.end(); ++i)
111 delete *i;
112 pending_events_.clear();
113 delegate()->SetContext(NULL, NULL, NULL);
116 void EventGenerator::PressLeftButton() {
117 PressButton(ui::EF_LEFT_MOUSE_BUTTON);
120 void EventGenerator::ReleaseLeftButton() {
121 ReleaseButton(ui::EF_LEFT_MOUSE_BUTTON);
124 void EventGenerator::ClickLeftButton() {
125 PressLeftButton();
126 ReleaseLeftButton();
129 void EventGenerator::DoubleClickLeftButton() {
130 flags_ &= ~ui::EF_IS_DOUBLE_CLICK;
131 ClickLeftButton();
132 flags_ |= ui::EF_IS_DOUBLE_CLICK;
133 ClickLeftButton();
134 flags_ &= ~ui::EF_IS_DOUBLE_CLICK;
137 void EventGenerator::PressRightButton() {
138 PressButton(ui::EF_RIGHT_MOUSE_BUTTON);
141 void EventGenerator::ReleaseRightButton() {
142 ReleaseButton(ui::EF_RIGHT_MOUSE_BUTTON);
145 void EventGenerator::MoveMouseWheel(int delta_x, int delta_y) {
146 gfx::Point location = GetLocationInCurrentRoot();
147 ui::MouseEvent mouseev(ui::ET_MOUSEWHEEL, location, location, flags_, 0);
148 ui::MouseWheelEvent wheelev(mouseev, delta_x, delta_y);
149 Dispatch(&wheelev);
152 void EventGenerator::SendMouseExit() {
153 gfx::Point exit_location(current_location_);
154 delegate()->ConvertPointToTarget(current_target_, &exit_location);
155 ui::MouseEvent mouseev(ui::ET_MOUSE_EXITED, exit_location, exit_location,
156 flags_, 0);
157 Dispatch(&mouseev);
160 void EventGenerator::MoveMouseToInHost(const gfx::Point& point_in_host) {
161 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
162 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
163 ui::MouseEvent mouseev(event_type, point_in_host, point_in_host, flags_, 0);
164 Dispatch(&mouseev);
166 current_location_ = point_in_host;
167 delegate()->ConvertPointFromHost(current_target_, &current_location_);
170 void EventGenerator::MoveMouseTo(const gfx::Point& point_in_screen,
171 int count) {
172 DCHECK_GT(count, 0);
173 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
174 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
176 gfx::Vector2dF diff(point_in_screen - current_location_);
177 for (float i = 1; i <= count; i++) {
178 gfx::Vector2dF step(diff);
179 step.Scale(i / count);
180 gfx::Point move_point = current_location_ + gfx::ToRoundedVector2d(step);
181 if (!grab_)
182 UpdateCurrentDispatcher(move_point);
183 delegate()->ConvertPointToTarget(current_target_, &move_point);
184 ui::MouseEvent mouseev(event_type, move_point, move_point, flags_, 0);
185 Dispatch(&mouseev);
187 current_location_ = point_in_screen;
190 void EventGenerator::MoveMouseRelativeTo(const EventTarget* window,
191 const gfx::Point& point_in_parent) {
192 gfx::Point point(point_in_parent);
193 delegate()->ConvertPointFromTarget(window, &point);
194 MoveMouseTo(point);
197 void EventGenerator::DragMouseTo(const gfx::Point& point) {
198 PressLeftButton();
199 MoveMouseTo(point);
200 ReleaseLeftButton();
203 void EventGenerator::MoveMouseToCenterOf(EventTarget* window) {
204 MoveMouseTo(CenterOfWindow(window));
207 void EventGenerator::PressTouch() {
208 PressTouchId(0);
211 void EventGenerator::PressTouchId(int touch_id) {
212 TestTouchEvent touchev(
213 ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), touch_id, flags_,
214 Now());
215 Dispatch(&touchev);
218 void EventGenerator::MoveTouch(const gfx::Point& point) {
219 MoveTouchId(point, 0);
222 void EventGenerator::MoveTouchId(const gfx::Point& point, int touch_id) {
223 current_location_ = point;
224 TestTouchEvent touchev(
225 ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), touch_id, flags_,
226 Now());
227 Dispatch(&touchev);
229 if (!grab_)
230 UpdateCurrentDispatcher(point);
233 void EventGenerator::ReleaseTouch() {
234 ReleaseTouchId(0);
237 void EventGenerator::ReleaseTouchId(int touch_id) {
238 TestTouchEvent touchev(
239 ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), touch_id, flags_,
240 Now());
241 Dispatch(&touchev);
244 void EventGenerator::PressMoveAndReleaseTouchTo(const gfx::Point& point) {
245 PressTouch();
246 MoveTouch(point);
247 ReleaseTouch();
250 void EventGenerator::PressMoveAndReleaseTouchToCenterOf(EventTarget* window) {
251 PressMoveAndReleaseTouchTo(CenterOfWindow(window));
254 void EventGenerator::GestureEdgeSwipe() {
255 ui::GestureEvent gesture(
256 0, 0, 0, Now(), ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE));
257 Dispatch(&gesture);
260 void EventGenerator::GestureTapAt(const gfx::Point& location) {
261 const int kTouchId = 2;
262 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
263 location,
264 kTouchId,
265 Now());
266 Dispatch(&press);
268 ui::TouchEvent release(
269 ui::ET_TOUCH_RELEASED, location, kTouchId,
270 press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
271 Dispatch(&release);
274 void EventGenerator::GestureTapDownAndUp(const gfx::Point& location) {
275 const int kTouchId = 3;
276 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
277 location,
278 kTouchId,
279 Now());
280 Dispatch(&press);
282 ui::TouchEvent release(
283 ui::ET_TOUCH_RELEASED, location, kTouchId,
284 press.time_stamp() + base::TimeDelta::FromMilliseconds(1000));
285 Dispatch(&release);
288 base::TimeDelta EventGenerator::CalculateScrollDurationForFlingVelocity(
289 const gfx::Point& start,
290 const gfx::Point& end,
291 float velocity,
292 int steps) {
293 const float kGestureDistance = (start - end).Length();
294 const float kFlingStepDelay = (kGestureDistance / velocity) / steps * 1000000;
295 return base::TimeDelta::FromMicroseconds(kFlingStepDelay);
298 void EventGenerator::GestureScrollSequence(const gfx::Point& start,
299 const gfx::Point& end,
300 const base::TimeDelta& step_delay,
301 int steps) {
302 GestureScrollSequenceWithCallback(start, end, step_delay, steps,
303 base::Bind(&DummyCallback));
306 void EventGenerator::GestureScrollSequenceWithCallback(
307 const gfx::Point& start,
308 const gfx::Point& end,
309 const base::TimeDelta& step_delay,
310 int steps,
311 const ScrollStepCallback& callback) {
312 const int kTouchId = 5;
313 base::TimeDelta timestamp = Now();
314 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, kTouchId, timestamp);
315 Dispatch(&press);
317 callback.Run(ui::ET_GESTURE_SCROLL_BEGIN, gfx::Vector2dF());
319 float dx = static_cast<float>(end.x() - start.x()) / steps;
320 float dy = static_cast<float>(end.y() - start.y()) / steps;
321 gfx::PointF location = start;
322 for (int i = 0; i < steps; ++i) {
323 location.Offset(dx, dy);
324 timestamp += step_delay;
325 ui::TouchEvent move(ui::ET_TOUCH_MOVED, location, kTouchId, timestamp);
326 Dispatch(&move);
327 callback.Run(ui::ET_GESTURE_SCROLL_UPDATE, gfx::Vector2dF(dx, dy));
330 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, kTouchId, timestamp);
331 Dispatch(&release);
333 callback.Run(ui::ET_GESTURE_SCROLL_END, gfx::Vector2dF());
336 void EventGenerator::GestureMultiFingerScroll(int count,
337 const gfx::Point start[],
338 int event_separation_time_ms,
339 int steps,
340 int move_x,
341 int move_y) {
342 const int kMaxTouchPoints = 10;
343 int delays[kMaxTouchPoints] = { 0 };
344 GestureMultiFingerScrollWithDelays(
345 count, start, delays, event_separation_time_ms, steps, move_x, move_y);
348 void EventGenerator::GestureMultiFingerScrollWithDelays(
349 int count,
350 const gfx::Point start[],
351 const int delay_adding_finger_ms[],
352 int event_separation_time_ms,
353 int steps,
354 int move_x,
355 int move_y) {
356 const int kMaxTouchPoints = 10;
357 gfx::Point points[kMaxTouchPoints];
358 CHECK_LE(count, kMaxTouchPoints);
359 CHECK_GT(steps, 0);
361 int delta_x = move_x / steps;
362 int delta_y = move_y / steps;
364 for (int i = 0; i < count; ++i) {
365 points[i] = start[i];
368 base::TimeDelta press_time_first = Now();
369 base::TimeDelta press_time[kMaxTouchPoints];
370 bool pressed[kMaxTouchPoints];
371 for (int i = 0; i < count; ++i) {
372 pressed[i] = false;
373 press_time[i] = press_time_first +
374 base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]);
377 int last_id = 0;
378 for (int step = 0; step < steps; ++step) {
379 base::TimeDelta move_time = press_time_first +
380 base::TimeDelta::FromMilliseconds(event_separation_time_ms * step);
382 while (last_id < count &&
383 !pressed[last_id] &&
384 move_time >= press_time[last_id]) {
385 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
386 points[last_id],
387 last_id,
388 press_time[last_id]);
389 Dispatch(&press);
390 pressed[last_id] = true;
391 last_id++;
394 for (int i = 0; i < count; ++i) {
395 points[i].Offset(delta_x, delta_y);
396 if (i >= last_id)
397 continue;
398 ui::TouchEvent move(ui::ET_TOUCH_MOVED, points[i], i, move_time);
399 Dispatch(&move);
403 base::TimeDelta release_time = press_time_first +
404 base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps);
405 for (int i = 0; i < last_id; ++i) {
406 ui::TouchEvent release(
407 ui::ET_TOUCH_RELEASED, points[i], i, release_time);
408 Dispatch(&release);
412 void EventGenerator::ScrollSequence(const gfx::Point& start,
413 const base::TimeDelta& step_delay,
414 float x_offset,
415 float y_offset,
416 int steps,
417 int num_fingers) {
418 base::TimeDelta timestamp = Now();
419 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
420 start,
421 timestamp,
423 0, 0,
424 0, 0,
425 num_fingers);
426 Dispatch(&fling_cancel);
428 float dx = x_offset / steps;
429 float dy = y_offset / steps;
430 for (int i = 0; i < steps; ++i) {
431 timestamp += step_delay;
432 ui::ScrollEvent move(ui::ET_SCROLL,
433 start,
434 timestamp,
436 dx, dy,
437 dx, dy,
438 num_fingers);
439 Dispatch(&move);
442 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
443 start,
444 timestamp,
446 x_offset, y_offset,
447 x_offset, y_offset,
448 num_fingers);
449 Dispatch(&fling_start);
452 void EventGenerator::ScrollSequence(const gfx::Point& start,
453 const base::TimeDelta& step_delay,
454 const std::vector<gfx::PointF>& offsets,
455 int num_fingers) {
456 size_t steps = offsets.size();
457 base::TimeDelta timestamp = Now();
458 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
459 start,
460 timestamp,
462 0, 0,
463 0, 0,
464 num_fingers);
465 Dispatch(&fling_cancel);
467 for (size_t i = 0; i < steps; ++i) {
468 timestamp += step_delay;
469 ui::ScrollEvent scroll(ui::ET_SCROLL,
470 start,
471 timestamp,
473 offsets[i].x(), offsets[i].y(),
474 offsets[i].x(), offsets[i].y(),
475 num_fingers);
476 Dispatch(&scroll);
479 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
480 start,
481 timestamp,
483 offsets[steps - 1].x(), offsets[steps - 1].y(),
484 offsets[steps - 1].x(), offsets[steps - 1].y(),
485 num_fingers);
486 Dispatch(&fling_start);
489 void EventGenerator::PressKey(ui::KeyboardCode key_code, int flags) {
490 DispatchKeyEvent(true, key_code, flags);
493 void EventGenerator::ReleaseKey(ui::KeyboardCode key_code, int flags) {
494 DispatchKeyEvent(false, key_code, flags);
497 void EventGenerator::Dispatch(ui::Event* event) {
498 DoDispatchEvent(event, async_);
501 void EventGenerator::SetTickClock(scoped_ptr<base::TickClock> tick_clock) {
502 tick_clock_ = tick_clock.Pass();
505 base::TimeDelta EventGenerator::Now() {
506 // This is the same as what EventTimeForNow() does, but here we do it
507 // with a tick clock that can be replaced with a simulated clock for tests.
508 return base::TimeDelta::FromInternalValue(
509 tick_clock_->NowTicks().ToInternalValue());
512 void EventGenerator::Init(gfx::NativeWindow root_window,
513 gfx::NativeWindow window_context) {
514 delegate()->SetContext(this, root_window, window_context);
515 if (window_context)
516 current_location_ = delegate()->CenterOfWindow(window_context);
517 current_target_ = delegate()->GetTargetAt(current_location_);
520 void EventGenerator::DispatchKeyEvent(bool is_press,
521 ui::KeyboardCode key_code,
522 int flags) {
523 #if defined(OS_WIN)
524 UINT key_press = WM_KEYDOWN;
525 uint16 character = ui::GetCharacterFromKeyCode(key_code, flags);
526 if (is_press && character) {
527 MSG native_event = { NULL, WM_KEYDOWN, key_code, 0 };
528 TestKeyEvent keyev(native_event, flags);
529 Dispatch(&keyev);
530 // On Windows, WM_KEYDOWN event is followed by WM_CHAR with a character
531 // if the key event cooresponds to a real character.
532 key_press = WM_CHAR;
533 key_code = static_cast<ui::KeyboardCode>(character);
535 MSG native_event =
536 { NULL, (is_press ? key_press : WM_KEYUP), key_code, 0 };
537 TestKeyEvent keyev(native_event, flags);
538 #elif defined(USE_X11)
539 ui::ScopedXI2Event xevent;
540 xevent.InitKeyEvent(is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
541 key_code,
542 flags);
543 ui::KeyEvent keyev(xevent);
544 #else
545 ui::EventType type = is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
546 ui::KeyEvent keyev(type, key_code, flags);
547 #endif // OS_WIN
548 Dispatch(&keyev);
551 void EventGenerator::UpdateCurrentDispatcher(const gfx::Point& point) {
552 current_target_ = delegate()->GetTargetAt(point);
555 void EventGenerator::PressButton(int flag) {
556 if (!(flags_ & flag)) {
557 flags_ |= flag;
558 grab_ = (flags_ & kAllButtonMask) != 0;
559 gfx::Point location = GetLocationInCurrentRoot();
560 ui::MouseEvent mouseev(ui::ET_MOUSE_PRESSED, location, location, flags_,
561 flag);
562 Dispatch(&mouseev);
566 void EventGenerator::ReleaseButton(int flag) {
567 if (flags_ & flag) {
568 gfx::Point location = GetLocationInCurrentRoot();
569 ui::MouseEvent mouseev(ui::ET_MOUSE_RELEASED, location,
570 location, flags_, flag);
571 Dispatch(&mouseev);
572 flags_ ^= flag;
574 grab_ = (flags_ & kAllButtonMask) != 0;
577 gfx::Point EventGenerator::GetLocationInCurrentRoot() const {
578 gfx::Point p(current_location_);
579 delegate()->ConvertPointToTarget(current_target_, &p);
580 return p;
583 gfx::Point EventGenerator::CenterOfWindow(const EventTarget* window) const {
584 return delegate()->CenterOfTarget(window);
587 void EventGenerator::DoDispatchEvent(ui::Event* event, bool async) {
588 if (async) {
589 ui::Event* pending_event;
590 if (event->IsKeyEvent()) {
591 pending_event = new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event));
592 } else if (event->IsMouseEvent()) {
593 pending_event = new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event));
594 } else if (event->IsTouchEvent()) {
595 pending_event = new ui::TouchEvent(*static_cast<ui::TouchEvent*>(event));
596 } else if (event->IsScrollEvent()) {
597 pending_event =
598 new ui::ScrollEvent(*static_cast<ui::ScrollEvent*>(event));
599 } else {
600 NOTREACHED() << "Invalid event type";
601 return;
603 if (pending_events_.empty()) {
604 base::ThreadTaskRunnerHandle::Get()->PostTask(
605 FROM_HERE,
606 base::Bind(&EventGenerator::DispatchNextPendingEvent,
607 base::Unretained(this)));
609 pending_events_.push_back(pending_event);
610 } else {
611 ui::EventSource* event_source = delegate()->GetEventSource(current_target_);
612 ui::EventSourceTestApi event_source_test(event_source);
613 ui::EventDispatchDetails details =
614 event_source_test.SendEventToProcessor(event);
615 CHECK(!details.dispatcher_destroyed);
619 void EventGenerator::DispatchNextPendingEvent() {
620 DCHECK(!pending_events_.empty());
621 ui::Event* event = pending_events_.front();
622 DoDispatchEvent(event, false);
623 pending_events_.pop_front();
624 delete event;
625 if (!pending_events_.empty()) {
626 base::ThreadTaskRunnerHandle::Get()->PostTask(
627 FROM_HERE,
628 base::Bind(&EventGenerator::DispatchNextPendingEvent,
629 base::Unretained(this)));
633 const EventGeneratorDelegate* EventGenerator::delegate() const {
634 if (delegate_)
635 return delegate_.get();
637 DCHECK(default_delegate);
638 return default_delegate;
641 EventGeneratorDelegate* EventGenerator::delegate() {
642 return const_cast<EventGeneratorDelegate*>(
643 const_cast<const EventGenerator*>(this)->delegate());
646 } // namespace test
647 } // namespace ui