Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / events / event.cc
blob27de2a96b6a150891a4632df87890562f06a4eb0
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.
5 #include "ui/events/event.h"
7 #if defined(USE_X11)
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
10 #endif
12 #include <cmath>
13 #include <cstring>
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"
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
30 namespace {
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.
81 #undef CASE_TYPE
83 NOTREACHED();
84 return std::string();
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
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
107 } // namespace
109 namespace ui {
111 ////////////////////////////////////////////////////////////////////////////////
112 // Event
114 Event::~Event() {
115 if (delete_native_event_)
116 ReleaseCopiedNativeEvent(native_event_);
119 GestureEvent* Event::AsGestureEvent() {
120 CHECK(IsGestureEvent());
121 return static_cast<GestureEvent*>(this);
124 const GestureEvent* Event::AsGestureEvent() const {
125 CHECK(IsGestureEvent());
126 return static_cast<const GestureEvent*>(this);
129 bool 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));
135 void 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);
143 void 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);
151 Event::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_);
166 Event::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,
190 1000000,
191 100,
192 base::HistogramBase::kUmaTargetedHistogramFlag);
193 counter_for_type->Add(delta.InMicroseconds());
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;
201 #endif
204 Event::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_);
220 void 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_);
228 ////////////////////////////////////////////////////////////////////////////////
229 // CancelModeEvent
231 CancelModeEvent::CancelModeEvent()
232 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
233 set_cancelable(false);
236 CancelModeEvent::~CancelModeEvent() {
239 ////////////////////////////////////////////////////////////////////////////////
240 // LocatedEvent
242 LocatedEvent::~LocatedEvent() {
245 LocatedEvent::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_) {
253 LocatedEvent::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) {
263 void 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_;
272 ////////////////////////////////////////////////////////////////////////////////
273 // MouseEvent
275 MouseEvent::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));
283 MouseEvent::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);
294 // static
295 bool 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;
303 if (event1.type() != ET_MOUSE_PRESSED ||
304 event2.type() != ET_MOUSE_PRESSED)
305 return false;
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;
312 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
314 if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
315 return false;
317 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
318 return false;
320 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
321 return false;
323 return true;
326 // static
327 int 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;
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;
349 delete last_click_event_;
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;
359 void MouseEvent::ResetLastClickForTest() {
360 if (last_click_event_) {
361 delete last_click_event_;
362 last_click_event_ = NULL;
363 last_click_complete_ = false;
367 // static
368 MouseEvent* MouseEvent::last_click_event_ = NULL;
369 bool MouseEvent::last_click_complete_ = false;
371 int MouseEvent::GetClickCount() const {
372 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
373 return 0;
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;
383 void MouseEvent::SetClickCount(int click_count) {
384 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
385 return;
387 DCHECK(click_count > 0);
388 DCHECK(click_count <= 3);
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;
405 set_flags(f);
408 ////////////////////////////////////////////////////////////////////////////////
409 // MouseWheelEvent
411 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
412 : MouseEvent(native_event),
413 offset_(GetMouseWheelOffset(native_event)) {
416 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
417 : MouseEvent(scroll_event),
418 offset_(scroll_event.x_offset(), scroll_event.y_offset()){
419 SetType(ET_MOUSEWHEEL);
422 MouseWheelEvent::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);
429 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
430 : MouseEvent(mouse_wheel_event),
431 offset_(mouse_wheel_event.offset()) {
432 DCHECK(type() == ET_MOUSEWHEEL);
435 MouseWheelEvent::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) {
445 #if defined(OS_WIN)
446 // This value matches windows WHEEL_DELTA.
447 // static
448 const int MouseWheelEvent::kWheelDelta = 120;
449 #else
450 // This value matches GTK+ wheel scroll amount.
451 const int MouseWheelEvent::kWheelDelta = 53;
452 #endif
454 void 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]);
466 ////////////////////////////////////////////////////////////////////////////////
467 // TouchEvent
469 TouchEvent::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,
480 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
483 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
485 if (type() == ET_TOUCH_PRESSED)
486 IncrementTouchIdRefCount(native_event);
489 TouchEvent::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);
502 TouchEvent::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);
520 TouchEvent::~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());
528 void 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];
540 ////////////////////////////////////////////////////////////////////////////////
541 // KeyEvent
543 // static
544 KeyEvent* KeyEvent::last_key_event_ = NULL;
546 // static
547 bool 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;
563 CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
564 if (!last_key_event_) {
565 last_key_event_ = new KeyEvent(event);
566 return false;
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;
574 delete last_key_event_;
575 last_key_event_ = new KeyEvent(event);
576 return false;
579 KeyEvent::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);
591 #if defined(USE_X11)
592 NormalizeFlags();
593 #endif
596 KeyEvent::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)) {
606 KeyEvent::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)) {
618 KeyEvent::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) {
627 KeyEvent::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());
638 KeyEvent& 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_;
647 if (rhs.extended_key_event_data_)
648 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
650 return *this;
653 KeyEvent::~KeyEvent() {}
655 void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) {
656 extended_key_event_data_ = data.Pass();
659 base::char16 KeyEvent::GetCharacter() const {
660 if (character_)
661 return character_;
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());
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)));
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);
689 return GetCharacterFromKeyCode(key_code_, flags());
690 #endif
693 bool 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
713 void 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;
731 if (type() == ET_KEY_PRESSED)
732 set_flags(flags() | mask);
733 else
734 set_flags(flags() & ~mask);
737 bool 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;
751 void 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();
766 ////////////////////////////////////////////////////////////////////////////////
767 // ScrollEvent
769 ScrollEvent::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.";
788 ScrollEvent::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());
807 void ScrollEvent::Scale(const float factor) {
808 x_offset_ *= factor;
809 y_offset_ *= factor;
810 x_offset_ordinal_ *= factor;
811 y_offset_ordinal_ *= factor;
814 ////////////////////////////////////////////////////////////////////////////////
815 // GestureEvent
817 GestureEvent::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) {
830 GestureEvent::~GestureEvent() {
833 } // namespace ui