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