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/base/events/event.h" 13 #include "ui/base/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/base/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(RootWindow* 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_; 41 } 42 43 virtual client::ScreenPositionClient* GetScreenPositionClient( 44 const aura::Window* window) const OVERRIDE { 45 return NULL; 46 } 47 48 private: 49 RootWindow* 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 flags) 67 : TouchEvent(type, root_location, flags, 0, ui::EventTimeForNow(), 68 1.0f, 1.0f, 1.0f, 1.0f) { 69 } 70 71 private: 72 DISALLOW_COPY_AND_ASSIGN(TestTouchEvent); 73 }; 74 75 const int kAllButtonMask = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON; 76 77 } // namespace 78 79 EventGenerator::EventGenerator(RootWindow* root_window) 80 : delegate_(new DefaultEventGeneratorDelegate(root_window)), 81 current_root_window_(delegate_->GetRootWindowAt(current_location_)), 82 flags_(0), 83 grab_(false), 84 async_(false) { 85 } 86 87 EventGenerator::EventGenerator(RootWindow* root_window, const gfx::Point& point) 88 : delegate_(new DefaultEventGeneratorDelegate(root_window)), 89 current_location_(point), 90 current_root_window_(delegate_->GetRootWindowAt(current_location_)), 91 flags_(0), 92 grab_(false), 93 async_(false) { 94 } 95 96 EventGenerator::EventGenerator(RootWindow* root_window, Window* window) 97 : delegate_(new DefaultEventGeneratorDelegate(root_window)), 98 current_location_(CenterOfWindow(window)), 99 current_root_window_(delegate_->GetRootWindowAt(current_location_)), 100 flags_(0), 101 grab_(false), 102 async_(false) { 103 } 104 105 EventGenerator::EventGenerator(EventGeneratorDelegate* delegate) 106 : delegate_(delegate), 107 current_root_window_(delegate_->GetRootWindowAt(current_location_)), 108 flags_(0), 109 grab_(false), 110 async_(false) { 111 } 112 113 EventGenerator::~EventGenerator() { 114 for (std::list<ui::Event*>::iterator i = pending_events_.begin(); 115 i != pending_events_.end(); ++i) 116 delete *i; 117 pending_events_.clear(); 118 } 119 120 void EventGenerator::PressLeftButton() { 121 PressButton(ui::EF_LEFT_MOUSE_BUTTON); 122 } 123 124 void EventGenerator::ReleaseLeftButton() { 125 ReleaseButton(ui::EF_LEFT_MOUSE_BUTTON); 126 } 127 128 void EventGenerator::ClickLeftButton() { 129 PressLeftButton(); 130 ReleaseLeftButton(); 131 } 132 133 void EventGenerator::DoubleClickLeftButton() { 134 flags_ |= ui::EF_IS_DOUBLE_CLICK; 135 PressLeftButton(); 136 flags_ ^= ui::EF_IS_DOUBLE_CLICK; 137 ReleaseLeftButton(); 138 } 139 140 void EventGenerator::PressRightButton() { 141 PressButton(ui::EF_RIGHT_MOUSE_BUTTON); 142 } 143 144 void EventGenerator::ReleaseRightButton() { 145 ReleaseButton(ui::EF_RIGHT_MOUSE_BUTTON); 146 } 147 148 void EventGenerator::MoveMouseToInHost(const gfx::Point& point_in_host) { 149 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ? 150 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED; 151 ui::MouseEvent mouseev(event_type, point_in_host, point_in_host, flags_); 152 Dispatch(&mouseev); 153 154 current_location_ = point_in_host; 155 current_root_window_->ConvertPointFromHost(¤t_location_); 156 } 157 158 void EventGenerator::MoveMouseTo(const gfx::Point& point_in_screen, 159 int count) { 160 DCHECK_GT(count, 0); 161 const ui::EventType event_type = (flags_ & ui::EF_LEFT_MOUSE_BUTTON) ? 162 ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED; 163 164 gfx::Vector2dF diff(point_in_screen - current_location_); 165 for (float i = 1; i <= count; i++) { 166 gfx::Vector2dF step(diff); 167 step.Scale(i / count); 168 gfx::Point move_point = current_location_ + gfx::ToRoundedVector2d(step); 169 if (!grab_) 170 UpdateCurrentRootWindow(move_point); 171 ConvertPointToTarget(current_root_window_, &move_point); 172 ui::MouseEvent mouseev(event_type, move_point, move_point, flags_); 173 Dispatch(&mouseev); 174 } 175 current_location_ = point_in_screen; 176 } 177 178 void EventGenerator::MoveMouseRelativeTo(const Window* window, 179 const gfx::Point& point_in_parent) { 180 gfx::Point point(point_in_parent); 181 ConvertPointFromTarget(window, &point); 182 MoveMouseTo(point); 183 } 184 185 void EventGenerator::DragMouseTo(const gfx::Point& point) { 186 PressLeftButton(); 187 MoveMouseTo(point); 188 ReleaseLeftButton(); 189 } 190 191 void EventGenerator::MoveMouseToCenterOf(Window* window) { 192 MoveMouseTo(CenterOfWindow(window)); 193 } 194 195 void EventGenerator::PressTouch() { 196 TestTouchEvent touchev( 197 ui::ET_TOUCH_PRESSED, GetLocationInCurrentRoot(), flags_); 198 Dispatch(&touchev); 199 } 200 201 void EventGenerator::MoveTouch(const gfx::Point& point) { 202 current_location_ = point; 203 TestTouchEvent touchev( 204 ui::ET_TOUCH_MOVED, GetLocationInCurrentRoot(), flags_); 205 Dispatch(&touchev); 206 207 if (!grab_) 208 UpdateCurrentRootWindow(point); 209 } 210 211 void EventGenerator::ReleaseTouch() { 212 TestTouchEvent touchev( 213 ui::ET_TOUCH_RELEASED, GetLocationInCurrentRoot(), flags_); 214 Dispatch(&touchev); 215 } 216 217 void EventGenerator::PressMoveAndReleaseTouchTo(const gfx::Point& point) { 218 PressTouch(); 219 MoveTouch(point); 220 ReleaseTouch(); 221 } 222 223 void EventGenerator::PressMoveAndReleaseTouchToCenterOf(Window* window) { 224 PressMoveAndReleaseTouchTo(CenterOfWindow(window)); 225 } 226 227 void EventGenerator::GestureTapAt(const gfx::Point& location) { 228 const int kTouchId = 2; 229 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 230 location, 231 kTouchId, 232 ui::EventTimeForNow()); 233 Dispatch(&press); 234 235 ui::TouchEvent release( 236 ui::ET_TOUCH_RELEASED, location, kTouchId, 237 press.time_stamp() + base::TimeDelta::FromMilliseconds(50)); 238 Dispatch(&release); 239 } 240 241 void EventGenerator::GestureTapDownAndUp(const gfx::Point& location) { 242 const int kTouchId = 3; 243 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 244 location, 245 kTouchId, 246 ui::EventTimeForNow()); 247 Dispatch(&press); 248 249 ui::TouchEvent release( 250 ui::ET_TOUCH_RELEASED, location, kTouchId, 251 press.time_stamp() + base::TimeDelta::FromMilliseconds(1000)); 252 Dispatch(&release); 253 } 254 255 void EventGenerator::GestureScrollSequence(const gfx::Point& start, 256 const gfx::Point& end, 257 const base::TimeDelta& step_delay, 258 int steps) { 259 GestureScrollSequenceWithCallback(start, end, step_delay, steps, 260 base::Bind(&DummyCallback)); 261 } 262 263 void EventGenerator::GestureScrollSequenceWithCallback( 264 const gfx::Point& start, 265 const gfx::Point& end, 266 const base::TimeDelta& step_delay, 267 int steps, 268 const ScrollStepCallback& callback) { 269 const int kTouchId = 5; 270 base::TimeDelta timestamp = ui::EventTimeForNow(); 271 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, kTouchId, timestamp); 272 Dispatch(&press); 273 274 callback.Run(ui::ET_GESTURE_SCROLL_BEGIN, gfx::Vector2dF()); 275 276 int dx = (end.x() - start.x()) / steps; 277 int dy = (end.y() - start.y()) / steps; 278 gfx::Point location = start; 279 for (int i = 0; i < steps; ++i) { 280 location.Offset(dx, dy); 281 timestamp += step_delay; 282 ui::TouchEvent move(ui::ET_TOUCH_MOVED, location, kTouchId, timestamp); 283 Dispatch(&move); 284 callback.Run(ui::ET_GESTURE_SCROLL_UPDATE, gfx::Vector2dF(dx, dy)); 285 } 286 287 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, kTouchId, timestamp); 288 Dispatch(&release); 289 290 callback.Run(ui::ET_GESTURE_SCROLL_END, gfx::Vector2dF()); 291 } 292 293 void EventGenerator::GestureMultiFingerScroll(int count, 294 const gfx::Point* start, 295 int event_separation_time_ms, 296 int steps, 297 int move_x, 298 int move_y) { 299 const int kMaxTouchPoints = 10; 300 gfx::Point points[kMaxTouchPoints]; 301 CHECK_LE(count, kMaxTouchPoints); 302 CHECK_GT(steps, 0); 303 304 int delta_x = move_x / steps; 305 int delta_y = move_y / steps; 306 307 base::TimeDelta press_time = ui::EventTimeForNow(); 308 for (int i = 0; i < count; ++i) { 309 points[i] = start[i]; 310 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, points[i], i, press_time); 311 Dispatch(&press); 312 } 313 314 for (int step = 0; step < steps; ++step) { 315 base::TimeDelta move_time = press_time + 316 base::TimeDelta::FromMilliseconds(event_separation_time_ms * step); 317 for (int i = 0; i < count; ++i) { 318 points[i].Offset(delta_x, delta_y); 319 ui::TouchEvent move(ui::ET_TOUCH_MOVED, points[i], i, move_time); 320 Dispatch(&move); 321 } 322 } 323 324 base::TimeDelta release_time = press_time + 325 base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps); 326 for (int i = 0; i < count; ++i) { 327 ui::TouchEvent release( 328 ui::ET_TOUCH_RELEASED, points[i], i, release_time); 329 Dispatch(&release); 330 } 331 } 332 333 void EventGenerator::ScrollSequence(const gfx::Point& start, 334 const base::TimeDelta& step_delay, 335 float x_offset, 336 float y_offset, 337 int steps, 338 int num_fingers) { 339 base::TimeDelta timestamp = base::TimeDelta::FromInternalValue( 340 base::TimeTicks::Now().ToInternalValue()); 341 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, 342 start, 343 timestamp, 344 0, 345 0, 0, 346 0, 0, 347 num_fingers); 348 Dispatch(&fling_cancel); 349 350 float dx = x_offset / steps; 351 float dy = y_offset / steps; 352 for (int i = 0; i < steps; ++i) { 353 timestamp += step_delay; 354 ui::ScrollEvent move(ui::ET_SCROLL, 355 start, 356 timestamp, 357 0, 358 dx, dy, 359 dx, dy, 360 num_fingers); 361 Dispatch(&move); 362 } 363 364 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, 365 start, 366 timestamp, 367 0, 368 x_offset, y_offset, 369 x_offset, y_offset, 370 num_fingers); 371 Dispatch(&fling_start); 372 } 373 374 void EventGenerator::ScrollSequence(const gfx::Point& start, 375 const base::TimeDelta& step_delay, 376 const std::vector<gfx::Point>& offsets, 377 int num_fingers) { 378 int steps = offsets.size(); 379 base::TimeDelta timestamp = ui::EventTimeForNow(); 380 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, 381 start, 382 timestamp, 383 0, 384 0, 0, 385 0, 0, 386 num_fingers); 387 Dispatch(&fling_cancel); 388 389 for (int i = 0; i < steps; ++i) { 390 timestamp += step_delay; 391 ui::ScrollEvent scroll(ui::ET_SCROLL, 392 start, 393 timestamp, 394 0, 395 offsets[i].x(), offsets[i].y(), 396 offsets[i].x(), offsets[i].y(), 397 num_fingers); 398 Dispatch(&scroll); 399 } 400 401 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, 402 start, 403 timestamp, 404 0, 405 offsets[steps - 1].x(), offsets[steps - 1].y(), 406 offsets[steps - 1].x(), offsets[steps - 1].y(), 407 num_fingers); 408 Dispatch(&fling_start); 409 } 410 411 void EventGenerator::PressKey(ui::KeyboardCode key_code, int flags) { 412 DispatchKeyEvent(true, key_code, flags); 413 } 414 415 void EventGenerator::ReleaseKey(ui::KeyboardCode key_code, int flags) { 416 DispatchKeyEvent(false, key_code, flags); 417 } 418 419 void EventGenerator::Dispatch(ui::Event* event) { 420 DoDispatchEvent(event, async_); 421 } 422 423 void EventGenerator::DispatchKeyEvent(bool is_press, 424 ui::KeyboardCode key_code, 425 int flags) { 426 #if defined(OS_WIN) 427 UINT key_press = WM_KEYDOWN; 428 uint16 character = ui::GetCharacterFromKeyCode(key_code, flags); 429 if (is_press && character) { 430 MSG native_event = { NULL, WM_KEYDOWN, key_code, 0 }; 431 TestKeyEvent keyev(native_event, flags, false); 432 Dispatch(&keyev); 433 // On Windows, WM_KEYDOWN event is followed by WM_CHAR with a character 434 // if the key event cooresponds to a real character. 435 key_press = WM_CHAR; 436 key_code = static_cast<ui::KeyboardCode>(character); 437 } 438 MSG native_event = 439 { NULL, (is_press ? key_press : WM_KEYUP), key_code, 0 }; 440 TestKeyEvent keyev(native_event, flags, key_press == WM_CHAR); 441 #else 442 ui::EventType type = is_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED; 443 #if defined(USE_X11) 444 scoped_ptr<XEvent> native_event(new XEvent); 445 ui::InitXKeyEventForTesting(type, key_code, flags, native_event.get()); 446 TestKeyEvent keyev(native_event.get(), flags, false); 447 #else 448 ui::KeyEvent keyev(type, key_code, flags, false); 449 #endif // USE_X11 450 #endif // OS_WIN 451 Dispatch(&keyev); 452 } 453 454 void EventGenerator::UpdateCurrentRootWindow(const gfx::Point& point) { 455 current_root_window_ = delegate_->GetRootWindowAt(point); 456 } 457 458 void EventGenerator::PressButton(int flag) { 459 if (!(flags_ & flag)) { 460 flags_ |= flag; 461 grab_ = flags_ & kAllButtonMask; 462 gfx::Point location = GetLocationInCurrentRoot(); 463 ui::MouseEvent mouseev(ui::ET_MOUSE_PRESSED, location, location, flags_); 464 Dispatch(&mouseev); 465 } 466 } 467 468 void EventGenerator::ReleaseButton(int flag) { 469 if (flags_ & flag) { 470 gfx::Point location = GetLocationInCurrentRoot(); 471 ui::MouseEvent mouseev(ui::ET_MOUSE_RELEASED, location, 472 location, flags_); 473 Dispatch(&mouseev); 474 flags_ ^= flag; 475 } 476 grab_ = flags_ & kAllButtonMask; 477 } 478 479 void EventGenerator::ConvertPointFromTarget(const aura::Window* target, 480 gfx::Point* point) const { 481 DCHECK(point); 482 aura::client::ScreenPositionClient* client = 483 delegate_->GetScreenPositionClient(target); 484 if (client) 485 client->ConvertPointToScreen(target, point); 486 else 487 aura::Window::ConvertPointToTarget(target, target->GetRootWindow(), point); 488 } 489 490 void EventGenerator::ConvertPointToTarget(const aura::Window* target, 491 gfx::Point* point) const { 492 DCHECK(point); 493 aura::client::ScreenPositionClient* client = 494 delegate_->GetScreenPositionClient(target); 495 if (client) 496 client->ConvertPointFromScreen(target, point); 497 else 498 aura::Window::ConvertPointToTarget(target->GetRootWindow(), target, point); 499 } 500 501 gfx::Point EventGenerator::GetLocationInCurrentRoot() const { 502 gfx::Point p(current_location_); 503 ConvertPointToTarget(current_root_window_, &p); 504 return p; 505 } 506 507 gfx::Point EventGenerator::CenterOfWindow(const Window* window) const { 508 gfx::Point center = gfx::Rect(window->bounds().size()).CenterPoint(); 509 ConvertPointFromTarget(window, ¢er); 510 return center; 511 } 512 513 void EventGenerator::DoDispatchEvent(ui::Event* event, bool async) { 514 if (async) { 515 ui::Event* pending_event; 516 if (event->IsKeyEvent()) { 517 pending_event = new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event)); 518 } else if (event->IsMouseEvent()) { 519 pending_event = new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event)); 520 } else if (event->IsTouchEvent()) { 521 pending_event = new ui::TouchEvent(*static_cast<ui::TouchEvent*>(event)); 522 } else if (event->IsScrollEvent()) { 523 pending_event = 524 new ui::ScrollEvent(*static_cast<ui::ScrollEvent*>(event)); 525 } else { 526 NOTREACHED() << "Invalid event type"; 527 return; 528 } 529 if (pending_events_.empty()) { 530 base::MessageLoopProxy::current()->PostTask( 531 FROM_HERE, 532 base::Bind(&EventGenerator::DispatchNextPendingEvent, 533 base::Unretained(this))); 534 } 535 pending_events_.push_back(pending_event); 536 } else { 537 RootWindowHostDelegate* root_window_host_delegate = 538 current_root_window_->AsRootWindowHostDelegate(); 539 if (event->IsKeyEvent()) { 540 root_window_host_delegate->OnHostKeyEvent( 541 static_cast<ui::KeyEvent*>(event)); 542 } else if (event->IsMouseEvent()) { 543 root_window_host_delegate->OnHostMouseEvent( 544 static_cast<ui::MouseEvent*>(event)); 545 } else if (event->IsTouchEvent()) { 546 root_window_host_delegate->OnHostTouchEvent( 547 static_cast<ui::TouchEvent*>(event)); 548 } else if (event->IsScrollEvent()) { 549 root_window_host_delegate->OnHostScrollEvent( 550 static_cast<ui::ScrollEvent*>(event)); 551 } else { 552 NOTREACHED() << "Invalid event type"; 553 } 554 } 555 } 556 557 void EventGenerator::DispatchNextPendingEvent() { 558 DCHECK(!pending_events_.empty()); 559 ui::Event* event = pending_events_.front(); 560 DoDispatchEvent(event, false); 561 pending_events_.pop_front(); 562 delete event; 563 if (!pending_events_.empty()) { 564 base::MessageLoopProxy::current()->PostTask( 565 FROM_HERE, 566 base::Bind(&EventGenerator::DispatchNextPendingEvent, 567 base::Unretained(this))); 568 } 569 } 570 571 572 } // namespace test 573 } // namespace aura 574