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_->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(¤t_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_->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_->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, ¢er); 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 625