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