Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / events / test / event_generator.cc
blobae3bcb6d667a786c82a7e55a47d290835d3c1898
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/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 TestTickClock : public base::TickClock {
36 public:
37 // Starts off with a clock set to TimeTicks().
38 TestTickClock() {}
40 base::TimeTicks NowTicks() override {
41 return base::TimeTicks::FromInternalValue(ticks_++ * 1000);
44 private:
45 int64 ticks_ = 1;
47 DISALLOW_COPY_AND_ASSIGN(TestTickClock);
50 class TestKeyEvent : public ui::KeyEvent {
51 public:
52 TestKeyEvent(const base::NativeEvent& native_event, int flags)
53 : KeyEvent(native_event) {
54 set_flags(flags);
58 class TestTouchEvent : public ui::TouchEvent {
59 public:
60 TestTouchEvent(ui::EventType type,
61 const gfx::Point& root_location,
62 int touch_id,
63 int flags,
64 base::TimeDelta timestamp)
65 : TouchEvent(type, root_location, flags, touch_id, timestamp,
66 1.0f, 1.0f, 0.0f, 0.0f) {
69 private:
70 DISALLOW_COPY_AND_ASSIGN(TestTouchEvent);
73 const int kAllButtonMask = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON;
75 } // namespace
77 EventGeneratorDelegate* EventGenerator::default_delegate = NULL;
79 EventGenerator::EventGenerator(gfx::NativeWindow root_window)
80 : current_target_(NULL),
81 flags_(0),
82 grab_(false),
83 async_(false),
84 targeting_application_(false),
85 tick_clock_(new TestTickClock()) {
86 Init(root_window, NULL);
89 EventGenerator::EventGenerator(gfx::NativeWindow root_window,
90 const gfx::Point& point)
91 : current_location_(point),
92 current_target_(NULL),
93 flags_(0),
94 grab_(false),
95 async_(false),
96 targeting_application_(false),
97 tick_clock_(new TestTickClock()) {
98 Init(root_window, NULL);
101 EventGenerator::EventGenerator(gfx::NativeWindow root_window,
102 gfx::NativeWindow window)
103 : current_target_(NULL),
104 flags_(0),
105 grab_(false),
106 async_(false),
107 targeting_application_(false),
108 tick_clock_(new TestTickClock()) {
109 Init(root_window, window);
112 EventGenerator::EventGenerator(EventGeneratorDelegate* delegate)
113 : delegate_(delegate),
114 current_target_(NULL),
115 flags_(0),
116 grab_(false),
117 async_(false),
118 targeting_application_(false),
119 tick_clock_(new TestTickClock()) {
120 Init(NULL, NULL);
123 EventGenerator::~EventGenerator() {
124 for (std::list<ui::Event*>::iterator i = pending_events_.begin();
125 i != pending_events_.end(); ++i)
126 delete *i;
127 pending_events_.clear();
128 delegate()->SetContext(NULL, NULL, NULL);
131 void EventGenerator::PressLeftButton() {
132 PressButton(ui::EF_LEFT_MOUSE_BUTTON);
135 void EventGenerator::ReleaseLeftButton() {
136 ReleaseButton(ui::EF_LEFT_MOUSE_BUTTON);
139 void EventGenerator::ClickLeftButton() {
140 PressLeftButton();
141 ReleaseLeftButton();
144 void EventGenerator::DoubleClickLeftButton() {
145 flags_ &= ~ui::EF_IS_DOUBLE_CLICK;
146 ClickLeftButton();
147 flags_ |= ui::EF_IS_DOUBLE_CLICK;
148 ClickLeftButton();
149 flags_ &= ~ui::EF_IS_DOUBLE_CLICK;
152 void EventGenerator::PressRightButton() {
153 PressButton(ui::EF_RIGHT_MOUSE_BUTTON);
156 void EventGenerator::ReleaseRightButton() {
157 ReleaseButton(ui::EF_RIGHT_MOUSE_BUTTON);
160 void EventGenerator::MoveMouseWheel(int delta_x, int delta_y) {
161 gfx::Point location = GetLocationInCurrentRoot();
162 ui::MouseEvent mouseev(ui::ET_MOUSEWHEEL, location, location,
163 ui::EventTimeForNow(), flags_, 0);
164 ui::MouseWheelEvent wheelev(mouseev, delta_x, delta_y);
165 Dispatch(&wheelev);
168 void EventGenerator::SendMouseExit() {
169 gfx::Point exit_location(current_location_);
170 delegate()->ConvertPointToTarget(current_target_, &exit_location);
171 ui::MouseEvent mouseev(ui::ET_MOUSE_EXITED, exit_location, exit_location,
172 ui::EventTimeForNow(), flags_, 0);
173 Dispatch(&mouseev);
176 void EventGenerator::MoveMouseToInHost(const gfx::Point& point_in_host) {
177 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
178 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
179 ui::MouseEvent mouseev(event_type, point_in_host, point_in_host,
180 ui::EventTimeForNow(), flags_, 0);
181 Dispatch(&mouseev);
183 current_location_ = point_in_host;
184 delegate()->ConvertPointFromHost(current_target_, &current_location_);
187 void EventGenerator::MoveMouseTo(const gfx::Point& point_in_screen,
188 int count) {
189 DCHECK_GT(count, 0);
190 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
191 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
193 gfx::Vector2dF diff(point_in_screen - current_location_);
194 for (float i = 1; i <= count; i++) {
195 gfx::Vector2dF step(diff);
196 step.Scale(i / count);
197 gfx::Point move_point = current_location_ + gfx::ToRoundedVector2d(step);
198 if (!grab_)
199 UpdateCurrentDispatcher(move_point);
200 delegate()->ConvertPointToTarget(current_target_, &move_point);
201 ui::MouseEvent mouseev(event_type, move_point, move_point,
202 ui::EventTimeForNow(), flags_, 0);
203 Dispatch(&mouseev);
205 current_location_ = point_in_screen;
208 void EventGenerator::MoveMouseRelativeTo(const EventTarget* window,
209 const gfx::Point& point_in_parent) {
210 gfx::Point point(point_in_parent);
211 delegate()->ConvertPointFromTarget(window, &point);
212 MoveMouseTo(point);
215 void EventGenerator::DragMouseTo(const gfx::Point& point) {
216 PressLeftButton();
217 MoveMouseTo(point);
218 ReleaseLeftButton();
221 void EventGenerator::MoveMouseToCenterOf(EventTarget* window) {
222 MoveMouseTo(CenterOfWindow(window));
225 void EventGenerator::PressTouch() {
226 PressTouchId(0);
229 void EventGenerator::PressTouchId(int touch_id) {
230 TestTouchEvent touchev(
231 ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), touch_id, flags_,
232 Now());
233 Dispatch(&touchev);
236 void EventGenerator::MoveTouch(const gfx::Point& point) {
237 MoveTouchId(point, 0);
240 void EventGenerator::MoveTouchId(const gfx::Point& point, int touch_id) {
241 current_location_ = point;
242 TestTouchEvent touchev(
243 ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), touch_id, flags_,
244 Now());
245 Dispatch(&touchev);
247 if (!grab_)
248 UpdateCurrentDispatcher(point);
251 void EventGenerator::ReleaseTouch() {
252 ReleaseTouchId(0);
255 void EventGenerator::ReleaseTouchId(int touch_id) {
256 TestTouchEvent touchev(
257 ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), touch_id, flags_,
258 Now());
259 Dispatch(&touchev);
262 void EventGenerator::PressMoveAndReleaseTouchTo(const gfx::Point& point) {
263 PressTouch();
264 MoveTouch(point);
265 ReleaseTouch();
268 void EventGenerator::PressMoveAndReleaseTouchToCenterOf(EventTarget* window) {
269 PressMoveAndReleaseTouchTo(CenterOfWindow(window));
272 void EventGenerator::GestureEdgeSwipe() {
273 ui::GestureEvent gesture(
274 0, 0, 0, Now(), ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE));
275 Dispatch(&gesture);
278 void EventGenerator::GestureTapAt(const gfx::Point& location) {
279 const int kTouchId = 2;
280 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
281 location,
282 kTouchId,
283 Now());
284 Dispatch(&press);
286 ui::TouchEvent release(
287 ui::ET_TOUCH_RELEASED, location, kTouchId,
288 press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
289 Dispatch(&release);
292 void EventGenerator::GestureTapDownAndUp(const gfx::Point& location) {
293 const int kTouchId = 3;
294 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
295 location,
296 kTouchId,
297 Now());
298 Dispatch(&press);
300 ui::TouchEvent release(
301 ui::ET_TOUCH_RELEASED, location, kTouchId,
302 press.time_stamp() + base::TimeDelta::FromMilliseconds(1000));
303 Dispatch(&release);
306 base::TimeDelta EventGenerator::CalculateScrollDurationForFlingVelocity(
307 const gfx::Point& start,
308 const gfx::Point& end,
309 float velocity,
310 int steps) {
311 const float kGestureDistance = (start - end).Length();
312 const float kFlingStepDelay = (kGestureDistance / velocity) / steps * 1000000;
313 return base::TimeDelta::FromMicroseconds(kFlingStepDelay);
316 void EventGenerator::GestureScrollSequence(const gfx::Point& start,
317 const gfx::Point& end,
318 const base::TimeDelta& step_delay,
319 int steps) {
320 GestureScrollSequenceWithCallback(start, end, step_delay, steps,
321 base::Bind(&DummyCallback));
324 void EventGenerator::GestureScrollSequenceWithCallback(
325 const gfx::Point& start,
326 const gfx::Point& end,
327 const base::TimeDelta& step_delay,
328 int steps,
329 const ScrollStepCallback& callback) {
330 const int kTouchId = 5;
331 base::TimeDelta timestamp = Now();
332 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, kTouchId, timestamp);
333 Dispatch(&press);
335 callback.Run(ui::ET_GESTURE_SCROLL_BEGIN, gfx::Vector2dF());
337 float dx = static_cast<float>(end.x() - start.x()) / steps;
338 float dy = static_cast<float>(end.y() - start.y()) / steps;
339 gfx::PointF location = start;
340 for (int i = 0; i < steps; ++i) {
341 location.Offset(dx, dy);
342 timestamp += step_delay;
343 ui::TouchEvent move(ui::ET_TOUCH_MOVED, location, kTouchId, timestamp);
344 Dispatch(&move);
345 callback.Run(ui::ET_GESTURE_SCROLL_UPDATE, gfx::Vector2dF(dx, dy));
348 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, kTouchId, timestamp);
349 Dispatch(&release);
351 callback.Run(ui::ET_GESTURE_SCROLL_END, gfx::Vector2dF());
354 void EventGenerator::GestureMultiFingerScroll(int count,
355 const gfx::Point start[],
356 int event_separation_time_ms,
357 int steps,
358 int move_x,
359 int move_y) {
360 const int kMaxTouchPoints = 10;
361 int delays[kMaxTouchPoints] = { 0 };
362 GestureMultiFingerScrollWithDelays(
363 count, start, delays, event_separation_time_ms, steps, move_x, move_y);
366 void EventGenerator::GestureMultiFingerScrollWithDelays(
367 int count,
368 const gfx::Point start[],
369 const int delay_adding_finger_ms[],
370 int event_separation_time_ms,
371 int steps,
372 int move_x,
373 int move_y) {
374 const int kMaxTouchPoints = 10;
375 gfx::Point points[kMaxTouchPoints];
376 CHECK_LE(count, kMaxTouchPoints);
377 CHECK_GT(steps, 0);
379 int delta_x = move_x / steps;
380 int delta_y = move_y / steps;
382 for (int i = 0; i < count; ++i) {
383 points[i] = start[i];
386 base::TimeDelta press_time_first = Now();
387 base::TimeDelta press_time[kMaxTouchPoints];
388 bool pressed[kMaxTouchPoints];
389 for (int i = 0; i < count; ++i) {
390 pressed[i] = false;
391 press_time[i] = press_time_first +
392 base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]);
395 int last_id = 0;
396 for (int step = 0; step < steps; ++step) {
397 base::TimeDelta move_time = press_time_first +
398 base::TimeDelta::FromMilliseconds(event_separation_time_ms * step);
400 while (last_id < count &&
401 !pressed[last_id] &&
402 move_time >= press_time[last_id]) {
403 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
404 points[last_id],
405 last_id,
406 press_time[last_id]);
407 Dispatch(&press);
408 pressed[last_id] = true;
409 last_id++;
412 for (int i = 0; i < count; ++i) {
413 points[i].Offset(delta_x, delta_y);
414 if (i >= last_id)
415 continue;
416 ui::TouchEvent move(ui::ET_TOUCH_MOVED, points[i], i, move_time);
417 Dispatch(&move);
421 base::TimeDelta release_time = press_time_first +
422 base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps);
423 for (int i = 0; i < last_id; ++i) {
424 ui::TouchEvent release(
425 ui::ET_TOUCH_RELEASED, points[i], i, release_time);
426 Dispatch(&release);
430 void EventGenerator::ScrollSequence(const gfx::Point& start,
431 const base::TimeDelta& step_delay,
432 float x_offset,
433 float y_offset,
434 int steps,
435 int num_fingers) {
436 base::TimeDelta timestamp = Now();
437 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
438 start,
439 timestamp,
441 0, 0,
442 0, 0,
443 num_fingers);
444 Dispatch(&fling_cancel);
446 float dx = x_offset / steps;
447 float dy = y_offset / steps;
448 for (int i = 0; i < steps; ++i) {
449 timestamp += step_delay;
450 ui::ScrollEvent move(ui::ET_SCROLL,
451 start,
452 timestamp,
454 dx, dy,
455 dx, dy,
456 num_fingers);
457 Dispatch(&move);
460 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
461 start,
462 timestamp,
464 x_offset, y_offset,
465 x_offset, y_offset,
466 num_fingers);
467 Dispatch(&fling_start);
470 void EventGenerator::ScrollSequence(const gfx::Point& start,
471 const base::TimeDelta& step_delay,
472 const std::vector<gfx::PointF>& offsets,
473 int num_fingers) {
474 size_t steps = offsets.size();
475 base::TimeDelta timestamp = Now();
476 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
477 start,
478 timestamp,
480 0, 0,
481 0, 0,
482 num_fingers);
483 Dispatch(&fling_cancel);
485 for (size_t i = 0; i < steps; ++i) {
486 timestamp += step_delay;
487 ui::ScrollEvent scroll(ui::ET_SCROLL,
488 start,
489 timestamp,
491 offsets[i].x(), offsets[i].y(),
492 offsets[i].x(), offsets[i].y(),
493 num_fingers);
494 Dispatch(&scroll);
497 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
498 start,
499 timestamp,
501 offsets[steps - 1].x(), offsets[steps - 1].y(),
502 offsets[steps - 1].x(), offsets[steps - 1].y(),
503 num_fingers);
504 Dispatch(&fling_start);
507 void EventGenerator::PressKey(ui::KeyboardCode key_code, int flags) {
508 DispatchKeyEvent(true, key_code, flags);
511 void EventGenerator::ReleaseKey(ui::KeyboardCode key_code, int flags) {
512 DispatchKeyEvent(false, key_code, flags);
515 void EventGenerator::Dispatch(ui::Event* event) {
516 DoDispatchEvent(event, async_);
519 void EventGenerator::SetTickClock(scoped_ptr<base::TickClock> tick_clock) {
520 tick_clock_ = tick_clock.Pass();
523 base::TimeDelta EventGenerator::Now() {
524 // This is the same as what EventTimeForNow() does, but here we do it
525 // with a tick clock that can be replaced with a simulated clock for tests.
526 return base::TimeDelta::FromInternalValue(
527 tick_clock_->NowTicks().ToInternalValue());
530 void EventGenerator::Init(gfx::NativeWindow root_window,
531 gfx::NativeWindow window_context) {
532 delegate()->SetContext(this, root_window, window_context);
533 if (window_context)
534 current_location_ = delegate()->CenterOfWindow(window_context);
535 current_target_ = delegate()->GetTargetAt(current_location_);
538 void EventGenerator::DispatchKeyEvent(bool is_press,
539 ui::KeyboardCode key_code,
540 int flags) {
541 #if defined(OS_WIN)
542 UINT key_press = WM_KEYDOWN;
543 uint16 character = ui::GetCharacterFromKeyCode(key_code, flags);
544 if (is_press && character) {
545 MSG native_event = { NULL, WM_KEYDOWN, key_code, 0 };
546 TestKeyEvent keyev(native_event, flags);
547 Dispatch(&keyev);
548 // On Windows, WM_KEYDOWN event is followed by WM_CHAR with a character
549 // if the key event cooresponds to a real character.
550 key_press = WM_CHAR;
551 key_code = static_cast<ui::KeyboardCode>(character);
553 MSG native_event =
554 { NULL, (is_press ? key_press : WM_KEYUP), key_code, 0 };
555 native_event.time = Now().InMicroseconds();
556 TestKeyEvent keyev(native_event, flags);
557 #elif defined(USE_X11)
558 ui::ScopedXI2Event xevent;
559 xevent.InitKeyEvent(is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
560 key_code,
561 flags);
562 static_cast<XEvent*>(xevent)->xkey.time = Now().InMicroseconds();
563 ui::KeyEvent keyev(xevent);
564 #else
565 ui::EventType type = is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
566 ui::KeyEvent keyev(type, key_code, flags);
567 #endif // OS_WIN
568 Dispatch(&keyev);
571 void EventGenerator::UpdateCurrentDispatcher(const gfx::Point& point) {
572 current_target_ = delegate()->GetTargetAt(point);
575 void EventGenerator::PressButton(int flag) {
576 if (!(flags_ & flag)) {
577 flags_ |= flag;
578 grab_ = (flags_ & kAllButtonMask) != 0;
579 gfx::Point location = GetLocationInCurrentRoot();
580 ui::MouseEvent mouseev(ui::ET_MOUSE_PRESSED, location, location,
581 ui::EventTimeForNow(), flags_, flag);
582 Dispatch(&mouseev);
586 void EventGenerator::ReleaseButton(int flag) {
587 if (flags_ & flag) {
588 gfx::Point location = GetLocationInCurrentRoot();
589 ui::MouseEvent mouseev(ui::ET_MOUSE_RELEASED, location, location,
590 ui::EventTimeForNow(), flags_, flag);
591 Dispatch(&mouseev);
592 flags_ ^= flag;
594 grab_ = (flags_ & kAllButtonMask) != 0;
597 gfx::Point EventGenerator::GetLocationInCurrentRoot() const {
598 gfx::Point p(current_location_);
599 delegate()->ConvertPointToTarget(current_target_, &p);
600 return p;
603 gfx::Point EventGenerator::CenterOfWindow(const EventTarget* window) const {
604 return delegate()->CenterOfTarget(window);
607 void EventGenerator::DoDispatchEvent(ui::Event* event, bool async) {
608 if (async) {
609 ui::Event* pending_event;
610 if (event->IsKeyEvent()) {
611 pending_event = new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event));
612 } else if (event->IsMouseEvent()) {
613 pending_event = new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event));
614 } else if (event->IsTouchEvent()) {
615 pending_event = new ui::TouchEvent(*static_cast<ui::TouchEvent*>(event));
616 } else if (event->IsScrollEvent()) {
617 pending_event =
618 new ui::ScrollEvent(*static_cast<ui::ScrollEvent*>(event));
619 } else {
620 NOTREACHED() << "Invalid event type";
621 return;
623 if (pending_events_.empty()) {
624 base::ThreadTaskRunnerHandle::Get()->PostTask(
625 FROM_HERE,
626 base::Bind(&EventGenerator::DispatchNextPendingEvent,
627 base::Unretained(this)));
629 pending_events_.push_back(pending_event);
630 } else {
631 ui::EventSource* event_source = delegate()->GetEventSource(current_target_);
632 ui::EventSourceTestApi event_source_test(event_source);
633 ui::EventDispatchDetails details =
634 event_source_test.SendEventToProcessor(event);
635 CHECK(!details.dispatcher_destroyed);
639 void EventGenerator::DispatchNextPendingEvent() {
640 DCHECK(!pending_events_.empty());
641 ui::Event* event = pending_events_.front();
642 DoDispatchEvent(event, false);
643 pending_events_.pop_front();
644 delete event;
645 if (!pending_events_.empty()) {
646 base::ThreadTaskRunnerHandle::Get()->PostTask(
647 FROM_HERE,
648 base::Bind(&EventGenerator::DispatchNextPendingEvent,
649 base::Unretained(this)));
653 const EventGeneratorDelegate* EventGenerator::delegate() const {
654 if (delegate_)
655 return delegate_.get();
657 DCHECK(default_delegate);
658 return default_delegate;
661 EventGeneratorDelegate* EventGenerator::delegate() {
662 return const_cast<EventGeneratorDelegate*>(
663 const_cast<const EventGenerator*>(this)->delegate());
666 } // namespace test
667 } // namespace ui