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