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#include <X11/keysym.h>
11#endif
12
13#include <cmath>
14#include <cstring>
15
16#include "base/metrics/histogram.h"
17#include "base/strings/stringprintf.h"
18#include "ui/events/event_utils.h"
19#include "ui/events/keycodes/keyboard_code_conversion.h"
20#include "ui/gfx/point3_f.h"
21#include "ui/gfx/point_conversions.h"
22#include "ui/gfx/transform.h"
23#include "ui/gfx/transform_util.h"
24
25#if defined(USE_X11)
26#include "ui/events/keycodes/keyboard_code_conversion_x.h"
27#elif defined(USE_OZONE)
28#include "ui/events/keycodes/keyboard_code_conversion.h"
29#endif
30
31namespace {
32
33std::string EventTypeName(ui::EventType type) {
34#define RETURN_IF_TYPE(t) if (type == ui::t)  return #t
35#define CASE_TYPE(t) case ui::t:  return #t
36  switch (type) {
37    CASE_TYPE(ET_UNKNOWN);
38    CASE_TYPE(ET_MOUSE_PRESSED);
39    CASE_TYPE(ET_MOUSE_DRAGGED);
40    CASE_TYPE(ET_MOUSE_RELEASED);
41    CASE_TYPE(ET_MOUSE_MOVED);
42    CASE_TYPE(ET_MOUSE_ENTERED);
43    CASE_TYPE(ET_MOUSE_EXITED);
44    CASE_TYPE(ET_KEY_PRESSED);
45    CASE_TYPE(ET_KEY_RELEASED);
46    CASE_TYPE(ET_MOUSEWHEEL);
47    CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED);
48    CASE_TYPE(ET_TOUCH_RELEASED);
49    CASE_TYPE(ET_TOUCH_PRESSED);
50    CASE_TYPE(ET_TOUCH_MOVED);
51    CASE_TYPE(ET_TOUCH_CANCELLED);
52    CASE_TYPE(ET_DROP_TARGET_EVENT);
53    CASE_TYPE(ET_TRANSLATED_KEY_PRESS);
54    CASE_TYPE(ET_TRANSLATED_KEY_RELEASE);
55    CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
56    CASE_TYPE(ET_GESTURE_SCROLL_END);
57    CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
58    CASE_TYPE(ET_GESTURE_SHOW_PRESS);
59    CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE);
60    CASE_TYPE(ET_GESTURE_TAP);
61    CASE_TYPE(ET_GESTURE_TAP_DOWN);
62    CASE_TYPE(ET_GESTURE_TAP_CANCEL);
63    CASE_TYPE(ET_GESTURE_BEGIN);
64    CASE_TYPE(ET_GESTURE_END);
65    CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP);
66    CASE_TYPE(ET_GESTURE_PINCH_BEGIN);
67    CASE_TYPE(ET_GESTURE_PINCH_END);
68    CASE_TYPE(ET_GESTURE_PINCH_UPDATE);
69    CASE_TYPE(ET_GESTURE_LONG_PRESS);
70    CASE_TYPE(ET_GESTURE_LONG_TAP);
71    CASE_TYPE(ET_GESTURE_SWIPE);
72    CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED);
73    CASE_TYPE(ET_GESTURE_DOUBLE_TAP);
74    CASE_TYPE(ET_SCROLL);
75    CASE_TYPE(ET_SCROLL_FLING_START);
76    CASE_TYPE(ET_SCROLL_FLING_CANCEL);
77    CASE_TYPE(ET_CANCEL_MODE);
78    CASE_TYPE(ET_UMA_DATA);
79    case ui::ET_LAST: NOTREACHED(); return std::string();
80    // Don't include default, so that we get an error when new type is added.
81  }
82#undef CASE_TYPE
83
84  NOTREACHED();
85  return std::string();
86}
87
88bool IsX11SendEventTrue(const base::NativeEvent& event) {
89#if defined(USE_X11)
90  return event && event->xany.send_event;
91#else
92  return false;
93#endif
94}
95
96bool X11EventHasNonStandardState(const base::NativeEvent& event) {
97#if defined(USE_X11)
98  const unsigned int kAllStateMask =
99      Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask |
100      Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask |
101      LockMask | ControlMask | AnyModifier;
102  return event && (event->xkey.state & ~kAllStateMask) != 0;
103#else
104  return false;
105#endif
106}
107
108}  // namespace
109
110namespace ui {
111
112////////////////////////////////////////////////////////////////////////////////
113// Event
114
115// static
116scoped_ptr<Event> Event::Clone(const Event& event) {
117  if (event.IsKeyEvent()) {
118    return scoped_ptr<Event>(new KeyEvent(static_cast<const KeyEvent&>(event)));
119  }
120
121  if (event.IsMouseEvent()) {
122    if (event.IsMouseWheelEvent()) {
123      return scoped_ptr<Event>(
124          new MouseWheelEvent(static_cast<const MouseWheelEvent&>(event)));
125    }
126
127    return scoped_ptr<Event>(
128        new MouseEvent(static_cast<const MouseEvent&>(event)));
129  }
130
131  if (event.IsTouchEvent()) {
132    return scoped_ptr<Event>(
133        new TouchEvent(static_cast<const TouchEvent&>(event)));
134  }
135
136  if (event.IsGestureEvent()) {
137    return scoped_ptr<Event>(
138        new GestureEvent(static_cast<const GestureEvent&>(event)));
139  }
140
141  if (event.IsScrollEvent()) {
142    return scoped_ptr<Event>(
143        new ScrollEvent(static_cast<const ScrollEvent&>(event)));
144  }
145
146  return scoped_ptr<Event>(new Event(event));
147}
148
149Event::~Event() {
150  if (delete_native_event_)
151    ReleaseCopiedNativeEvent(native_event_);
152}
153
154GestureEvent* Event::AsGestureEvent() {
155  CHECK(IsGestureEvent());
156  return static_cast<GestureEvent*>(this);
157}
158
159const GestureEvent* Event::AsGestureEvent() const {
160  CHECK(IsGestureEvent());
161  return static_cast<const GestureEvent*>(this);
162}
163
164bool Event::HasNativeEvent() const {
165  base::NativeEvent null_event;
166  std::memset(&null_event, 0, sizeof(null_event));
167  return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
168}
169
170void Event::StopPropagation() {
171  // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
172  // events.
173  // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
174  CHECK(cancelable_);
175  result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
176}
177
178void Event::SetHandled() {
179  // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
180  // events.
181  // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
182  CHECK(cancelable_);
183  result_ = static_cast<EventResult>(result_ | ER_HANDLED);
184}
185
186Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
187    : type_(type),
188      time_stamp_(time_stamp),
189      flags_(flags),
190      native_event_(base::NativeEvent()),
191      delete_native_event_(false),
192      cancelable_(true),
193      target_(NULL),
194      phase_(EP_PREDISPATCH),
195      result_(ER_UNHANDLED),
196      source_device_id_(ED_UNKNOWN_DEVICE) {
197  if (type_ < ET_LAST)
198    name_ = EventTypeName(type_);
199}
200
201Event::Event(const base::NativeEvent& native_event,
202             EventType type,
203             int flags)
204    : type_(type),
205      time_stamp_(EventTimeFromNative(native_event)),
206      flags_(flags),
207      native_event_(native_event),
208      delete_native_event_(false),
209      cancelable_(true),
210      target_(NULL),
211      phase_(EP_PREDISPATCH),
212      result_(ER_UNHANDLED),
213      source_device_id_(ED_UNKNOWN_DEVICE) {
214  base::TimeDelta delta = EventTimeForNow() - time_stamp_;
215  if (type_ < ET_LAST)
216    name_ = EventTypeName(type_);
217  UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser",
218                              delta.InMicroseconds(), 1, 1000000, 100);
219  std::string name_for_event =
220      base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
221  base::HistogramBase* counter_for_type =
222      base::Histogram::FactoryGet(
223          name_for_event,
224          1,
225          1000000,
226          100,
227          base::HistogramBase::kUmaTargetedHistogramFlag);
228  counter_for_type->Add(delta.InMicroseconds());
229
230#if defined(USE_X11)
231  if (native_event->type == GenericEvent) {
232    XIDeviceEvent* xiev =
233        static_cast<XIDeviceEvent*>(native_event->xcookie.data);
234    source_device_id_ = xiev->sourceid;
235  }
236#endif
237}
238
239Event::Event(const Event& copy)
240    : type_(copy.type_),
241      time_stamp_(copy.time_stamp_),
242      latency_(copy.latency_),
243      flags_(copy.flags_),
244      native_event_(CopyNativeEvent(copy.native_event_)),
245      delete_native_event_(true),
246      cancelable_(true),
247      target_(NULL),
248      phase_(EP_PREDISPATCH),
249      result_(ER_UNHANDLED),
250      source_device_id_(copy.source_device_id_) {
251  if (type_ < ET_LAST)
252    name_ = EventTypeName(type_);
253}
254
255void Event::SetType(EventType type) {
256  if (type_ < ET_LAST)
257    name_ = std::string();
258  type_ = type;
259  if (type_ < ET_LAST)
260    name_ = EventTypeName(type_);
261}
262
263////////////////////////////////////////////////////////////////////////////////
264// CancelModeEvent
265
266CancelModeEvent::CancelModeEvent()
267    : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
268  set_cancelable(false);
269}
270
271CancelModeEvent::~CancelModeEvent() {
272}
273
274////////////////////////////////////////////////////////////////////////////////
275// LocatedEvent
276
277LocatedEvent::~LocatedEvent() {
278}
279
280LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
281    : Event(native_event,
282            EventTypeFromNative(native_event),
283            EventFlagsFromNative(native_event)),
284      location_(EventLocationFromNative(native_event)),
285      root_location_(location_) {
286}
287
288LocatedEvent::LocatedEvent(EventType type,
289                           const gfx::PointF& location,
290                           const gfx::PointF& root_location,
291                           base::TimeDelta time_stamp,
292                           int flags)
293    : Event(type, time_stamp, flags),
294      location_(location),
295      root_location_(root_location) {
296}
297
298void LocatedEvent::UpdateForRootTransform(
299    const gfx::Transform& reversed_root_transform) {
300  // Transform has to be done at root level.
301  gfx::Point3F p(location_);
302  reversed_root_transform.TransformPoint(&p);
303  location_ = p.AsPointF();
304  root_location_ = location_;
305}
306
307////////////////////////////////////////////////////////////////////////////////
308// MouseEvent
309
310MouseEvent::MouseEvent(const base::NativeEvent& native_event)
311    : LocatedEvent(native_event),
312      changed_button_flags_(
313          GetChangedMouseButtonFlagsFromNative(native_event)) {
314  if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED)
315    SetClickCount(GetRepeatCount(*this));
316}
317
318MouseEvent::MouseEvent(EventType type,
319                       const gfx::PointF& location,
320                       const gfx::PointF& root_location,
321                       int flags,
322                       int changed_button_flags)
323    : LocatedEvent(type, location, root_location, EventTimeForNow(), flags),
324      changed_button_flags_(changed_button_flags) {
325  if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
326    SetType(ET_MOUSE_DRAGGED);
327}
328
329// static
330bool MouseEvent::IsRepeatedClickEvent(
331    const MouseEvent& event1,
332    const MouseEvent& event2) {
333  // These values match the Windows defaults.
334  static const int kDoubleClickTimeMS = 500;
335  static const int kDoubleClickWidth = 4;
336  static const int kDoubleClickHeight = 4;
337
338  if (event1.type() != ET_MOUSE_PRESSED ||
339      event2.type() != ET_MOUSE_PRESSED)
340    return false;
341
342  // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
343  if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
344      (event2.flags() & ~EF_IS_DOUBLE_CLICK))
345    return false;
346
347  base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
348
349  if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
350    return false;
351
352  if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
353    return false;
354
355  if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
356    return false;
357
358  return true;
359}
360
361// static
362int MouseEvent::GetRepeatCount(const MouseEvent& event) {
363  int click_count = 1;
364  if (last_click_event_) {
365    if (event.type() == ui::ET_MOUSE_RELEASED) {
366      if (event.changed_button_flags() ==
367              last_click_event_->changed_button_flags()) {
368        last_click_complete_ = true;
369        return last_click_event_->GetClickCount();
370      } else {
371        // If last_click_event_ has changed since this button was pressed
372        // return a click count of 1.
373        return click_count;
374      }
375    }
376    if (event.time_stamp() != last_click_event_->time_stamp())
377      last_click_complete_ = true;
378    if (!last_click_complete_ ||
379        IsX11SendEventTrue(event.native_event())) {
380      click_count = last_click_event_->GetClickCount();
381    } else if (IsRepeatedClickEvent(*last_click_event_, event)) {
382      click_count = last_click_event_->GetClickCount() + 1;
383    }
384    delete last_click_event_;
385  }
386  last_click_event_ = new MouseEvent(event);
387  last_click_complete_ = false;
388  if (click_count > 3)
389    click_count = 3;
390  last_click_event_->SetClickCount(click_count);
391  return click_count;
392}
393
394void MouseEvent::ResetLastClickForTest() {
395  if (last_click_event_) {
396    delete last_click_event_;
397    last_click_event_ = NULL;
398    last_click_complete_ = false;
399  }
400}
401
402// static
403MouseEvent* MouseEvent::last_click_event_ = NULL;
404bool MouseEvent::last_click_complete_ = false;
405
406int MouseEvent::GetClickCount() const {
407  if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
408    return 0;
409
410  if (flags() & EF_IS_TRIPLE_CLICK)
411    return 3;
412  else if (flags() & EF_IS_DOUBLE_CLICK)
413    return 2;
414  else
415    return 1;
416}
417
418void MouseEvent::SetClickCount(int click_count) {
419  if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
420    return;
421
422  DCHECK(click_count > 0);
423  DCHECK(click_count <= 3);
424
425  int f = flags();
426  switch (click_count) {
427    case 1:
428      f &= ~EF_IS_DOUBLE_CLICK;
429      f &= ~EF_IS_TRIPLE_CLICK;
430      break;
431    case 2:
432      f |= EF_IS_DOUBLE_CLICK;
433      f &= ~EF_IS_TRIPLE_CLICK;
434      break;
435    case 3:
436      f &= ~EF_IS_DOUBLE_CLICK;
437      f |= EF_IS_TRIPLE_CLICK;
438      break;
439  }
440  set_flags(f);
441}
442
443////////////////////////////////////////////////////////////////////////////////
444// MouseWheelEvent
445
446MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
447    : MouseEvent(native_event),
448      offset_(GetMouseWheelOffset(native_event)) {
449}
450
451MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
452    : MouseEvent(scroll_event),
453      offset_(scroll_event.x_offset(), scroll_event.y_offset()){
454  SetType(ET_MOUSEWHEEL);
455}
456
457MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
458                                 int x_offset,
459                                 int y_offset)
460    : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
461  DCHECK(type() == ET_MOUSEWHEEL);
462}
463
464MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
465    : MouseEvent(mouse_wheel_event),
466      offset_(mouse_wheel_event.offset()) {
467  DCHECK(type() == ET_MOUSEWHEEL);
468}
469
470MouseWheelEvent::MouseWheelEvent(const gfx::Vector2d& offset,
471                                 const gfx::PointF& location,
472                                 const gfx::PointF& root_location,
473                                 int flags,
474                                 int changed_button_flags)
475    : MouseEvent(ui::ET_MOUSEWHEEL, location, root_location, flags,
476                 changed_button_flags),
477      offset_(offset) {
478}
479
480#if defined(OS_WIN)
481// This value matches windows WHEEL_DELTA.
482// static
483const int MouseWheelEvent::kWheelDelta = 120;
484#else
485// This value matches GTK+ wheel scroll amount.
486const int MouseWheelEvent::kWheelDelta = 53;
487#endif
488
489void MouseWheelEvent::UpdateForRootTransform(
490    const gfx::Transform& inverted_root_transform) {
491  LocatedEvent::UpdateForRootTransform(inverted_root_transform);
492  gfx::DecomposedTransform decomp;
493  bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
494  DCHECK(success);
495  if (decomp.scale[0])
496    offset_.set_x(offset_.x() * decomp.scale[0]);
497  if (decomp.scale[1])
498    offset_.set_y(offset_.y() * decomp.scale[1]);
499}
500
501////////////////////////////////////////////////////////////////////////////////
502// TouchEvent
503
504TouchEvent::TouchEvent(const base::NativeEvent& native_event)
505    : LocatedEvent(native_event),
506      touch_id_(GetTouchId(native_event)),
507      radius_x_(GetTouchRadiusX(native_event)),
508      radius_y_(GetTouchRadiusY(native_event)),
509      rotation_angle_(GetTouchAngle(native_event)),
510      force_(GetTouchForce(native_event)) {
511  latency()->AddLatencyNumberWithTimestamp(
512      INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
513      0,
514      0,
515      base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
516      1);
517
518  latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
519
520  if (type() == ET_TOUCH_PRESSED)
521    IncrementTouchIdRefCount(native_event);
522}
523
524TouchEvent::TouchEvent(EventType type,
525                       const gfx::PointF& location,
526                       int touch_id,
527                       base::TimeDelta time_stamp)
528    : LocatedEvent(type, location, location, time_stamp, 0),
529      touch_id_(touch_id),
530      radius_x_(0.0f),
531      radius_y_(0.0f),
532      rotation_angle_(0.0f),
533      force_(0.0f) {
534  latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
535}
536
537TouchEvent::TouchEvent(EventType type,
538                       const gfx::PointF& location,
539                       int flags,
540                       int touch_id,
541                       base::TimeDelta time_stamp,
542                       float radius_x,
543                       float radius_y,
544                       float angle,
545                       float force)
546    : LocatedEvent(type, location, location, time_stamp, flags),
547      touch_id_(touch_id),
548      radius_x_(radius_x),
549      radius_y_(radius_y),
550      rotation_angle_(angle),
551      force_(force) {
552  latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
553}
554
555TouchEvent::~TouchEvent() {
556  // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
557  // platform setups the tracking_id to slot mapping. So in dtor here,
558  // if this touch event is a release event, we clear the mapping accordingly.
559  if (HasNativeEvent())
560    ClearTouchIdIfReleased(native_event());
561}
562
563void TouchEvent::UpdateForRootTransform(
564    const gfx::Transform& inverted_root_transform) {
565  LocatedEvent::UpdateForRootTransform(inverted_root_transform);
566  gfx::DecomposedTransform decomp;
567  bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
568  DCHECK(success);
569  if (decomp.scale[0])
570    radius_x_ *= decomp.scale[0];
571  if (decomp.scale[1])
572    radius_y_ *= decomp.scale[1];
573}
574
575////////////////////////////////////////////////////////////////////////////////
576// KeyEvent
577
578// static
579KeyEvent* KeyEvent::last_key_event_ = NULL;
580
581// static
582bool KeyEvent::IsRepeated(const KeyEvent& event) {
583  // A safe guard in case if there were continous key pressed events that are
584  // not auto repeat.
585  const int kMaxAutoRepeatTimeMs = 2000;
586  // Ignore key events that have non standard state masks as it may be
587  // reposted by an IME. IBUS-GTK uses this field to detect the
588  // re-posted event for example. crbug.com/385873.
589  if (X11EventHasNonStandardState(event.native_event()))
590    return false;
591  if (event.is_char())
592    return false;
593  if (event.type() == ui::ET_KEY_RELEASED) {
594    delete last_key_event_;
595    last_key_event_ = NULL;
596    return false;
597  }
598  CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
599  if (!last_key_event_) {
600    last_key_event_ = new KeyEvent(event);
601    return false;
602  }
603  if (event.key_code() == last_key_event_->key_code() &&
604      event.flags() == last_key_event_->flags() &&
605      (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() <
606      kMaxAutoRepeatTimeMs) {
607    return true;
608  }
609  delete last_key_event_;
610  last_key_event_ = new KeyEvent(event);
611  return false;
612}
613
614KeyEvent::KeyEvent(const base::NativeEvent& native_event)
615    : Event(native_event,
616            EventTypeFromNative(native_event),
617            EventFlagsFromNative(native_event)),
618      key_code_(KeyboardCodeFromNative(native_event)),
619      code_(CodeFromNative(native_event)),
620      is_char_(IsCharFromNative(native_event)),
621      platform_keycode_(PlatformKeycodeFromNative(native_event)),
622      character_(0) {
623  if (IsRepeated(*this))
624    set_flags(flags() | ui::EF_IS_REPEAT);
625
626#if defined(USE_X11)
627  NormalizeFlags();
628#endif
629#if defined(OS_WIN)
630  // Only Windows has native character events.
631  if (is_char_)
632    character_ = native_event.wParam;
633#endif
634}
635
636KeyEvent::KeyEvent(EventType type,
637                   KeyboardCode key_code,
638                   int flags)
639    : Event(type, EventTimeForNow(), flags),
640      key_code_(key_code),
641      is_char_(false),
642      platform_keycode_(0),
643      character_() {
644}
645
646KeyEvent::KeyEvent(EventType type,
647                   KeyboardCode key_code,
648                   const std::string& code,
649                   int flags)
650    : Event(type, EventTimeForNow(), flags),
651      key_code_(key_code),
652      code_(code),
653      is_char_(false),
654      platform_keycode_(0),
655      character_(0) {
656}
657
658KeyEvent::KeyEvent(base::char16 character, KeyboardCode key_code, int flags)
659    : Event(ET_KEY_PRESSED, EventTimeForNow(), flags),
660      key_code_(key_code),
661      code_(""),
662      is_char_(true),
663      platform_keycode_(0),
664      character_(character) {
665}
666
667KeyEvent::KeyEvent(const KeyEvent& rhs)
668    : Event(rhs),
669      key_code_(rhs.key_code_),
670      code_(rhs.code_),
671      is_char_(rhs.is_char_),
672      platform_keycode_(rhs.platform_keycode_),
673      character_(rhs.character_) {
674  if (rhs.extended_key_event_data_)
675    extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
676}
677
678KeyEvent& KeyEvent::operator=(const KeyEvent& rhs) {
679  if (this != &rhs) {
680    Event::operator=(rhs);
681    key_code_ = rhs.key_code_;
682    code_ = rhs.code_;
683    is_char_ = rhs.is_char_;
684    platform_keycode_ = rhs.platform_keycode_;
685    character_ = rhs.character_;
686
687    if (rhs.extended_key_event_data_)
688      extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
689  }
690  return *this;
691}
692
693KeyEvent::~KeyEvent() {}
694
695void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) {
696  extended_key_event_data_ = data.Pass();
697}
698
699base::char16 KeyEvent::GetCharacter() const {
700  if (is_char_ || character_)
701    return character_;
702
703  // TODO(kpschoedel): streamline these cases after settling Ozone
704  // positional coding.
705#if defined(OS_WIN)
706  // Native Windows character events always have is_char_ == true,
707  // so this is a synthetic or native keystroke event.
708  character_ = GetCharacterFromKeyCode(key_code_, flags());
709  return character_;
710#elif defined(USE_X11)
711  if (!native_event()) {
712    character_ = GetCharacterFromKeyCode(key_code_, flags());
713    return character_;
714  }
715
716  DCHECK(native_event()->type == KeyPress ||
717         native_event()->type == KeyRelease ||
718         (native_event()->type == GenericEvent &&
719          (native_event()->xgeneric.evtype == XI_KeyPress ||
720           native_event()->xgeneric.evtype == XI_KeyRelease)));
721
722  // When a control key is held, prefer ASCII characters to non ASCII
723  // characters in order to use it for shortcut keys.  GetCharacterFromKeyCode
724  // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
725  // GetCharacterFromXEvent returns 'à' in that case.
726  return IsControlDown() ?
727      GetCharacterFromKeyCode(key_code_, flags()) :
728      GetCharacterFromXEvent(native_event());
729#else
730  if (native_event()) {
731    DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
732           EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
733  }
734
735  return GetCharacterFromKeyCode(key_code_, flags());
736#endif
737}
738
739base::char16 KeyEvent::GetText() const {
740  if ((flags() & EF_CONTROL_DOWN) != 0) {
741    return GetControlCharacterForKeycode(key_code_,
742                                         (flags() & EF_SHIFT_DOWN) != 0);
743  }
744  return GetUnmodifiedText();
745}
746
747base::char16 KeyEvent::GetUnmodifiedText() const {
748  if (!is_char_ && (key_code_ == VKEY_RETURN))
749    return '\r';
750  return GetCharacter();
751}
752
753bool KeyEvent::IsUnicodeKeyCode() const {
754#if defined(OS_WIN)
755  if (!IsAltDown())
756    return false;
757  const int key = key_code();
758  if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
759    return true;
760  // Check whether the user is using the numeric keypad with num-lock off.
761  // In that case, EF_EXTENDED will not be set; if it is set, the key event
762  // originated from the relevant non-numpad dedicated key, e.g. [Insert].
763  return (!(flags() & EF_EXTENDED) &&
764          (key == VKEY_INSERT || key == VKEY_END  || key == VKEY_DOWN ||
765           key == VKEY_NEXT   || key == VKEY_LEFT || key == VKEY_CLEAR ||
766           key == VKEY_RIGHT  || key == VKEY_HOME || key == VKEY_UP ||
767           key == VKEY_PRIOR));
768#else
769  return false;
770#endif
771}
772
773void KeyEvent::NormalizeFlags() {
774  int mask = 0;
775  switch (key_code()) {
776    case VKEY_CONTROL:
777      mask = EF_CONTROL_DOWN;
778      break;
779    case VKEY_SHIFT:
780      mask = EF_SHIFT_DOWN;
781      break;
782    case VKEY_MENU:
783      mask = EF_ALT_DOWN;
784      break;
785    case VKEY_CAPITAL:
786      mask = EF_CAPS_LOCK_DOWN;
787      break;
788    default:
789      return;
790  }
791  if (type() == ET_KEY_PRESSED)
792    set_flags(flags() | mask);
793  else
794    set_flags(flags() & ~mask);
795}
796
797bool KeyEvent::IsTranslated() const {
798  switch (type()) {
799    case ET_KEY_PRESSED:
800    case ET_KEY_RELEASED:
801      return false;
802    case ET_TRANSLATED_KEY_PRESS:
803    case ET_TRANSLATED_KEY_RELEASE:
804      return true;
805    default:
806      NOTREACHED();
807      return false;
808  }
809}
810
811void KeyEvent::SetTranslated(bool translated) {
812  switch (type()) {
813    case ET_KEY_PRESSED:
814    case ET_TRANSLATED_KEY_PRESS:
815      SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED);
816      break;
817    case ET_KEY_RELEASED:
818    case ET_TRANSLATED_KEY_RELEASE:
819      SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED);
820      break;
821    default:
822      NOTREACHED();
823  }
824}
825
826bool KeyEvent::IsRightSideKey() const {
827  switch (key_code_) {
828    case VKEY_CONTROL:
829    case VKEY_SHIFT:
830    case VKEY_MENU:
831    case VKEY_LWIN:
832#if defined(USE_X11)
833      // Under X11, setting code_ requires platform-dependent information, and
834      // currently assumes that X keycodes are based on Linux evdev keycodes.
835      // In certain test environments this is not the case, and code_ is not
836      // set accurately, so we need a different mechanism. Fortunately X11 key
837      // mapping preserves the left-right distinction, so testing keysyms works
838      // if the value is available (as it is for all X11 native-based events).
839      if (platform_keycode_) {
840        return (platform_keycode_ == XK_Shift_R) ||
841               (platform_keycode_ == XK_Control_R) ||
842               (platform_keycode_ == XK_Alt_R) ||
843               (platform_keycode_ == XK_Meta_R) ||
844               (platform_keycode_ == XK_Super_R) ||
845               (platform_keycode_ == XK_Hyper_R);
846      }
847      // Fall through to the generic code if we have no platform_keycode_.
848      // Under X11, this must be a synthetic event, so we can require that
849      // code_ be set correctly.
850#endif
851      return ((code_.size() > 5) &&
852              (code_.compare(code_.size() - 5, 5, "Right", 5)) == 0);
853    default:
854      return false;
855  }
856}
857
858KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
859  switch (key_code_) {
860    case VKEY_SHIFT:
861      return IsRightSideKey() ? VKEY_RSHIFT : VKEY_LSHIFT;
862    case VKEY_CONTROL:
863      return IsRightSideKey() ? VKEY_RCONTROL : VKEY_LCONTROL;
864    case VKEY_MENU:
865      return IsRightSideKey() ? VKEY_RMENU : VKEY_LMENU;
866    case VKEY_LWIN:
867      return IsRightSideKey() ? VKEY_RWIN : VKEY_LWIN;
868    // TODO(kpschoedel): EF_NUMPAD_KEY is present only on X11. Currently this
869    // function is only called on X11. Likely the tests here will be replaced
870    // with a DOM-based code enumeration test in the course of Ozone
871    // platform-indpendent key event work.
872    case VKEY_0:
873      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD0 : VKEY_0;
874    case VKEY_1:
875      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD1 : VKEY_1;
876    case VKEY_2:
877      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD2 : VKEY_2;
878    case VKEY_3:
879      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD3 : VKEY_3;
880    case VKEY_4:
881      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD4 : VKEY_4;
882    case VKEY_5:
883      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD5 : VKEY_5;
884    case VKEY_6:
885      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD6 : VKEY_6;
886    case VKEY_7:
887      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD7 : VKEY_7;
888    case VKEY_8:
889      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD8 : VKEY_8;
890    case VKEY_9:
891      return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD9 : VKEY_9;
892    default:
893      return key_code_;
894  }
895}
896
897uint16 KeyEvent::GetConflatedWindowsKeyCode() const {
898  if (is_char_)
899    return character_;
900  return key_code_;
901}
902
903////////////////////////////////////////////////////////////////////////////////
904// ScrollEvent
905
906ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
907    : MouseEvent(native_event) {
908  if (type() == ET_SCROLL) {
909    GetScrollOffsets(native_event,
910                     &x_offset_, &y_offset_,
911                     &x_offset_ordinal_, &y_offset_ordinal_,
912                     &finger_count_);
913  } else if (type() == ET_SCROLL_FLING_START ||
914             type() == ET_SCROLL_FLING_CANCEL) {
915    GetFlingData(native_event,
916                 &x_offset_, &y_offset_,
917                 &x_offset_ordinal_, &y_offset_ordinal_,
918                 NULL);
919  } else {
920    NOTREACHED() << "Unexpected event type " << type()
921        << " when constructing a ScrollEvent.";
922  }
923}
924
925ScrollEvent::ScrollEvent(EventType type,
926                         const gfx::PointF& location,
927                         base::TimeDelta time_stamp,
928                         int flags,
929                         float x_offset,
930                         float y_offset,
931                         float x_offset_ordinal,
932                         float y_offset_ordinal,
933                         int finger_count)
934    : MouseEvent(type, location, location, flags, 0),
935      x_offset_(x_offset),
936      y_offset_(y_offset),
937      x_offset_ordinal_(x_offset_ordinal),
938      y_offset_ordinal_(y_offset_ordinal),
939      finger_count_(finger_count) {
940  set_time_stamp(time_stamp);
941  CHECK(IsScrollEvent());
942}
943
944void ScrollEvent::Scale(const float factor) {
945  x_offset_ *= factor;
946  y_offset_ *= factor;
947  x_offset_ordinal_ *= factor;
948  y_offset_ordinal_ *= factor;
949}
950
951////////////////////////////////////////////////////////////////////////////////
952// GestureEvent
953
954GestureEvent::GestureEvent(float x,
955                           float y,
956                           int flags,
957                           base::TimeDelta time_stamp,
958                           const GestureEventDetails& details)
959    : LocatedEvent(details.type(),
960                   gfx::PointF(x, y),
961                   gfx::PointF(x, y),
962                   time_stamp,
963                   flags | EF_FROM_TOUCH),
964      details_(details) {
965}
966
967GestureEvent::~GestureEvent() {
968}
969
970}  // namespace ui
971