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  return event && event->xany.send_event;
90#else
91  return false;
92#endif
93}
94
95bool X11EventHasNonStandardState(const base::NativeEvent& event) {
96#if defined(USE_X11)
97  const unsigned int kAllStateMask =
98      Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask |
99      Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask |
100      LockMask | ControlMask | AnyModifier;
101  return event && (event->xkey.state & ~kAllStateMask) != 0;
102#else
103  return false;
104#endif
105}
106
107}  // namespace
108
109namespace ui {
110
111////////////////////////////////////////////////////////////////////////////////
112// Event
113
114Event::~Event() {
115  if (delete_native_event_)
116    ReleaseCopiedNativeEvent(native_event_);
117}
118
119bool Event::HasNativeEvent() const {
120  base::NativeEvent null_event;
121  std::memset(&null_event, 0, sizeof(null_event));
122  return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
123}
124
125void Event::StopPropagation() {
126  // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
127  // events.
128  // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
129  CHECK(cancelable_);
130  result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
131}
132
133void Event::SetHandled() {
134  // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
135  // events.
136  // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
137  CHECK(cancelable_);
138  result_ = static_cast<EventResult>(result_ | ER_HANDLED);
139}
140
141Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
142    : type_(type),
143      time_stamp_(time_stamp),
144      flags_(flags),
145      native_event_(base::NativeEvent()),
146      delete_native_event_(false),
147      cancelable_(true),
148      target_(NULL),
149      phase_(EP_PREDISPATCH),
150      result_(ER_UNHANDLED) {
151  if (type_ < ET_LAST)
152    name_ = EventTypeName(type_);
153}
154
155Event::Event(const base::NativeEvent& native_event,
156             EventType type,
157             int flags)
158    : type_(type),
159      time_stamp_(EventTimeFromNative(native_event)),
160      flags_(flags),
161      native_event_(native_event),
162      delete_native_event_(false),
163      cancelable_(true),
164      target_(NULL),
165      phase_(EP_PREDISPATCH),
166      result_(ER_UNHANDLED) {
167  base::TimeDelta delta = EventTimeForNow() - time_stamp_;
168  if (type_ < ET_LAST)
169    name_ = EventTypeName(type_);
170  UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser",
171                              delta.InMicroseconds(), 1, 1000000, 100);
172  std::string name_for_event =
173      base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
174  base::HistogramBase* counter_for_type =
175      base::Histogram::FactoryGet(
176          name_for_event,
177          1,
178          1000000,
179          100,
180          base::HistogramBase::kUmaTargetedHistogramFlag);
181  counter_for_type->Add(delta.InMicroseconds());
182}
183
184Event::Event(const Event& copy)
185    : type_(copy.type_),
186      time_stamp_(copy.time_stamp_),
187      latency_(copy.latency_),
188      flags_(copy.flags_),
189      native_event_(CopyNativeEvent(copy.native_event_)),
190      delete_native_event_(true),
191      cancelable_(true),
192      target_(NULL),
193      phase_(EP_PREDISPATCH),
194      result_(ER_UNHANDLED) {
195  if (type_ < ET_LAST)
196    name_ = EventTypeName(type_);
197}
198
199void Event::SetType(EventType type) {
200  if (type_ < ET_LAST)
201    name_ = std::string();
202  type_ = type;
203  if (type_ < ET_LAST)
204    name_ = EventTypeName(type_);
205}
206
207////////////////////////////////////////////////////////////////////////////////
208// CancelModeEvent
209
210CancelModeEvent::CancelModeEvent()
211    : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
212  set_cancelable(false);
213}
214
215CancelModeEvent::~CancelModeEvent() {
216}
217
218////////////////////////////////////////////////////////////////////////////////
219// LocatedEvent
220
221LocatedEvent::~LocatedEvent() {
222}
223
224LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
225    : Event(native_event,
226            EventTypeFromNative(native_event),
227            EventFlagsFromNative(native_event)),
228      location_(EventLocationFromNative(native_event)),
229      root_location_(location_) {
230}
231
232LocatedEvent::LocatedEvent(EventType type,
233                           const gfx::PointF& location,
234                           const gfx::PointF& root_location,
235                           base::TimeDelta time_stamp,
236                           int flags)
237    : Event(type, time_stamp, flags),
238      location_(location),
239      root_location_(root_location) {
240}
241
242void LocatedEvent::UpdateForRootTransform(
243    const gfx::Transform& reversed_root_transform) {
244  // Transform has to be done at root level.
245  gfx::Point3F p(location_);
246  reversed_root_transform.TransformPoint(&p);
247  location_ = p.AsPointF();
248  root_location_ = location_;
249}
250
251////////////////////////////////////////////////////////////////////////////////
252// MouseEvent
253
254MouseEvent::MouseEvent(const base::NativeEvent& native_event)
255    : LocatedEvent(native_event),
256      changed_button_flags_(
257          GetChangedMouseButtonFlagsFromNative(native_event)) {
258  if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED)
259    SetClickCount(GetRepeatCount(*this));
260}
261
262MouseEvent::MouseEvent(EventType type,
263                       const gfx::PointF& location,
264                       const gfx::PointF& root_location,
265                       int flags,
266                       int changed_button_flags)
267    : LocatedEvent(type, location, root_location, EventTimeForNow(), flags),
268      changed_button_flags_(changed_button_flags) {
269  if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
270    SetType(ET_MOUSE_DRAGGED);
271}
272
273// static
274bool MouseEvent::IsRepeatedClickEvent(
275    const MouseEvent& event1,
276    const MouseEvent& event2) {
277  // These values match the Windows defaults.
278  static const int kDoubleClickTimeMS = 500;
279  static const int kDoubleClickWidth = 4;
280  static const int kDoubleClickHeight = 4;
281
282  if (event1.type() != ET_MOUSE_PRESSED ||
283      event2.type() != ET_MOUSE_PRESSED)
284    return false;
285
286  // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
287  if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
288      (event2.flags() & ~EF_IS_DOUBLE_CLICK))
289    return false;
290
291  base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
292
293  if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
294    return false;
295
296  if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
297    return false;
298
299  if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
300    return false;
301
302  return true;
303}
304
305// static
306int MouseEvent::GetRepeatCount(const MouseEvent& event) {
307  int click_count = 1;
308  if (last_click_event_) {
309    if (event.type() == ui::ET_MOUSE_RELEASED) {
310      if (event.changed_button_flags() ==
311              last_click_event_->changed_button_flags()) {
312        last_click_complete_ = true;
313        return last_click_event_->GetClickCount();
314      } else {
315        // If last_click_event_ has changed since this button was pressed
316        // return a click count of 1.
317        return click_count;
318      }
319    }
320    if (event.time_stamp() != last_click_event_->time_stamp())
321      last_click_complete_ = true;
322    if (!last_click_complete_ ||
323        IsX11SendEventTrue(event.native_event())) {
324      click_count = last_click_event_->GetClickCount();
325    } else if (IsRepeatedClickEvent(*last_click_event_, event)) {
326      click_count = last_click_event_->GetClickCount() + 1;
327    }
328    delete last_click_event_;
329  }
330  last_click_event_ = new MouseEvent(event);
331  last_click_complete_ = false;
332  if (click_count > 3)
333    click_count = 3;
334  last_click_event_->SetClickCount(click_count);
335  return click_count;
336}
337
338void MouseEvent::ResetLastClickForTest() {
339  if (last_click_event_) {
340    delete last_click_event_;
341    last_click_event_ = NULL;
342    last_click_complete_ = false;
343  }
344}
345
346// static
347MouseEvent* MouseEvent::last_click_event_ = NULL;
348bool MouseEvent::last_click_complete_ = false;
349
350int MouseEvent::GetClickCount() const {
351  if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
352    return 0;
353
354  if (flags() & EF_IS_TRIPLE_CLICK)
355    return 3;
356  else if (flags() & EF_IS_DOUBLE_CLICK)
357    return 2;
358  else
359    return 1;
360}
361
362void MouseEvent::SetClickCount(int click_count) {
363  if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
364    return;
365
366  DCHECK(click_count > 0);
367  DCHECK(click_count <= 3);
368
369  int f = flags();
370  switch (click_count) {
371    case 1:
372      f &= ~EF_IS_DOUBLE_CLICK;
373      f &= ~EF_IS_TRIPLE_CLICK;
374      break;
375    case 2:
376      f |= EF_IS_DOUBLE_CLICK;
377      f &= ~EF_IS_TRIPLE_CLICK;
378      break;
379    case 3:
380      f &= ~EF_IS_DOUBLE_CLICK;
381      f |= EF_IS_TRIPLE_CLICK;
382      break;
383  }
384  set_flags(f);
385}
386
387////////////////////////////////////////////////////////////////////////////////
388// MouseWheelEvent
389
390MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
391    : MouseEvent(native_event),
392      offset_(GetMouseWheelOffset(native_event)) {
393}
394
395MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
396    : MouseEvent(scroll_event),
397      offset_(scroll_event.x_offset(), scroll_event.y_offset()){
398  SetType(ET_MOUSEWHEEL);
399}
400
401MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
402                                 int x_offset,
403                                 int y_offset)
404    : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
405  DCHECK(type() == ET_MOUSEWHEEL);
406}
407
408MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
409    : MouseEvent(mouse_wheel_event),
410      offset_(mouse_wheel_event.offset()) {
411  DCHECK(type() == ET_MOUSEWHEEL);
412}
413
414#if defined(OS_WIN)
415// This value matches windows WHEEL_DELTA.
416// static
417const int MouseWheelEvent::kWheelDelta = 120;
418#else
419// This value matches GTK+ wheel scroll amount.
420const int MouseWheelEvent::kWheelDelta = 53;
421#endif
422
423void MouseWheelEvent::UpdateForRootTransform(
424    const gfx::Transform& inverted_root_transform) {
425  LocatedEvent::UpdateForRootTransform(inverted_root_transform);
426  gfx::DecomposedTransform decomp;
427  bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
428  DCHECK(success);
429  if (decomp.scale[0])
430    offset_.set_x(offset_.x() * decomp.scale[0]);
431  if (decomp.scale[1])
432    offset_.set_y(offset_.y() * decomp.scale[1]);
433}
434
435////////////////////////////////////////////////////////////////////////////////
436// TouchEvent
437
438TouchEvent::TouchEvent(const base::NativeEvent& native_event)
439    : LocatedEvent(native_event),
440      touch_id_(GetTouchId(native_event)),
441      radius_x_(GetTouchRadiusX(native_event)),
442      radius_y_(GetTouchRadiusY(native_event)),
443      rotation_angle_(GetTouchAngle(native_event)),
444      force_(GetTouchForce(native_event)),
445      source_device_id_(-1) {
446  latency()->AddLatencyNumberWithTimestamp(
447      INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
448      0,
449      0,
450      base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
451      1);
452
453#if defined(USE_X11)
454  XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data);
455  source_device_id_ = xiev->deviceid;
456#endif
457
458  latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
459}
460
461TouchEvent::TouchEvent(EventType type,
462                       const gfx::PointF& location,
463                       int touch_id,
464                       base::TimeDelta time_stamp)
465    : LocatedEvent(type, location, location, time_stamp, 0),
466      touch_id_(touch_id),
467      radius_x_(0.0f),
468      radius_y_(0.0f),
469      rotation_angle_(0.0f),
470      force_(0.0f),
471      source_device_id_(-1) {
472  latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
473}
474
475TouchEvent::TouchEvent(EventType type,
476                       const gfx::PointF& 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      source_device_id_(-1) {
491  latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
492}
493
494TouchEvent::~TouchEvent() {
495  // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
496  // platform setups the tracking_id to slot mapping. So in dtor here,
497  // if this touch event is a release event, we clear the mapping accordingly.
498  if (HasNativeEvent())
499    ClearTouchIdIfReleased(native_event());
500}
501
502void TouchEvent::UpdateForRootTransform(
503    const gfx::Transform& inverted_root_transform) {
504  LocatedEvent::UpdateForRootTransform(inverted_root_transform);
505  gfx::DecomposedTransform decomp;
506  bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
507  DCHECK(success);
508  if (decomp.scale[0])
509    radius_x_ *= decomp.scale[0];
510  if (decomp.scale[1])
511    radius_y_ *= decomp.scale[1];
512}
513
514////////////////////////////////////////////////////////////////////////////////
515// KeyEvent
516
517// static
518KeyEvent* KeyEvent::last_key_event_ = NULL;
519
520// static
521bool KeyEvent::IsRepeated(const KeyEvent& event) {
522  // A safe guard in case if there were continous key pressed events that are
523  // not auto repeat.
524  const int kMaxAutoRepeatTimeMs = 2000;
525  // Ignore key events that have non standard state masks as it may be
526  // reposted by an IME. IBUS-GTK uses this field to detect the
527  // re-posted event for example. crbug.com/385873.
528  if (X11EventHasNonStandardState(event.native_event()))
529    return false;
530  if (event.is_char())
531    return false;
532  if (event.type() == ui::ET_KEY_RELEASED) {
533    delete last_key_event_;
534    last_key_event_ = NULL;
535    return false;
536  }
537  CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
538  if (!last_key_event_) {
539    last_key_event_ = new KeyEvent(event);
540    return false;
541  }
542  if (event.key_code() == last_key_event_->key_code() &&
543      event.flags() == last_key_event_->flags() &&
544      (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() <
545      kMaxAutoRepeatTimeMs) {
546    return true;
547  }
548  delete last_key_event_;
549  last_key_event_ = new KeyEvent(event);
550  return false;
551}
552
553KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char)
554    : Event(native_event,
555            EventTypeFromNative(native_event),
556            EventFlagsFromNative(native_event)),
557      key_code_(KeyboardCodeFromNative(native_event)),
558      code_(CodeFromNative(native_event)),
559      is_char_(is_char),
560      platform_keycode_(PlatformKeycodeFromNative(native_event)),
561      character_(0) {
562  if (IsRepeated(*this))
563    set_flags(flags() | ui::EF_IS_REPEAT);
564
565#if defined(USE_X11)
566  NormalizeFlags();
567#endif
568}
569
570KeyEvent::KeyEvent(EventType type,
571                   KeyboardCode key_code,
572                   int flags,
573                   bool is_char)
574    : Event(type, EventTimeForNow(), flags),
575      key_code_(key_code),
576      is_char_(is_char),
577      platform_keycode_(0),
578      character_(GetCharacterFromKeyCode(key_code, flags)) {
579}
580
581KeyEvent::KeyEvent(EventType type,
582                   KeyboardCode key_code,
583                   const std::string& code,
584                   int flags,
585                   bool is_char)
586    : Event(type, EventTimeForNow(), flags),
587      key_code_(key_code),
588      code_(code),
589      is_char_(is_char),
590      platform_keycode_(0),
591      character_(GetCharacterFromKeyCode(key_code, flags)) {
592}
593
594uint16 KeyEvent::GetCharacter() const {
595  if (character_)
596    return character_;
597
598#if defined(OS_WIN)
599  return (native_event().message == WM_CHAR) ? key_code_ :
600      GetCharacterFromKeyCode(key_code_, flags());
601#elif defined(USE_X11)
602  if (!native_event())
603    return GetCharacterFromKeyCode(key_code_, flags());
604
605  DCHECK(native_event()->type == KeyPress ||
606         native_event()->type == KeyRelease);
607
608  // When a control key is held, prefer ASCII characters to non ASCII
609  // characters in order to use it for shortcut keys.  GetCharacterFromKeyCode
610  // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
611  // GetCharacterFromXEvent returns 'à' in that case.
612  return IsControlDown() ?
613      GetCharacterFromKeyCode(key_code_, flags()) :
614      GetCharacterFromXEvent(native_event());
615#else
616  if (native_event()) {
617    DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
618           EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
619  }
620
621  return GetCharacterFromKeyCode(key_code_, flags());
622#endif
623}
624
625bool KeyEvent::IsUnicodeKeyCode() const {
626#if defined(OS_WIN)
627  if (!IsAltDown())
628    return false;
629  const int key = key_code();
630  if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
631    return true;
632  // Check whether the user is using the numeric keypad with num-lock off.
633  // In that case, EF_EXTENDED will not be set; if it is set, the key event
634  // originated from the relevant non-numpad dedicated key, e.g. [Insert].
635  return (!(flags() & EF_EXTENDED) &&
636          (key == VKEY_INSERT || key == VKEY_END  || key == VKEY_DOWN ||
637           key == VKEY_NEXT   || key == VKEY_LEFT || key == VKEY_CLEAR ||
638           key == VKEY_RIGHT  || key == VKEY_HOME || key == VKEY_UP ||
639           key == VKEY_PRIOR));
640#else
641  return false;
642#endif
643}
644
645void KeyEvent::NormalizeFlags() {
646  int mask = 0;
647  switch (key_code()) {
648    case VKEY_CONTROL:
649      mask = EF_CONTROL_DOWN;
650      break;
651    case VKEY_SHIFT:
652      mask = EF_SHIFT_DOWN;
653      break;
654    case VKEY_MENU:
655      mask = EF_ALT_DOWN;
656      break;
657    case VKEY_CAPITAL:
658      mask = EF_CAPS_LOCK_DOWN;
659      break;
660    default:
661      return;
662  }
663  if (type() == ET_KEY_PRESSED)
664    set_flags(flags() | mask);
665  else
666    set_flags(flags() & ~mask);
667}
668
669bool KeyEvent::IsTranslated() const {
670  switch (type()) {
671    case ET_KEY_PRESSED:
672    case ET_KEY_RELEASED:
673      return false;
674    case ET_TRANSLATED_KEY_PRESS:
675    case ET_TRANSLATED_KEY_RELEASE:
676      return true;
677    default:
678      NOTREACHED();
679      return false;
680  }
681}
682
683void KeyEvent::SetTranslated(bool translated) {
684  switch (type()) {
685    case ET_KEY_PRESSED:
686    case ET_TRANSLATED_KEY_PRESS:
687      SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED);
688      break;
689    case ET_KEY_RELEASED:
690    case ET_TRANSLATED_KEY_RELEASE:
691      SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED);
692      break;
693    default:
694      NOTREACHED();
695  }
696}
697
698////////////////////////////////////////////////////////////////////////////////
699// ScrollEvent
700
701ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
702    : MouseEvent(native_event) {
703  if (type() == ET_SCROLL) {
704    GetScrollOffsets(native_event,
705                     &x_offset_, &y_offset_,
706                     &x_offset_ordinal_, &y_offset_ordinal_,
707                     &finger_count_);
708  } else if (type() == ET_SCROLL_FLING_START ||
709             type() == ET_SCROLL_FLING_CANCEL) {
710    GetFlingData(native_event,
711                 &x_offset_, &y_offset_,
712                 &x_offset_ordinal_, &y_offset_ordinal_,
713                 NULL);
714  } else {
715    NOTREACHED() << "Unexpected event type " << type()
716        << " when constructing a ScrollEvent.";
717  }
718}
719
720ScrollEvent::ScrollEvent(EventType type,
721                         const gfx::PointF& location,
722                         base::TimeDelta time_stamp,
723                         int flags,
724                         float x_offset,
725                         float y_offset,
726                         float x_offset_ordinal,
727                         float y_offset_ordinal,
728                         int finger_count)
729    : MouseEvent(type, location, location, flags, 0),
730      x_offset_(x_offset),
731      y_offset_(y_offset),
732      x_offset_ordinal_(x_offset_ordinal),
733      y_offset_ordinal_(y_offset_ordinal),
734      finger_count_(finger_count) {
735  set_time_stamp(time_stamp);
736  CHECK(IsScrollEvent());
737}
738
739void ScrollEvent::Scale(const float factor) {
740  x_offset_ *= factor;
741  y_offset_ *= factor;
742  x_offset_ordinal_ *= factor;
743  y_offset_ordinal_ *= factor;
744}
745
746////////////////////////////////////////////////////////////////////////////////
747// GestureEvent
748
749GestureEvent::GestureEvent(EventType type,
750                           float x,
751                           float y,
752                           int flags,
753                           base::TimeDelta time_stamp,
754                           const GestureEventDetails& details,
755                           unsigned int touch_ids_bitfield)
756    : LocatedEvent(type,
757                   gfx::PointF(x, y),
758                   gfx::PointF(x, y),
759                   time_stamp,
760                   flags | EF_FROM_TOUCH),
761      details_(details),
762      touch_ids_bitfield_(touch_ids_bitfield) {
763}
764
765GestureEvent::~GestureEvent() {
766}
767
768int GestureEvent::GetLowestTouchId() const {
769  if (touch_ids_bitfield_ == 0)
770    return -1;
771  int i = -1;
772  // Find the index of the least significant 1 bit
773  while (!(1 << ++i & touch_ids_bitfield_));
774  return i;
775}
776
777}  // namespace ui
778