platformKeys: Add per-extension sign permissions.
[chromium-blink-merge.git] / ui / events / test / event_generator.cc
blobf743ba18408f9b98626ff2859a806d2a53225577
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,
148 ui::EventTimeForNow(), flags_, 0);
149 ui::MouseWheelEvent wheelev(mouseev, delta_x, delta_y);
150 Dispatch(&wheelev);
153 void EventGenerator::SendMouseExit() {
154 gfx::Point exit_location(current_location_);
155 delegate()->ConvertPointToTarget(current_target_, &exit_location);
156 ui::MouseEvent mouseev(ui::ET_MOUSE_EXITED, exit_location, exit_location,
157 ui::EventTimeForNow(), flags_, 0);
158 Dispatch(&mouseev);
161 void EventGenerator::MoveMouseToInHost(const gfx::Point& point_in_host) {
162 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
163 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
164 ui::MouseEvent mouseev(event_type, point_in_host, point_in_host,
165 ui::EventTimeForNow(), flags_, 0);
166 Dispatch(&mouseev);
168 current_location_ = point_in_host;
169 delegate()->ConvertPointFromHost(current_target_, &current_location_);
172 void EventGenerator::MoveMouseTo(const gfx::Point& point_in_screen,
173 int count) {
174 DCHECK_GT(count, 0);
175 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ?
176 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED;
178 gfx::Vector2dF diff(point_in_screen - current_location_);
179 for (float i = 1; i <= count; i++) {
180 gfx::Vector2dF step(diff);
181 step.Scale(i / count);
182 gfx::Point move_point = current_location_ + gfx::ToRoundedVector2d(step);
183 if (!grab_)
184 UpdateCurrentDispatcher(move_point);
185 delegate()->ConvertPointToTarget(current_target_, &move_point);
186 ui::MouseEvent mouseev(event_type, move_point, move_point,
187 ui::EventTimeForNow(), flags_, 0);
188 Dispatch(&mouseev);
190 current_location_ = point_in_screen;
193 void EventGenerator::MoveMouseRelativeTo(const EventTarget* window,
194 const gfx::Point& point_in_parent) {
195 gfx::Point point(point_in_parent);
196 delegate()->ConvertPointFromTarget(window, &point);
197 MoveMouseTo(point);
200 void EventGenerator::DragMouseTo(const gfx::Point& point) {
201 PressLeftButton();
202 MoveMouseTo(point);
203 ReleaseLeftButton();
206 void EventGenerator::MoveMouseToCenterOf(EventTarget* window) {
207 MoveMouseTo(CenterOfWindow(window));
210 void EventGenerator::PressTouch() {
211 PressTouchId(0);
214 void EventGenerator::PressTouchId(int touch_id) {
215 TestTouchEvent touchev(
216 ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), touch_id, flags_,
217 Now());
218 Dispatch(&touchev);
221 void EventGenerator::MoveTouch(const gfx::Point& point) {
222 MoveTouchId(point, 0);
225 void EventGenerator::MoveTouchId(const gfx::Point& point, int touch_id) {
226 current_location_ = point;
227 TestTouchEvent touchev(
228 ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), touch_id, flags_,
229 Now());
230 Dispatch(&touchev);
232 if (!grab_)
233 UpdateCurrentDispatcher(point);
236 void EventGenerator::ReleaseTouch() {
237 ReleaseTouchId(0);
240 void EventGenerator::ReleaseTouchId(int touch_id) {
241 TestTouchEvent touchev(
242 ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), touch_id, flags_,
243 Now());
244 Dispatch(&touchev);
247 void EventGenerator::PressMoveAndReleaseTouchTo(const gfx::Point& point) {
248 PressTouch();
249 MoveTouch(point);
250 ReleaseTouch();
253 void EventGenerator::PressMoveAndReleaseTouchToCenterOf(EventTarget* window) {
254 PressMoveAndReleaseTouchTo(CenterOfWindow(window));
257 void EventGenerator::GestureEdgeSwipe() {
258 ui::GestureEvent gesture(
259 0, 0, 0, Now(), ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE));
260 Dispatch(&gesture);
263 void EventGenerator::GestureTapAt(const gfx::Point& location) {
264 const int kTouchId = 2;
265 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
266 location,
267 kTouchId,
268 Now());
269 Dispatch(&press);
271 ui::TouchEvent release(
272 ui::ET_TOUCH_RELEASED, location, kTouchId,
273 press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
274 Dispatch(&release);
277 void EventGenerator::GestureTapDownAndUp(const gfx::Point& location) {
278 const int kTouchId = 3;
279 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
280 location,
281 kTouchId,
282 Now());
283 Dispatch(&press);
285 ui::TouchEvent release(
286 ui::ET_TOUCH_RELEASED, location, kTouchId,
287 press.time_stamp() + base::TimeDelta::FromMilliseconds(1000));
288 Dispatch(&release);
291 base::TimeDelta EventGenerator::CalculateScrollDurationForFlingVelocity(
292 const gfx::Point& start,
293 const gfx::Point& end,
294 float velocity,
295 int steps) {
296 const float kGestureDistance = (start - end).Length();
297 const float kFlingStepDelay = (kGestureDistance / velocity) / steps * 1000000;
298 return base::TimeDelta::FromMicroseconds(kFlingStepDelay);
301 void EventGenerator::GestureScrollSequence(const gfx::Point& start,
302 const gfx::Point& end,
303 const base::TimeDelta& step_delay,
304 int steps) {
305 GestureScrollSequenceWithCallback(start, end, step_delay, steps,
306 base::Bind(&DummyCallback));
309 void EventGenerator::GestureScrollSequenceWithCallback(
310 const gfx::Point& start,
311 const gfx::Point& end,
312 const base::TimeDelta& step_delay,
313 int steps,
314 const ScrollStepCallback& callback) {
315 const int kTouchId = 5;
316 base::TimeDelta timestamp = Now();
317 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, kTouchId, timestamp);
318 Dispatch(&press);
320 callback.Run(ui::ET_GESTURE_SCROLL_BEGIN, gfx::Vector2dF());
322 float dx = static_cast<float>(end.x() - start.x()) / steps;
323 float dy = static_cast<float>(end.y() - start.y()) / steps;
324 gfx::PointF location = start;
325 for (int i = 0; i < steps; ++i) {
326 location.Offset(dx, dy);
327 timestamp += step_delay;
328 ui::TouchEvent move(ui::ET_TOUCH_MOVED, location, kTouchId, timestamp);
329 Dispatch(&move);
330 callback.Run(ui::ET_GESTURE_SCROLL_UPDATE, gfx::Vector2dF(dx, dy));
333 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, kTouchId, timestamp);
334 Dispatch(&release);
336 callback.Run(ui::ET_GESTURE_SCROLL_END, gfx::Vector2dF());
339 void EventGenerator::GestureMultiFingerScroll(int count,
340 const gfx::Point start[],
341 int event_separation_time_ms,
342 int steps,
343 int move_x,
344 int move_y) {
345 const int kMaxTouchPoints = 10;
346 int delays[kMaxTouchPoints] = { 0 };
347 GestureMultiFingerScrollWithDelays(
348 count, start, delays, event_separation_time_ms, steps, move_x, move_y);
351 void EventGenerator::GestureMultiFingerScrollWithDelays(
352 int count,
353 const gfx::Point start[],
354 const int delay_adding_finger_ms[],
355 int event_separation_time_ms,
356 int steps,
357 int move_x,
358 int move_y) {
359 const int kMaxTouchPoints = 10;
360 gfx::Point points[kMaxTouchPoints];
361 CHECK_LE(count, kMaxTouchPoints);
362 CHECK_GT(steps, 0);
364 int delta_x = move_x / steps;
365 int delta_y = move_y / steps;
367 for (int i = 0; i < count; ++i) {
368 points[i] = start[i];
371 base::TimeDelta press_time_first = Now();
372 base::TimeDelta press_time[kMaxTouchPoints];
373 bool pressed[kMaxTouchPoints];
374 for (int i = 0; i < count; ++i) {
375 pressed[i] = false;
376 press_time[i] = press_time_first +
377 base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]);
380 int last_id = 0;
381 for (int step = 0; step < steps; ++step) {
382 base::TimeDelta move_time = press_time_first +
383 base::TimeDelta::FromMilliseconds(event_separation_time_ms * step);
385 while (last_id < count &&
386 !pressed[last_id] &&
387 move_time >= press_time[last_id]) {
388 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
389 points[last_id],
390 last_id,
391 press_time[last_id]);
392 Dispatch(&press);
393 pressed[last_id] = true;
394 last_id++;
397 for (int i = 0; i < count; ++i) {
398 points[i].Offset(delta_x, delta_y);
399 if (i >= last_id)
400 continue;
401 ui::TouchEvent move(ui::ET_TOUCH_MOVED, points[i], i, move_time);
402 Dispatch(&move);
406 base::TimeDelta release_time = press_time_first +
407 base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps);
408 for (int i = 0; i < last_id; ++i) {
409 ui::TouchEvent release(
410 ui::ET_TOUCH_RELEASED, points[i], i, release_time);
411 Dispatch(&release);
415 void EventGenerator::ScrollSequence(const gfx::Point& start,
416 const base::TimeDelta& step_delay,
417 float x_offset,
418 float y_offset,
419 int steps,
420 int num_fingers) {
421 base::TimeDelta timestamp = Now();
422 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
423 start,
424 timestamp,
426 0, 0,
427 0, 0,
428 num_fingers);
429 Dispatch(&fling_cancel);
431 float dx = x_offset / steps;
432 float dy = y_offset / steps;
433 for (int i = 0; i < steps; ++i) {
434 timestamp += step_delay;
435 ui::ScrollEvent move(ui::ET_SCROLL,
436 start,
437 timestamp,
439 dx, dy,
440 dx, dy,
441 num_fingers);
442 Dispatch(&move);
445 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
446 start,
447 timestamp,
449 x_offset, y_offset,
450 x_offset, y_offset,
451 num_fingers);
452 Dispatch(&fling_start);
455 void EventGenerator::ScrollSequence(const gfx::Point& start,
456 const base::TimeDelta& step_delay,
457 const std::vector<gfx::PointF>& offsets,
458 int num_fingers) {
459 size_t steps = offsets.size();
460 base::TimeDelta timestamp = Now();
461 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL,
462 start,
463 timestamp,
465 0, 0,
466 0, 0,
467 num_fingers);
468 Dispatch(&fling_cancel);
470 for (size_t i = 0; i < steps; ++i) {
471 timestamp += step_delay;
472 ui::ScrollEvent scroll(ui::ET_SCROLL,
473 start,
474 timestamp,
476 offsets[i].x(), offsets[i].y(),
477 offsets[i].x(), offsets[i].y(),
478 num_fingers);
479 Dispatch(&scroll);
482 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START,
483 start,
484 timestamp,
486 offsets[steps - 1].x(), offsets[steps - 1].y(),
487 offsets[steps - 1].x(), offsets[steps - 1].y(),
488 num_fingers);
489 Dispatch(&fling_start);
492 void EventGenerator::PressKey(ui::KeyboardCode key_code, int flags) {
493 DispatchKeyEvent(true, key_code, flags);
496 void EventGenerator::ReleaseKey(ui::KeyboardCode key_code, int flags) {
497 DispatchKeyEvent(false, key_code, flags);
500 void EventGenerator::Dispatch(ui::Event* event) {
501 DoDispatchEvent(event, async_);
504 void EventGenerator::SetTickClock(scoped_ptr<base::TickClock> tick_clock) {
505 tick_clock_ = tick_clock.Pass();
508 base::TimeDelta EventGenerator::Now() {
509 // This is the same as what EventTimeForNow() does, but here we do it
510 // with a tick clock that can be replaced with a simulated clock for tests.
511 return base::TimeDelta::FromInternalValue(
512 tick_clock_->NowTicks().ToInternalValue());
515 void EventGenerator::Init(gfx::NativeWindow root_window,
516 gfx::NativeWindow window_context) {
517 delegate()->SetContext(this, root_window, window_context);
518 if (window_context)
519 current_location_ = delegate()->CenterOfWindow(window_context);
520 current_target_ = delegate()->GetTargetAt(current_location_);
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);
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);
538 MSG native_event =
539 { NULL, (is_press ? key_press : WM_KEYUP), key_code, 0 };
540 TestKeyEvent keyev(native_event, flags);
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);
547 #else
548 ui::EventType type = is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
549 ui::KeyEvent keyev(type, key_code, flags);
550 #endif // OS_WIN
551 Dispatch(&keyev);
554 void EventGenerator::UpdateCurrentDispatcher(const gfx::Point& point) {
555 current_target_ = delegate()->GetTargetAt(point);
558 void EventGenerator::PressButton(int flag) {
559 if (!(flags_ & flag)) {
560 flags_ |= flag;
561 grab_ = (flags_ & kAllButtonMask) != 0;
562 gfx::Point location = GetLocationInCurrentRoot();
563 ui::MouseEvent mouseev(ui::ET_MOUSE_PRESSED, location, location,
564 ui::EventTimeForNow(), flags_, flag);
565 Dispatch(&mouseev);
569 void EventGenerator::ReleaseButton(int flag) {
570 if (flags_ & flag) {
571 gfx::Point location = GetLocationInCurrentRoot();
572 ui::MouseEvent mouseev(ui::ET_MOUSE_RELEASED, location, location,
573 ui::EventTimeForNow(), flags_, flag);
574 Dispatch(&mouseev);
575 flags_ ^= flag;
577 grab_ = (flags_ & kAllButtonMask) != 0;
580 gfx::Point EventGenerator::GetLocationInCurrentRoot() const {
581 gfx::Point p(current_location_);
582 delegate()->ConvertPointToTarget(current_target_, &p);
583 return p;
586 gfx::Point EventGenerator::CenterOfWindow(const EventTarget* window) const {
587 return delegate()->CenterOfTarget(window);
590 void EventGenerator::DoDispatchEvent(ui::Event* event, bool async) {
591 if (async) {
592 ui::Event* pending_event;
593 if (event->IsKeyEvent()) {
594 pending_event = new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event));
595 } else if (event->IsMouseEvent()) {
596 pending_event = new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event));
597 } else if (event->IsTouchEvent()) {
598 pending_event = new ui::TouchEvent(*static_cast<ui::TouchEvent*>(event));
599 } else if (event->IsScrollEvent()) {
600 pending_event =
601 new ui::ScrollEvent(*static_cast<ui::ScrollEvent*>(event));
602 } else {
603 NOTREACHED() << "Invalid event type";
604 return;
606 if (pending_events_.empty()) {
607 base::ThreadTaskRunnerHandle::Get()->PostTask(
608 FROM_HERE,
609 base::Bind(&EventGenerator::DispatchNextPendingEvent,
610 base::Unretained(this)));
612 pending_events_.push_back(pending_event);
613 } else {
614 ui::EventSource* event_source = delegate()->GetEventSource(current_target_);
615 ui::EventSourceTestApi event_source_test(event_source);
616 ui::EventDispatchDetails details =
617 event_source_test.SendEventToProcessor(event);
618 CHECK(!details.dispatcher_destroyed);
622 void EventGenerator::DispatchNextPendingEvent() {
623 DCHECK(!pending_events_.empty());
624 ui::Event* event = pending_events_.front();
625 DoDispatchEvent(event, false);
626 pending_events_.pop_front();
627 delete event;
628 if (!pending_events_.empty()) {
629 base::ThreadTaskRunnerHandle::Get()->PostTask(
630 FROM_HERE,
631 base::Bind(&EventGenerator::DispatchNextPendingEvent,
632 base::Unretained(this)));
636 const EventGeneratorDelegate* EventGenerator::delegate() const {
637 if (delegate_)
638 return delegate_.get();
640 DCHECK(default_delegate);
641 return default_delegate;
644 EventGeneratorDelegate* EventGenerator::delegate() {
645 return const_cast<EventGeneratorDelegate*>(
646 const_cast<const EventGenerator*>(this)->delegate());
649 } // namespace test
650 } // namespace ui