event.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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/events/event.h" 6 7#if defined(USE_X11) 8#include <X11/extensions/XInput2.h> 9#include <X11/Xlib.h> 10#endif 11 12#include <cmath> 13#include <cstring> 14 15#include "base/metrics/histogram.h" 16#include "base/strings/stringprintf.h" 17#include "ui/events/event_utils.h" 18#include "ui/events/keycodes/keyboard_code_conversion.h" 19#include "ui/gfx/point3_f.h" 20#include "ui/gfx/point_conversions.h" 21#include "ui/gfx/transform.h" 22#include "ui/gfx/transform_util.h" 23 24#if defined(USE_X11) 25#include "ui/events/keycodes/keyboard_code_conversion_x.h" 26#elif defined(USE_OZONE) 27#include "ui/events/keycodes/keyboard_code_conversion.h" 28#endif 29 30namespace { 31 32std::string EventTypeName(ui::EventType type) { 33#define RETURN_IF_TYPE(t) if (type == ui::t) return #t 34#define CASE_TYPE(t) case ui::t: return #t 35 switch (type) { 36 CASE_TYPE(ET_UNKNOWN); 37 CASE_TYPE(ET_MOUSE_PRESSED); 38 CASE_TYPE(ET_MOUSE_DRAGGED); 39 CASE_TYPE(ET_MOUSE_RELEASED); 40 CASE_TYPE(ET_MOUSE_MOVED); 41 CASE_TYPE(ET_MOUSE_ENTERED); 42 CASE_TYPE(ET_MOUSE_EXITED); 43 CASE_TYPE(ET_KEY_PRESSED); 44 CASE_TYPE(ET_KEY_RELEASED); 45 CASE_TYPE(ET_MOUSEWHEEL); 46 CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED); 47 CASE_TYPE(ET_TOUCH_RELEASED); 48 CASE_TYPE(ET_TOUCH_PRESSED); 49 CASE_TYPE(ET_TOUCH_MOVED); 50 CASE_TYPE(ET_TOUCH_CANCELLED); 51 CASE_TYPE(ET_DROP_TARGET_EVENT); 52 CASE_TYPE(ET_TRANSLATED_KEY_PRESS); 53 CASE_TYPE(ET_TRANSLATED_KEY_RELEASE); 54 CASE_TYPE(ET_GESTURE_SCROLL_BEGIN); 55 CASE_TYPE(ET_GESTURE_SCROLL_END); 56 CASE_TYPE(ET_GESTURE_SCROLL_UPDATE); 57 CASE_TYPE(ET_GESTURE_SHOW_PRESS); 58 CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE); 59 CASE_TYPE(ET_GESTURE_TAP); 60 CASE_TYPE(ET_GESTURE_TAP_DOWN); 61 CASE_TYPE(ET_GESTURE_TAP_CANCEL); 62 CASE_TYPE(ET_GESTURE_BEGIN); 63 CASE_TYPE(ET_GESTURE_END); 64 CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP); 65 CASE_TYPE(ET_GESTURE_PINCH_BEGIN); 66 CASE_TYPE(ET_GESTURE_PINCH_END); 67 CASE_TYPE(ET_GESTURE_PINCH_UPDATE); 68 CASE_TYPE(ET_GESTURE_LONG_PRESS); 69 CASE_TYPE(ET_GESTURE_LONG_TAP); 70 CASE_TYPE(ET_GESTURE_SWIPE); 71 CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED); 72 CASE_TYPE(ET_GESTURE_DOUBLE_TAP); 73 CASE_TYPE(ET_SCROLL); 74 CASE_TYPE(ET_SCROLL_FLING_START); 75 CASE_TYPE(ET_SCROLL_FLING_CANCEL); 76 CASE_TYPE(ET_CANCEL_MODE); 77 CASE_TYPE(ET_UMA_DATA); 78 case ui::ET_LAST: NOTREACHED(); return std::string(); 79 // Don't include default, so that we get an error when new type is added. 80 } 81#undef CASE_TYPE 82 83 NOTREACHED(); 84 return std::string(); 85} 86 87bool IsX11SendEventTrue(const base::NativeEvent& event) { 88#if defined(USE_X11) 89 if (event && event->xany.send_event) 90 return true; 91#endif 92 return false; 93} 94 95} // namespace 96 97namespace ui { 98 99//////////////////////////////////////////////////////////////////////////////// 100// Event 101 102Event::~Event() { 103 if (delete_native_event_) 104 ReleaseCopiedNativeEvent(native_event_); 105} 106 107bool Event::HasNativeEvent() const { 108 base::NativeEvent null_event; 109 std::memset(&null_event, 0, sizeof(null_event)); 110 return !!std::memcmp(&native_event_, &null_event, sizeof(null_event)); 111} 112 113void Event::StopPropagation() { 114 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch 115 // events. 116 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH); 117 CHECK(cancelable_); 118 result_ = static_cast<EventResult>(result_ | ER_CONSUMED); 119} 120 121void Event::SetHandled() { 122 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch 123 // events. 124 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH); 125 CHECK(cancelable_); 126 result_ = static_cast<EventResult>(result_ | ER_HANDLED); 127} 128 129Event::Event(EventType type, base::TimeDelta time_stamp, int flags) 130 : type_(type), 131 time_stamp_(time_stamp), 132 flags_(flags), 133 native_event_(base::NativeEvent()), 134 delete_native_event_(false), 135 cancelable_(true), 136 target_(NULL), 137 phase_(EP_PREDISPATCH), 138 result_(ER_UNHANDLED) { 139 if (type_ < ET_LAST) 140 name_ = EventTypeName(type_); 141} 142 143Event::Event(const base::NativeEvent& native_event, 144 EventType type, 145 int flags) 146 : type_(type), 147 time_stamp_(EventTimeFromNative(native_event)), 148 flags_(flags), 149 native_event_(native_event), 150 delete_native_event_(false), 151 cancelable_(true), 152 target_(NULL), 153 phase_(EP_PREDISPATCH), 154 result_(ER_UNHANDLED) { 155 base::TimeDelta delta = EventTimeForNow() - time_stamp_; 156 if (type_ < ET_LAST) 157 name_ = EventTypeName(type_); 158 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser", 159 delta.InMicroseconds(), 1, 1000000, 100); 160 std::string name_for_event = 161 base::StringPrintf("Event.Latency.Browser.%s", name_.c_str()); 162 base::HistogramBase* counter_for_type = 163 base::Histogram::FactoryGet( 164 name_for_event, 165 1, 166 1000000, 167 100, 168 base::HistogramBase::kUmaTargetedHistogramFlag); 169 counter_for_type->Add(delta.InMicroseconds()); 170} 171 172Event::Event(const Event& copy) 173 : type_(copy.type_), 174 time_stamp_(copy.time_stamp_), 175 latency_(copy.latency_), 176 flags_(copy.flags_), 177 native_event_(CopyNativeEvent(copy.native_event_)), 178 delete_native_event_(true), 179 cancelable_(true), 180 target_(NULL), 181 phase_(EP_PREDISPATCH), 182 result_(ER_UNHANDLED) { 183 if (type_ < ET_LAST) 184 name_ = EventTypeName(type_); 185} 186 187void Event::SetType(EventType type) { 188 if (type_ < ET_LAST) 189 name_ = std::string(); 190 type_ = type; 191 if (type_ < ET_LAST) 192 name_ = EventTypeName(type_); 193} 194 195//////////////////////////////////////////////////////////////////////////////// 196// CancelModeEvent 197 198CancelModeEvent::CancelModeEvent() 199 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) { 200 set_cancelable(false); 201} 202 203CancelModeEvent::~CancelModeEvent() { 204} 205 206//////////////////////////////////////////////////////////////////////////////// 207// LocatedEvent 208 209LocatedEvent::~LocatedEvent() { 210} 211 212LocatedEvent::LocatedEvent(const base::NativeEvent& native_event) 213 : Event(native_event, 214 EventTypeFromNative(native_event), 215 EventFlagsFromNative(native_event)), 216 location_(EventLocationFromNative(native_event)), 217 root_location_(location_) { 218} 219 220LocatedEvent::LocatedEvent(EventType type, 221 const gfx::PointF& location, 222 const gfx::PointF& root_location, 223 base::TimeDelta time_stamp, 224 int flags) 225 : Event(type, time_stamp, flags), 226 location_(location), 227 root_location_(root_location) { 228} 229 230void LocatedEvent::UpdateForRootTransform( 231 const gfx::Transform& reversed_root_transform) { 232 // Transform has to be done at root level. 233 gfx::Point3F p(location_); 234 reversed_root_transform.TransformPoint(&p); 235 location_ = p.AsPointF(); 236 root_location_ = location_; 237} 238 239//////////////////////////////////////////////////////////////////////////////// 240// MouseEvent 241 242MouseEvent::MouseEvent(const base::NativeEvent& native_event) 243 : LocatedEvent(native_event), 244 changed_button_flags_( 245 GetChangedMouseButtonFlagsFromNative(native_event)) { 246 if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED) 247 SetClickCount(GetRepeatCount(*this)); 248} 249 250MouseEvent::MouseEvent(EventType type, 251 const gfx::PointF& location, 252 const gfx::PointF& root_location, 253 int flags, 254 int changed_button_flags) 255 : LocatedEvent(type, location, root_location, EventTimeForNow(), flags), 256 changed_button_flags_(changed_button_flags) { 257 if (this->type() == ET_MOUSE_MOVED && IsAnyButton()) 258 SetType(ET_MOUSE_DRAGGED); 259} 260 261// static 262bool MouseEvent::IsRepeatedClickEvent( 263 const MouseEvent& event1, 264 const MouseEvent& event2) { 265 // These values match the Windows defaults. 266 static const int kDoubleClickTimeMS = 500; 267 static const int kDoubleClickWidth = 4; 268 static const int kDoubleClickHeight = 4; 269 270 if (event1.type() != ET_MOUSE_PRESSED || 271 event2.type() != ET_MOUSE_PRESSED) 272 return false; 273 274 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks. 275 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) != 276 (event2.flags() & ~EF_IS_DOUBLE_CLICK)) 277 return false; 278 279 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp(); 280 281 if (time_difference.InMilliseconds() > kDoubleClickTimeMS) 282 return false; 283 284 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2) 285 return false; 286 287 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2) 288 return false; 289 290 return true; 291} 292 293// static 294int MouseEvent::GetRepeatCount(const MouseEvent& event) { 295 int click_count = 1; 296 if (last_click_event_) { 297 if (event.type() == ui::ET_MOUSE_RELEASED) 298 return last_click_event_->GetClickCount(); 299 if (IsX11SendEventTrue(event.native_event())) 300 click_count = last_click_event_->GetClickCount(); 301 else if (IsRepeatedClickEvent(*last_click_event_, event)) 302 click_count = last_click_event_->GetClickCount() + 1; 303 delete last_click_event_; 304 } 305 last_click_event_ = new MouseEvent(event); 306 if (click_count > 3) 307 click_count = 3; 308 last_click_event_->SetClickCount(click_count); 309 return click_count; 310} 311 312// static 313MouseEvent* MouseEvent::last_click_event_ = NULL; 314 315int MouseEvent::GetClickCount() const { 316 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED) 317 return 0; 318 319 if (flags() & EF_IS_TRIPLE_CLICK) 320 return 3; 321 else if (flags() & EF_IS_DOUBLE_CLICK) 322 return 2; 323 else 324 return 1; 325} 326 327void MouseEvent::SetClickCount(int click_count) { 328 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED) 329 return; 330 331 DCHECK(click_count > 0); 332 DCHECK(click_count <= 3); 333 334 int f = flags(); 335 switch (click_count) { 336 case 1: 337 f &= ~EF_IS_DOUBLE_CLICK; 338 f &= ~EF_IS_TRIPLE_CLICK; 339 break; 340 case 2: 341 f |= EF_IS_DOUBLE_CLICK; 342 f &= ~EF_IS_TRIPLE_CLICK; 343 break; 344 case 3: 345 f &= ~EF_IS_DOUBLE_CLICK; 346 f |= EF_IS_TRIPLE_CLICK; 347 break; 348 } 349 set_flags(f); 350} 351 352//////////////////////////////////////////////////////////////////////////////// 353// MouseWheelEvent 354 355MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event) 356 : MouseEvent(native_event), 357 offset_(GetMouseWheelOffset(native_event)) { 358} 359 360MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event) 361 : MouseEvent(scroll_event), 362 offset_(scroll_event.x_offset(), scroll_event.y_offset()){ 363 SetType(ET_MOUSEWHEEL); 364} 365 366MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event, 367 int x_offset, 368 int y_offset) 369 : MouseEvent(mouse_event), offset_(x_offset, y_offset) { 370 DCHECK(type() == ET_MOUSEWHEEL); 371} 372 373MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event) 374 : MouseEvent(mouse_wheel_event), 375 offset_(mouse_wheel_event.offset()) { 376 DCHECK(type() == ET_MOUSEWHEEL); 377} 378 379#if defined(OS_WIN) 380// This value matches windows WHEEL_DELTA. 381// static 382const int MouseWheelEvent::kWheelDelta = 120; 383#else 384// This value matches GTK+ wheel scroll amount. 385const int MouseWheelEvent::kWheelDelta = 53; 386#endif 387 388void MouseWheelEvent::UpdateForRootTransform( 389 const gfx::Transform& inverted_root_transform) { 390 LocatedEvent::UpdateForRootTransform(inverted_root_transform); 391 gfx::DecomposedTransform decomp; 392 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform); 393 DCHECK(success); 394 if (decomp.scale[0]) 395 offset_.set_x(offset_.x() * decomp.scale[0]); 396 if (decomp.scale[1]) 397 offset_.set_y(offset_.y() * decomp.scale[1]); 398} 399 400//////////////////////////////////////////////////////////////////////////////// 401// TouchEvent 402 403TouchEvent::TouchEvent(const base::NativeEvent& native_event) 404 : LocatedEvent(native_event), 405 touch_id_(GetTouchId(native_event)), 406 radius_x_(GetTouchRadiusX(native_event)), 407 radius_y_(GetTouchRadiusY(native_event)), 408 rotation_angle_(GetTouchAngle(native_event)), 409 force_(GetTouchForce(native_event)), 410 source_device_id_(-1) { 411 latency()->AddLatencyNumberWithTimestamp( 412 INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 413 0, 414 0, 415 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 416 1); 417 418#if defined(USE_X11) 419 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data); 420 source_device_id_ = xiev->deviceid; 421#endif 422 423 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); 424} 425 426TouchEvent::TouchEvent(EventType type, 427 const gfx::PointF& location, 428 int touch_id, 429 base::TimeDelta time_stamp) 430 : LocatedEvent(type, location, location, time_stamp, 0), 431 touch_id_(touch_id), 432 radius_x_(0.0f), 433 radius_y_(0.0f), 434 rotation_angle_(0.0f), 435 force_(0.0f), 436 source_device_id_(-1) { 437 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); 438} 439 440TouchEvent::TouchEvent(EventType type, 441 const gfx::PointF& location, 442 int flags, 443 int touch_id, 444 base::TimeDelta time_stamp, 445 float radius_x, 446 float radius_y, 447 float angle, 448 float force) 449 : LocatedEvent(type, location, location, time_stamp, flags), 450 touch_id_(touch_id), 451 radius_x_(radius_x), 452 radius_y_(radius_y), 453 rotation_angle_(angle), 454 force_(force), 455 source_device_id_(-1) { 456 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); 457} 458 459TouchEvent::~TouchEvent() { 460 // In ctor TouchEvent(native_event) we call GetTouchId() which in X11 461 // platform setups the tracking_id to slot mapping. So in dtor here, 462 // if this touch event is a release event, we clear the mapping accordingly. 463 if (HasNativeEvent()) 464 ClearTouchIdIfReleased(native_event()); 465} 466 467void TouchEvent::UpdateForRootTransform( 468 const gfx::Transform& inverted_root_transform) { 469 LocatedEvent::UpdateForRootTransform(inverted_root_transform); 470 gfx::DecomposedTransform decomp; 471 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform); 472 DCHECK(success); 473 if (decomp.scale[0]) 474 radius_x_ *= decomp.scale[0]; 475 if (decomp.scale[1]) 476 radius_y_ *= decomp.scale[1]; 477} 478 479//////////////////////////////////////////////////////////////////////////////// 480// KeyEvent 481 482// static 483KeyEvent* KeyEvent::last_key_event_ = NULL; 484 485// static 486bool KeyEvent::IsRepeated(const KeyEvent& event) { 487 // A safe guard in case if there were continous key pressed events that are 488 // not auto repeat. 489 const int kMaxAutoRepeatTimeMs = 2000; 490 491 if (event.is_char()) 492 return false; 493 if (event.type() == ui::ET_KEY_RELEASED) { 494 delete last_key_event_; 495 last_key_event_ = NULL; 496 return false; 497 } 498 CHECK_EQ(ui::ET_KEY_PRESSED, event.type()); 499 if (!last_key_event_) { 500 last_key_event_ = new KeyEvent(event); 501 return false; 502 } 503 if (event.key_code() == last_key_event_->key_code() && 504 event.flags() == last_key_event_->flags() && 505 (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() < 506 kMaxAutoRepeatTimeMs) { 507 return true; 508 } 509 delete last_key_event_; 510 last_key_event_ = new KeyEvent(event); 511 return false; 512} 513 514KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char) 515 : Event(native_event, 516 EventTypeFromNative(native_event), 517 EventFlagsFromNative(native_event)), 518 key_code_(KeyboardCodeFromNative(native_event)), 519 code_(CodeFromNative(native_event)), 520 is_char_(is_char), 521 platform_keycode_(PlatformKeycodeFromNative(native_event)), 522 character_(0) { 523 if (IsRepeated(*this)) 524 set_flags(flags() | ui::EF_IS_REPEAT); 525 526#if defined(USE_X11) 527 NormalizeFlags(); 528#endif 529} 530 531KeyEvent::KeyEvent(EventType type, 532 KeyboardCode key_code, 533 int flags, 534 bool is_char) 535 : Event(type, EventTimeForNow(), flags), 536 key_code_(key_code), 537 is_char_(is_char), 538 platform_keycode_(0), 539 character_(GetCharacterFromKeyCode(key_code, flags)) { 540} 541 542KeyEvent::KeyEvent(EventType type, 543 KeyboardCode key_code, 544 const std::string& code, 545 int flags, 546 bool is_char) 547 : Event(type, EventTimeForNow(), flags), 548 key_code_(key_code), 549 code_(code), 550 is_char_(is_char), 551 platform_keycode_(0), 552 character_(GetCharacterFromKeyCode(key_code, flags)) { 553} 554 555uint16 KeyEvent::GetCharacter() const { 556 if (character_) 557 return character_; 558 559#if defined(OS_WIN) 560 return (native_event().message == WM_CHAR) ? key_code_ : 561 GetCharacterFromKeyCode(key_code_, flags()); 562#elif defined(USE_X11) 563 if (!native_event()) 564 return GetCharacterFromKeyCode(key_code_, flags()); 565 566 DCHECK(native_event()->type == KeyPress || 567 native_event()->type == KeyRelease); 568 569 // When a control key is held, prefer ASCII characters to non ASCII 570 // characters in order to use it for shortcut keys. GetCharacterFromKeyCode 571 // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11. 572 // GetCharacterFromXEvent returns 'à' in that case. 573 return IsControlDown() ? 574 GetCharacterFromKeyCode(key_code_, flags()) : 575 GetCharacterFromXEvent(native_event()); 576#else 577 if (native_event()) { 578 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED || 579 EventTypeFromNative(native_event()) == ET_KEY_RELEASED); 580 } 581 582 return GetCharacterFromKeyCode(key_code_, flags()); 583#endif 584} 585 586bool KeyEvent::IsUnicodeKeyCode() const { 587#if defined(OS_WIN) 588 if (!IsAltDown()) 589 return false; 590 const int key = key_code(); 591 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9) 592 return true; 593 // Check whether the user is using the numeric keypad with num-lock off. 594 // In that case, EF_EXTENDED will not be set; if it is set, the key event 595 // originated from the relevant non-numpad dedicated key, e.g. [Insert]. 596 return (!(flags() & EF_EXTENDED) && 597 (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN || 598 key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR || 599 key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP || 600 key == VKEY_PRIOR)); 601#else 602 return false; 603#endif 604} 605 606void KeyEvent::NormalizeFlags() { 607 int mask = 0; 608 switch (key_code()) { 609 case VKEY_CONTROL: 610 mask = EF_CONTROL_DOWN; 611 break; 612 case VKEY_SHIFT: 613 mask = EF_SHIFT_DOWN; 614 break; 615 case VKEY_MENU: 616 mask = EF_ALT_DOWN; 617 break; 618 case VKEY_CAPITAL: 619 mask = EF_CAPS_LOCK_DOWN; 620 break; 621 default: 622 return; 623 } 624 if (type() == ET_KEY_PRESSED) 625 set_flags(flags() | mask); 626 else 627 set_flags(flags() & ~mask); 628} 629 630bool KeyEvent::IsTranslated() const { 631 switch (type()) { 632 case ET_KEY_PRESSED: 633 case ET_KEY_RELEASED: 634 return false; 635 case ET_TRANSLATED_KEY_PRESS: 636 case ET_TRANSLATED_KEY_RELEASE: 637 return true; 638 default: 639 NOTREACHED(); 640 return false; 641 } 642} 643 644void KeyEvent::SetTranslated(bool translated) { 645 switch (type()) { 646 case ET_KEY_PRESSED: 647 case ET_TRANSLATED_KEY_PRESS: 648 SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED); 649 break; 650 case ET_KEY_RELEASED: 651 case ET_TRANSLATED_KEY_RELEASE: 652 SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED); 653 break; 654 default: 655 NOTREACHED(); 656 } 657} 658 659//////////////////////////////////////////////////////////////////////////////// 660// ScrollEvent 661 662ScrollEvent::ScrollEvent(const base::NativeEvent& native_event) 663 : MouseEvent(native_event) { 664 if (type() == ET_SCROLL) { 665 GetScrollOffsets(native_event, 666 &x_offset_, &y_offset_, 667 &x_offset_ordinal_, &y_offset_ordinal_, 668 &finger_count_); 669 } else if (type() == ET_SCROLL_FLING_START || 670 type() == ET_SCROLL_FLING_CANCEL) { 671 GetFlingData(native_event, 672 &x_offset_, &y_offset_, 673 &x_offset_ordinal_, &y_offset_ordinal_, 674 NULL); 675 } else { 676 NOTREACHED() << "Unexpected event type " << type() 677 << " when constructing a ScrollEvent."; 678 } 679} 680 681ScrollEvent::ScrollEvent(EventType type, 682 const gfx::PointF& location, 683 base::TimeDelta time_stamp, 684 int flags, 685 float x_offset, 686 float y_offset, 687 float x_offset_ordinal, 688 float y_offset_ordinal, 689 int finger_count) 690 : MouseEvent(type, location, location, flags, 0), 691 x_offset_(x_offset), 692 y_offset_(y_offset), 693 x_offset_ordinal_(x_offset_ordinal), 694 y_offset_ordinal_(y_offset_ordinal), 695 finger_count_(finger_count) { 696 set_time_stamp(time_stamp); 697 CHECK(IsScrollEvent()); 698} 699 700void ScrollEvent::Scale(const float factor) { 701 x_offset_ *= factor; 702 y_offset_ *= factor; 703 x_offset_ordinal_ *= factor; 704 y_offset_ordinal_ *= factor; 705} 706 707//////////////////////////////////////////////////////////////////////////////// 708// GestureEvent 709 710GestureEvent::GestureEvent(EventType type, 711 float x, 712 float y, 713 int flags, 714 base::TimeDelta time_stamp, 715 const GestureEventDetails& details, 716 unsigned int touch_ids_bitfield) 717 : LocatedEvent(type, 718 gfx::PointF(x, y), 719 gfx::PointF(x, y), 720 time_stamp, 721 flags | EF_FROM_TOUCH), 722 details_(details), 723 touch_ids_bitfield_(touch_ids_bitfield) { 724} 725 726GestureEvent::~GestureEvent() { 727} 728 729int GestureEvent::GetLowestTouchId() const { 730 if (touch_ids_bitfield_ == 0) 731 return -1; 732 int i = -1; 733 // Find the index of the least significant 1 bit 734 while (!(1 << ++i & touch_ids_bitfield_)); 735 return i; 736} 737 738} // namespace ui 739