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