event.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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#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 NULL;
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 || type() == ET_MOUSE_RELEASED)
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 (event.type() == ui::ET_MOUSE_RELEASED)
349      return last_click_event_->GetClickCount();
350    if (IsX11SendEventTrue(event.native_event()))
351      click_count = last_click_event_->GetClickCount();
352    else if (IsRepeatedClickEvent(*last_click_event_, event))
353      click_count = last_click_event_->GetClickCount() + 1;
354    delete last_click_event_;
355  }
356  last_click_event_ = new MouseEvent(event);
357  if (click_count > 3)
358    click_count = 3;
359  last_click_event_->SetClickCount(click_count);
360  return click_count;
361}
362
363// static
364MouseEvent* MouseEvent::last_click_event_ = NULL;
365
366int MouseEvent::GetClickCount() const {
367  if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
368    return 0;
369
370  if (flags() & EF_IS_TRIPLE_CLICK)
371    return 3;
372  else if (flags() & EF_IS_DOUBLE_CLICK)
373    return 2;
374  else
375    return 1;
376}
377
378void MouseEvent::SetClickCount(int click_count) {
379  if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
380    return;
381
382  DCHECK(click_count > 0);
383  DCHECK(click_count <= 3);
384
385  int f = flags();
386  switch (click_count) {
387    case 1:
388      f &= ~EF_IS_DOUBLE_CLICK;
389      f &= ~EF_IS_TRIPLE_CLICK;
390      break;
391    case 2:
392      f |= EF_IS_DOUBLE_CLICK;
393      f &= ~EF_IS_TRIPLE_CLICK;
394      break;
395    case 3:
396      f &= ~EF_IS_DOUBLE_CLICK;
397      f |= EF_IS_TRIPLE_CLICK;
398      break;
399  }
400  set_flags(f);
401}
402
403////////////////////////////////////////////////////////////////////////////////
404// MouseWheelEvent
405
406MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
407    : MouseEvent(native_event),
408      offset_(GetMouseWheelOffset(native_event)) {
409}
410
411MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
412    : MouseEvent(scroll_event),
413      offset_(scroll_event.x_offset(), scroll_event.y_offset()){
414  SetType(ET_MOUSEWHEEL);
415}
416
417MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
418                                 int x_offset,
419                                 int y_offset)
420    : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
421  DCHECK(type() == ET_MOUSEWHEEL);
422}
423
424MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
425    : MouseEvent(mouse_wheel_event),
426      offset_(mouse_wheel_event.offset()) {
427  DCHECK(type() == ET_MOUSEWHEEL);
428}
429
430#if defined(OS_WIN)
431// This value matches windows WHEEL_DELTA.
432// static
433const int MouseWheelEvent::kWheelDelta = 120;
434#else
435// This value matches GTK+ wheel scroll amount.
436const int MouseWheelEvent::kWheelDelta = 53;
437#endif
438
439void MouseWheelEvent::UpdateForRootTransform(
440    const gfx::Transform& inverted_root_transform) {
441  LocatedEvent::UpdateForRootTransform(inverted_root_transform);
442  gfx::DecomposedTransform decomp;
443  bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
444  DCHECK(success);
445  if (decomp.scale[0])
446    offset_.set_x(offset_.x() * decomp.scale[0]);
447  if (decomp.scale[1])
448    offset_.set_y(offset_.y() * decomp.scale[1]);
449}
450
451////////////////////////////////////////////////////////////////////////////////
452// TouchEvent
453
454TouchEvent::TouchEvent(const base::NativeEvent& native_event)
455    : LocatedEvent(native_event),
456      touch_id_(GetTouchId(native_event)),
457      radius_x_(GetTouchRadiusX(native_event)),
458      radius_y_(GetTouchRadiusY(native_event)),
459      rotation_angle_(GetTouchAngle(native_event)),
460      force_(GetTouchForce(native_event)) {
461  InitLatencyInfo();
462}
463
464TouchEvent::TouchEvent(EventType type,
465                       const gfx::Point& location,
466                       int touch_id,
467                       base::TimeDelta time_stamp)
468    : LocatedEvent(type, location, location, time_stamp, 0),
469      touch_id_(touch_id),
470      radius_x_(0.0f),
471      radius_y_(0.0f),
472      rotation_angle_(0.0f),
473      force_(0.0f) {
474  InitLatencyInfo();
475}
476
477TouchEvent::TouchEvent(EventType type,
478                       const gfx::Point& location,
479                       int flags,
480                       int touch_id,
481                       base::TimeDelta time_stamp,
482                       float radius_x,
483                       float radius_y,
484                       float angle,
485                       float force)
486    : LocatedEvent(type, location, location, time_stamp, flags),
487      touch_id_(touch_id),
488      radius_x_(radius_x),
489      radius_y_(radius_y),
490      rotation_angle_(angle),
491      force_(force) {
492  InitLatencyInfo();
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      is_char_(is_char),
529      character_(0),
530      unmodified_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      unmodified_character_(0) {
545}
546
547uint16 KeyEvent::GetCharacter() const {
548  if (character_)
549    return character_;
550
551#if defined(OS_WIN)
552  return (native_event().message == WM_CHAR) ? key_code_ :
553      GetCharacterFromKeyCode(key_code_, flags());
554#elif defined(USE_X11)
555  if (!native_event())
556    return GetCharacterFromKeyCode(key_code_, flags());
557
558  DCHECK(native_event()->type == KeyPress ||
559         native_event()->type == KeyRelease);
560
561  uint16 ch = 0;
562  if (!IsControlDown())
563    ch = GetCharacterFromXEvent(native_event());
564  return ch ? ch : GetCharacterFromKeyCode(key_code_, flags());
565#else
566  NOTIMPLEMENTED();
567  return 0;
568#endif
569}
570
571uint16 KeyEvent::GetUnmodifiedCharacter() const {
572  if (unmodified_character_)
573    return unmodified_character_;
574
575#if defined(OS_WIN)
576  // Looks like there is no way to get unmodified character on Windows.
577  return (native_event().message == WM_CHAR) ? key_code_ :
578      GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN);
579#elif defined(USE_X11)
580  if (!native_event())
581    return GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN);
582
583  DCHECK(native_event()->type == KeyPress ||
584         native_event()->type == KeyRelease);
585
586  static const unsigned int kIgnoredModifiers = ControlMask | LockMask |
587      Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask;
588
589  XKeyEvent copy = native_event()->xkey;  // bit-wise copy is safe.
590  // We can't use things like (native_event()->xkey.state & ShiftMask), as it
591  // may mask out bits used by X11 internally.
592  copy.state &= ~kIgnoredModifiers;
593  uint16 ch = GetCharacterFromXEvent(reinterpret_cast<XEvent*>(&copy));
594  return ch ? ch : GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN);
595#elif defined(USE_OZONE)
596  return is_char() ? key_code_ : GetCharacterFromKeyCode(
597                                     key_code_, flags() & EF_SHIFT_DOWN);
598#else
599  NOTIMPLEMENTED();
600  return 0;
601#endif
602}
603
604KeyEvent* KeyEvent::Copy() const {
605#if defined(USE_OZONE)
606  KeyEvent* copy = new KeyEvent(*this);
607#else
608  KeyEvent* copy = new KeyEvent(::CopyNativeEvent(native_event()), is_char());
609#endif
610#if defined(USE_X11)
611  copy->set_delete_native_event(true);
612#endif
613  return copy;
614}
615
616bool KeyEvent::IsUnicodeKeyCode() const {
617  if (!IsAltDown())
618    return false;
619  const int key = key_code();
620  if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
621    return true;
622  // Check whether the user is using the numeric keypad with num-lock off.
623  // In that case, EF_EXTENDED will not be set; if it is set, the key event
624  // originated from the relevant non-numpad dedicated key, e.g. [Insert].
625  return (!(flags() & EF_EXTENDED) &&
626          (key == VKEY_INSERT || key == VKEY_END  || key == VKEY_DOWN ||
627           key == VKEY_NEXT   || key == VKEY_LEFT || key == VKEY_CLEAR ||
628           key == VKEY_RIGHT  || key == VKEY_HOME || key == VKEY_UP ||
629           key == VKEY_PRIOR));
630}
631
632void KeyEvent::NormalizeFlags() {
633  int mask = 0;
634  switch (key_code()) {
635    case VKEY_CONTROL:
636      mask = EF_CONTROL_DOWN;
637      break;
638    case VKEY_SHIFT:
639      mask = EF_SHIFT_DOWN;
640      break;
641    case VKEY_MENU:
642      mask = EF_ALT_DOWN;
643      break;
644    case VKEY_CAPITAL:
645      mask = EF_CAPS_LOCK_DOWN;
646      break;
647    default:
648      return;
649  }
650  if (type() == ET_KEY_PRESSED)
651    set_flags(flags() | mask);
652  else
653    set_flags(flags() & ~mask);
654}
655
656////////////////////////////////////////////////////////////////////////////////
657// TranslatedKeyEvent
658
659TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event,
660                                       bool is_char)
661    : KeyEvent(native_event, is_char) {
662  SetType(type() == ET_KEY_PRESSED ?
663          ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE);
664}
665
666TranslatedKeyEvent::TranslatedKeyEvent(bool is_press,
667                                       KeyboardCode key_code,
668                                       int flags)
669    : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE),
670               key_code,
671               flags,
672               false) {
673}
674
675void TranslatedKeyEvent::ConvertToKeyEvent() {
676  SetType(type() == ET_TRANSLATED_KEY_PRESS ?
677          ET_KEY_PRESSED : ET_KEY_RELEASED);
678}
679
680////////////////////////////////////////////////////////////////////////////////
681// ScrollEvent
682
683ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
684    : MouseEvent(native_event) {
685  if (type() == ET_SCROLL) {
686    GetScrollOffsets(native_event,
687                     &x_offset_, &y_offset_,
688                     &x_offset_ordinal_, &y_offset_ordinal_,
689                     &finger_count_);
690  } else if (type() == ET_SCROLL_FLING_START ||
691             type() == ET_SCROLL_FLING_CANCEL) {
692    GetFlingData(native_event,
693                 &x_offset_, &y_offset_,
694                 &x_offset_ordinal_, &y_offset_ordinal_,
695                 NULL);
696  } else {
697    NOTREACHED() << "Unexpected event type " << type()
698        << " when constructing a ScrollEvent.";
699  }
700}
701
702ScrollEvent::ScrollEvent(EventType type,
703                         const gfx::Point& location,
704                         base::TimeDelta time_stamp,
705                         int flags,
706                         float x_offset,
707                         float y_offset,
708                         float x_offset_ordinal,
709                         float y_offset_ordinal,
710                         int finger_count)
711    : MouseEvent(type, location, location, flags),
712      x_offset_(x_offset),
713      y_offset_(y_offset),
714      x_offset_ordinal_(x_offset_ordinal),
715      y_offset_ordinal_(y_offset_ordinal),
716      finger_count_(finger_count) {
717  set_time_stamp(time_stamp);
718  CHECK(IsScrollEvent());
719}
720
721void ScrollEvent::Scale(const float factor) {
722  x_offset_ *= factor;
723  y_offset_ *= factor;
724  x_offset_ordinal_ *= factor;
725  y_offset_ordinal_ *= factor;
726}
727
728void ScrollEvent::UpdateForRootTransform(
729    const gfx::Transform& inverted_root_transform) {
730  LocatedEvent::UpdateForRootTransform(inverted_root_transform);
731  gfx::DecomposedTransform decomp;
732  bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
733  DCHECK(success);
734  if (decomp.scale[0])
735    x_offset_ordinal_ *= decomp.scale[0];
736  if (decomp.scale[1])
737    y_offset_ordinal_ *= decomp.scale[1];
738}
739
740////////////////////////////////////////////////////////////////////////////////
741// GestureEvent
742
743GestureEvent::GestureEvent(EventType type,
744                           int x,
745                           int y,
746                           int flags,
747                           base::TimeDelta time_stamp,
748                           const GestureEventDetails& details,
749                           unsigned int touch_ids_bitfield)
750    : LocatedEvent(type,
751                   gfx::Point(x, y),
752                   gfx::Point(x, y),
753                   time_stamp,
754                   flags | EF_FROM_TOUCH),
755      details_(details),
756      touch_ids_bitfield_(touch_ids_bitfield) {
757}
758
759GestureEvent::~GestureEvent() {
760}
761
762int GestureEvent::GetLowestTouchId() const {
763  if (touch_ids_bitfield_ == 0)
764    return -1;
765  int i = -1;
766  // Find the index of the least significant 1 bit
767  while (!(1 << ++i & touch_ids_bitfield_));
768  return i;
769}
770
771}  // namespace ui
772