Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / ui / events / event.cc
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
30 namespace {
31
32 std::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
87 bool 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
95 bool 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
109 namespace ui {
110
111 ////////////////////////////////////////////////////////////////////////////////
112 // Event
113
114 Event::~Event() {
115   if (delete_native_event_)
116     ReleaseCopiedNativeEvent(native_event_);
117 }
118
119 bool 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
125 void 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
133 void 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
141 Event::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
155 Event::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
184 Event::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
199 void 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
210 CancelModeEvent::CancelModeEvent()
211     : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
212   set_cancelable(false);
213 }
214
215 CancelModeEvent::~CancelModeEvent() {
216 }
217
218 ////////////////////////////////////////////////////////////////////////////////
219 // LocatedEvent
220
221 LocatedEvent::~LocatedEvent() {
222 }
223
224 LocatedEvent::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
232 LocatedEvent::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
242 void 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
254 MouseEvent::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
262 MouseEvent::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
274 bool 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
306 int 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
338 void 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
347 MouseEvent* MouseEvent::last_click_event_ = NULL;
348 bool MouseEvent::last_click_complete_ = false;
349
350 int 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
362 void 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
390 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
391     : MouseEvent(native_event),
392       offset_(GetMouseWheelOffset(native_event)) {
393 }
394
395 MouseWheelEvent::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
401 MouseWheelEvent::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
408 MouseWheelEvent::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
417 const int MouseWheelEvent::kWheelDelta = 120;
418 #else
419 // This value matches GTK+ wheel scroll amount.
420 const int MouseWheelEvent::kWheelDelta = 53;
421 #endif
422
423 void 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
438 TouchEvent::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
461 TouchEvent::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
475 TouchEvent::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
494 TouchEvent::~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
502 void 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
518 KeyEvent* KeyEvent::last_key_event_ = NULL;
519
520 // static
521 bool 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
553 KeyEvent::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
570 KeyEvent::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
581 KeyEvent::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
594 uint16 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
625 bool 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
645 void 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
669 bool 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
683 void 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
701 ScrollEvent::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
720 ScrollEvent::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
739 void 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
749 GestureEvent::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
765 GestureEvent::~GestureEvent() {
766 }
767
768 int 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