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"
8 #include <X11/extensions/XInput2.h>
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"
25 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
26 #elif defined(USE_OZONE)
27 #include "ui/events/keycodes/keyboard_code_conversion.h"
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
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);
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.
87 bool IsX11SendEventTrue(const base::NativeEvent& event) {
89 return event && event->xany.send_event;
95 bool X11EventHasNonStandardState(const base::NativeEvent& event) {
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;
111 ////////////////////////////////////////////////////////////////////////////////
115 if (delete_native_event_)
116 ReleaseCopiedNativeEvent(native_event_);
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));
125 void Event::StopPropagation() {
126 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
128 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
130 result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
133 void Event::SetHandled() {
134 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
136 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
138 result_ = static_cast<EventResult>(result_ | ER_HANDLED);
141 Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
143 time_stamp_(time_stamp),
145 native_event_(base::NativeEvent()),
146 delete_native_event_(false),
149 phase_(EP_PREDISPATCH),
150 result_(ER_UNHANDLED) {
152 name_ = EventTypeName(type_);
155 Event::Event(const base::NativeEvent& native_event,
159 time_stamp_(EventTimeFromNative(native_event)),
161 native_event_(native_event),
162 delete_native_event_(false),
165 phase_(EP_PREDISPATCH),
166 result_(ER_UNHANDLED) {
167 base::TimeDelta delta = EventTimeForNow() - time_stamp_;
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(
180 base::HistogramBase::kUmaTargetedHistogramFlag);
181 counter_for_type->Add(delta.InMicroseconds());
184 Event::Event(const Event& copy)
186 time_stamp_(copy.time_stamp_),
187 latency_(copy.latency_),
189 native_event_(CopyNativeEvent(copy.native_event_)),
190 delete_native_event_(true),
193 phase_(EP_PREDISPATCH),
194 result_(ER_UNHANDLED) {
196 name_ = EventTypeName(type_);
199 void Event::SetType(EventType type) {
201 name_ = std::string();
204 name_ = EventTypeName(type_);
207 ////////////////////////////////////////////////////////////////////////////////
210 CancelModeEvent::CancelModeEvent()
211 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
212 set_cancelable(false);
215 CancelModeEvent::~CancelModeEvent() {
218 ////////////////////////////////////////////////////////////////////////////////
221 LocatedEvent::~LocatedEvent() {
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_) {
232 LocatedEvent::LocatedEvent(EventType type,
233 const gfx::PointF& location,
234 const gfx::PointF& root_location,
235 base::TimeDelta time_stamp,
237 : Event(type, time_stamp, flags),
239 root_location_(root_location) {
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_;
251 ////////////////////////////////////////////////////////////////////////////////
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));
262 MouseEvent::MouseEvent(EventType type,
263 const gfx::PointF& location,
264 const gfx::PointF& root_location,
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);
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;
282 if (event1.type() != ET_MOUSE_PRESSED ||
283 event2.type() != ET_MOUSE_PRESSED)
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))
291 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
293 if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
296 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
299 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
306 int MouseEvent::GetRepeatCount(const MouseEvent& event) {
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();
315 // If last_click_event_ has changed since this button was pressed
316 // return a click count of 1.
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;
328 delete last_click_event_;
330 last_click_event_ = new MouseEvent(event);
331 last_click_complete_ = false;
334 last_click_event_->SetClickCount(click_count);
338 void MouseEvent::ResetLastClickForTest() {
339 if (last_click_event_) {
340 delete last_click_event_;
341 last_click_event_ = NULL;
342 last_click_complete_ = false;
347 MouseEvent* MouseEvent::last_click_event_ = NULL;
348 bool MouseEvent::last_click_complete_ = false;
350 int MouseEvent::GetClickCount() const {
351 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
354 if (flags() & EF_IS_TRIPLE_CLICK)
356 else if (flags() & EF_IS_DOUBLE_CLICK)
362 void MouseEvent::SetClickCount(int click_count) {
363 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
366 DCHECK(click_count > 0);
367 DCHECK(click_count <= 3);
370 switch (click_count) {
372 f &= ~EF_IS_DOUBLE_CLICK;
373 f &= ~EF_IS_TRIPLE_CLICK;
376 f |= EF_IS_DOUBLE_CLICK;
377 f &= ~EF_IS_TRIPLE_CLICK;
380 f &= ~EF_IS_DOUBLE_CLICK;
381 f |= EF_IS_TRIPLE_CLICK;
387 ////////////////////////////////////////////////////////////////////////////////
390 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
391 : MouseEvent(native_event),
392 offset_(GetMouseWheelOffset(native_event)) {
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);
401 MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
404 : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
405 DCHECK(type() == ET_MOUSEWHEEL);
408 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
409 : MouseEvent(mouse_wheel_event),
410 offset_(mouse_wheel_event.offset()) {
411 DCHECK(type() == ET_MOUSEWHEEL);
415 // This value matches windows WHEEL_DELTA.
417 const int MouseWheelEvent::kWheelDelta = 120;
419 // This value matches GTK+ wheel scroll amount.
420 const int MouseWheelEvent::kWheelDelta = 53;
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);
430 offset_.set_x(offset_.x() * decomp.scale[0]);
432 offset_.set_y(offset_.y() * decomp.scale[1]);
435 ////////////////////////////////////////////////////////////////////////////////
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,
450 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
454 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data);
455 source_device_id_ = xiev->deviceid;
458 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
461 TouchEvent::TouchEvent(EventType type,
462 const gfx::PointF& location,
464 base::TimeDelta time_stamp)
465 : LocatedEvent(type, location, location, time_stamp, 0),
469 rotation_angle_(0.0f),
471 source_device_id_(-1) {
472 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
475 TouchEvent::TouchEvent(EventType type,
476 const gfx::PointF& location,
479 base::TimeDelta time_stamp,
484 : LocatedEvent(type, location, location, time_stamp, flags),
488 rotation_angle_(angle),
490 source_device_id_(-1) {
491 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
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());
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);
509 radius_x_ *= decomp.scale[0];
511 radius_y_ *= decomp.scale[1];
514 ////////////////////////////////////////////////////////////////////////////////
518 KeyEvent* KeyEvent::last_key_event_ = NULL;
521 bool KeyEvent::IsRepeated(const KeyEvent& event) {
522 // A safe guard in case if there were continous key pressed events that are
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()))
532 if (event.type() == ui::ET_KEY_RELEASED) {
533 delete last_key_event_;
534 last_key_event_ = NULL;
537 CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
538 if (!last_key_event_) {
539 last_key_event_ = new KeyEvent(event);
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) {
548 delete last_key_event_;
549 last_key_event_ = new KeyEvent(event);
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)),
560 platform_keycode_(PlatformKeycodeFromNative(native_event)),
562 if (IsRepeated(*this))
563 set_flags(flags() | ui::EF_IS_REPEAT);
570 KeyEvent::KeyEvent(EventType type,
571 KeyboardCode key_code,
574 : Event(type, EventTimeForNow(), flags),
577 platform_keycode_(0),
578 character_(GetCharacterFromKeyCode(key_code, flags)) {
581 KeyEvent::KeyEvent(EventType type,
582 KeyboardCode key_code,
583 const std::string& code,
586 : Event(type, EventTimeForNow(), flags),
590 platform_keycode_(0),
591 character_(GetCharacterFromKeyCode(key_code, flags)) {
594 uint16 KeyEvent::GetCharacter() const {
599 return (native_event().message == WM_CHAR) ? key_code_ :
600 GetCharacterFromKeyCode(key_code_, flags());
601 #elif defined(USE_X11)
603 return GetCharacterFromKeyCode(key_code_, flags());
605 DCHECK(native_event()->type == KeyPress ||
606 native_event()->type == KeyRelease);
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());
616 if (native_event()) {
617 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
618 EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
621 return GetCharacterFromKeyCode(key_code_, flags());
625 bool KeyEvent::IsUnicodeKeyCode() const {
629 const int key = key_code();
630 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
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 ||
645 void KeyEvent::NormalizeFlags() {
647 switch (key_code()) {
649 mask = EF_CONTROL_DOWN;
652 mask = EF_SHIFT_DOWN;
658 mask = EF_CAPS_LOCK_DOWN;
663 if (type() == ET_KEY_PRESSED)
664 set_flags(flags() | mask);
666 set_flags(flags() & ~mask);
669 bool KeyEvent::IsTranslated() const {
672 case ET_KEY_RELEASED:
674 case ET_TRANSLATED_KEY_PRESS:
675 case ET_TRANSLATED_KEY_RELEASE:
683 void KeyEvent::SetTranslated(bool translated) {
686 case ET_TRANSLATED_KEY_PRESS:
687 SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED);
689 case ET_KEY_RELEASED:
690 case ET_TRANSLATED_KEY_RELEASE:
691 SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED);
698 ////////////////////////////////////////////////////////////////////////////////
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_,
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_,
715 NOTREACHED() << "Unexpected event type " << type()
716 << " when constructing a ScrollEvent.";
720 ScrollEvent::ScrollEvent(EventType type,
721 const gfx::PointF& location,
722 base::TimeDelta time_stamp,
726 float x_offset_ordinal,
727 float y_offset_ordinal,
729 : MouseEvent(type, location, location, flags, 0),
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());
739 void ScrollEvent::Scale(const float factor) {
742 x_offset_ordinal_ *= factor;
743 y_offset_ordinal_ *= factor;
746 ////////////////////////////////////////////////////////////////////////////////
749 GestureEvent::GestureEvent(EventType type,
753 base::TimeDelta time_stamp,
754 const GestureEventDetails& details,
755 unsigned int touch_ids_bitfield)
760 flags | EF_FROM_TOUCH),
762 touch_ids_bitfield_(touch_ids_bitfield) {
765 GestureEvent::~GestureEvent() {
768 int GestureEvent::GetLowestTouchId() const {
769 if (touch_ids_bitfield_ == 0)
772 // Find the index of the least significant 1 bit
773 while (!(1 << ++i & touch_ids_bitfield_));