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