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_MULTIFINGER_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 if (event && event->xany.send_event)
99 ////////////////////////////////////////////////////////////////////////////////
103 if (delete_native_event_)
104 ReleaseCopiedNativeEvent(native_event_);
107 bool Event::HasNativeEvent() const {
108 base::NativeEvent null_event;
109 std::memset(&null_event, 0, sizeof(null_event));
110 return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
113 void Event::StopPropagation() {
114 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
116 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
118 result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
121 void Event::SetHandled() {
122 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
124 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
126 result_ = static_cast<EventResult>(result_ | ER_HANDLED);
129 Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
131 time_stamp_(time_stamp),
133 native_event_(base::NativeEvent()),
134 delete_native_event_(false),
137 phase_(EP_PREDISPATCH),
138 result_(ER_UNHANDLED) {
140 name_ = EventTypeName(type_);
143 Event::Event(const base::NativeEvent& native_event,
147 time_stamp_(EventTimeFromNative(native_event)),
149 native_event_(native_event),
150 delete_native_event_(false),
153 phase_(EP_PREDISPATCH),
154 result_(ER_UNHANDLED) {
155 base::TimeDelta delta = EventTimeForNow() - time_stamp_;
157 name_ = EventTypeName(type_);
158 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser",
159 delta.InMicroseconds(), 1, 1000000, 100);
160 std::string name_for_event =
161 base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
162 base::HistogramBase* counter_for_type =
163 base::Histogram::FactoryGet(
168 base::HistogramBase::kUmaTargetedHistogramFlag);
169 counter_for_type->Add(delta.InMicroseconds());
172 Event::Event(const Event& copy)
174 time_stamp_(copy.time_stamp_),
175 latency_(copy.latency_),
177 native_event_(CopyNativeEvent(copy.native_event_)),
178 delete_native_event_(true),
181 phase_(EP_PREDISPATCH),
182 result_(ER_UNHANDLED) {
184 name_ = EventTypeName(type_);
187 void Event::SetType(EventType type) {
189 name_ = std::string();
192 name_ = EventTypeName(type_);
195 ////////////////////////////////////////////////////////////////////////////////
198 CancelModeEvent::CancelModeEvent()
199 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
200 set_cancelable(false);
203 CancelModeEvent::~CancelModeEvent() {
206 ////////////////////////////////////////////////////////////////////////////////
209 LocatedEvent::~LocatedEvent() {
212 LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
213 : Event(native_event,
214 EventTypeFromNative(native_event),
215 EventFlagsFromNative(native_event)),
216 location_(EventLocationFromNative(native_event)),
217 root_location_(location_) {
220 LocatedEvent::LocatedEvent(EventType type,
221 const gfx::PointF& location,
222 const gfx::PointF& root_location,
223 base::TimeDelta time_stamp,
225 : Event(type, time_stamp, flags),
227 root_location_(root_location) {
230 void LocatedEvent::UpdateForRootTransform(
231 const gfx::Transform& reversed_root_transform) {
232 // Transform has to be done at root level.
233 gfx::Point3F p(location_);
234 reversed_root_transform.TransformPoint(&p);
235 location_ = p.AsPointF();
236 root_location_ = location_;
239 ////////////////////////////////////////////////////////////////////////////////
242 MouseEvent::MouseEvent(const base::NativeEvent& native_event)
243 : LocatedEvent(native_event),
244 changed_button_flags_(
245 GetChangedMouseButtonFlagsFromNative(native_event)) {
246 if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED)
247 SetClickCount(GetRepeatCount(*this));
250 MouseEvent::MouseEvent(EventType type,
251 const gfx::PointF& location,
252 const gfx::PointF& root_location,
254 int changed_button_flags)
255 : LocatedEvent(type, location, root_location, EventTimeForNow(), flags),
256 changed_button_flags_(changed_button_flags) {
257 if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
258 SetType(ET_MOUSE_DRAGGED);
262 bool MouseEvent::IsRepeatedClickEvent(
263 const MouseEvent& event1,
264 const MouseEvent& event2) {
265 // These values match the Windows defaults.
266 static const int kDoubleClickTimeMS = 500;
267 static const int kDoubleClickWidth = 4;
268 static const int kDoubleClickHeight = 4;
270 if (event1.type() != ET_MOUSE_PRESSED ||
271 event2.type() != ET_MOUSE_PRESSED)
274 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
275 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
276 (event2.flags() & ~EF_IS_DOUBLE_CLICK))
279 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
281 if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
284 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
287 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
294 int MouseEvent::GetRepeatCount(const MouseEvent& event) {
296 if (last_click_event_) {
297 if (event.type() == ui::ET_MOUSE_RELEASED)
298 return last_click_event_->GetClickCount();
299 if (IsX11SendEventTrue(event.native_event()))
300 click_count = last_click_event_->GetClickCount();
301 else if (IsRepeatedClickEvent(*last_click_event_, event))
302 click_count = last_click_event_->GetClickCount() + 1;
303 delete last_click_event_;
305 last_click_event_ = new MouseEvent(event);
308 last_click_event_->SetClickCount(click_count);
313 MouseEvent* MouseEvent::last_click_event_ = NULL;
315 int MouseEvent::GetClickCount() const {
316 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
319 if (flags() & EF_IS_TRIPLE_CLICK)
321 else if (flags() & EF_IS_DOUBLE_CLICK)
327 void MouseEvent::SetClickCount(int click_count) {
328 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
331 DCHECK(click_count > 0);
332 DCHECK(click_count <= 3);
335 switch (click_count) {
337 f &= ~EF_IS_DOUBLE_CLICK;
338 f &= ~EF_IS_TRIPLE_CLICK;
341 f |= EF_IS_DOUBLE_CLICK;
342 f &= ~EF_IS_TRIPLE_CLICK;
345 f &= ~EF_IS_DOUBLE_CLICK;
346 f |= EF_IS_TRIPLE_CLICK;
352 ////////////////////////////////////////////////////////////////////////////////
355 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
356 : MouseEvent(native_event),
357 offset_(GetMouseWheelOffset(native_event)) {
360 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
361 : MouseEvent(scroll_event),
362 offset_(scroll_event.x_offset(), scroll_event.y_offset()){
363 SetType(ET_MOUSEWHEEL);
366 MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
369 : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
370 DCHECK(type() == ET_MOUSEWHEEL);
373 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
374 : MouseEvent(mouse_wheel_event),
375 offset_(mouse_wheel_event.offset()) {
376 DCHECK(type() == ET_MOUSEWHEEL);
380 // This value matches windows WHEEL_DELTA.
382 const int MouseWheelEvent::kWheelDelta = 120;
384 // This value matches GTK+ wheel scroll amount.
385 const int MouseWheelEvent::kWheelDelta = 53;
388 void MouseWheelEvent::UpdateForRootTransform(
389 const gfx::Transform& inverted_root_transform) {
390 LocatedEvent::UpdateForRootTransform(inverted_root_transform);
391 gfx::DecomposedTransform decomp;
392 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
395 offset_.set_x(offset_.x() * decomp.scale[0]);
397 offset_.set_y(offset_.y() * decomp.scale[1]);
400 ////////////////////////////////////////////////////////////////////////////////
403 TouchEvent::TouchEvent(const base::NativeEvent& native_event)
404 : LocatedEvent(native_event),
405 touch_id_(GetTouchId(native_event)),
406 radius_x_(GetTouchRadiusX(native_event)),
407 radius_y_(GetTouchRadiusY(native_event)),
408 rotation_angle_(GetTouchAngle(native_event)),
409 force_(GetTouchForce(native_event)),
410 source_device_id_(-1) {
411 latency()->AddLatencyNumberWithTimestamp(
412 INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
415 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
419 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data);
420 source_device_id_ = xiev->deviceid;
423 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
426 TouchEvent::TouchEvent(EventType type,
427 const gfx::PointF& location,
429 base::TimeDelta time_stamp)
430 : LocatedEvent(type, location, location, time_stamp, 0),
434 rotation_angle_(0.0f),
436 source_device_id_(-1) {
437 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
440 TouchEvent::TouchEvent(EventType type,
441 const gfx::PointF& location,
444 base::TimeDelta time_stamp,
449 : LocatedEvent(type, location, location, time_stamp, flags),
453 rotation_angle_(angle),
455 source_device_id_(-1) {
456 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
459 TouchEvent::~TouchEvent() {
460 // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
461 // platform setups the tracking_id to slot mapping. So in dtor here,
462 // if this touch event is a release event, we clear the mapping accordingly.
463 if (HasNativeEvent())
464 ClearTouchIdIfReleased(native_event());
467 void TouchEvent::Relocate(const gfx::Point& origin) {
468 location_ -= origin.OffsetFromOrigin();
469 root_location_ -= origin.OffsetFromOrigin();
472 void TouchEvent::UpdateForRootTransform(
473 const gfx::Transform& inverted_root_transform) {
474 LocatedEvent::UpdateForRootTransform(inverted_root_transform);
475 gfx::DecomposedTransform decomp;
476 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
479 radius_x_ *= decomp.scale[0];
481 radius_y_ *= decomp.scale[1];
484 ////////////////////////////////////////////////////////////////////////////////
487 KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char)
488 : Event(native_event,
489 EventTypeFromNative(native_event),
490 EventFlagsFromNative(native_event)),
491 key_code_(KeyboardCodeFromNative(native_event)),
492 code_(CodeFromNative(native_event)),
500 KeyEvent::KeyEvent(EventType type,
501 KeyboardCode key_code,
504 : Event(type, EventTimeForNow(), flags),
507 character_(GetCharacterFromKeyCode(key_code, flags)) {
510 KeyEvent::KeyEvent(EventType type,
511 KeyboardCode key_code,
512 const std::string& code,
515 : Event(type, EventTimeForNow(), flags),
519 character_(GetCharacterFromKeyCode(key_code, flags)) {
522 uint16 KeyEvent::GetCharacter() const {
527 return (native_event().message == WM_CHAR) ? key_code_ :
528 GetCharacterFromKeyCode(key_code_, flags());
529 #elif defined(USE_X11)
531 return GetCharacterFromKeyCode(key_code_, flags());
533 DCHECK(native_event()->type == KeyPress ||
534 native_event()->type == KeyRelease);
537 if (!IsControlDown())
538 ch = GetCharacterFromXEvent(native_event());
539 return ch ? ch : GetCharacterFromKeyCode(key_code_, flags());
541 if (native_event()) {
542 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
543 EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
546 return GetCharacterFromKeyCode(key_code_, flags());
550 bool KeyEvent::IsUnicodeKeyCode() const {
554 const int key = key_code();
555 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
557 // Check whether the user is using the numeric keypad with num-lock off.
558 // In that case, EF_EXTENDED will not be set; if it is set, the key event
559 // originated from the relevant non-numpad dedicated key, e.g. [Insert].
560 return (!(flags() & EF_EXTENDED) &&
561 (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN ||
562 key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR ||
563 key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP ||
570 void KeyEvent::NormalizeFlags() {
572 switch (key_code()) {
574 mask = EF_CONTROL_DOWN;
577 mask = EF_SHIFT_DOWN;
583 mask = EF_CAPS_LOCK_DOWN;
588 if (type() == ET_KEY_PRESSED)
589 set_flags(flags() | mask);
591 set_flags(flags() & ~mask);
594 ////////////////////////////////////////////////////////////////////////////////
595 // TranslatedKeyEvent
597 TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event,
599 : KeyEvent(native_event, is_char) {
600 SetType(type() == ET_KEY_PRESSED ?
601 ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE);
604 TranslatedKeyEvent::TranslatedKeyEvent(bool is_press,
605 KeyboardCode key_code,
607 : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE),
613 TranslatedKeyEvent::TranslatedKeyEvent(const KeyEvent& key_event)
614 : KeyEvent(key_event) {
615 SetType(type() == ET_KEY_PRESSED ?
616 ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE);
620 void TranslatedKeyEvent::ConvertToKeyEvent() {
621 SetType(type() == ET_TRANSLATED_KEY_PRESS ?
622 ET_KEY_PRESSED : ET_KEY_RELEASED);
625 ////////////////////////////////////////////////////////////////////////////////
628 ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
629 : MouseEvent(native_event) {
630 if (type() == ET_SCROLL) {
631 GetScrollOffsets(native_event,
632 &x_offset_, &y_offset_,
633 &x_offset_ordinal_, &y_offset_ordinal_,
635 } else if (type() == ET_SCROLL_FLING_START ||
636 type() == ET_SCROLL_FLING_CANCEL) {
637 GetFlingData(native_event,
638 &x_offset_, &y_offset_,
639 &x_offset_ordinal_, &y_offset_ordinal_,
642 NOTREACHED() << "Unexpected event type " << type()
643 << " when constructing a ScrollEvent.";
647 ScrollEvent::ScrollEvent(EventType type,
648 const gfx::PointF& location,
649 base::TimeDelta time_stamp,
653 float x_offset_ordinal,
654 float y_offset_ordinal,
656 : MouseEvent(type, location, location, flags, 0),
659 x_offset_ordinal_(x_offset_ordinal),
660 y_offset_ordinal_(y_offset_ordinal),
661 finger_count_(finger_count) {
662 set_time_stamp(time_stamp);
663 CHECK(IsScrollEvent());
666 void ScrollEvent::Scale(const float factor) {
669 x_offset_ordinal_ *= factor;
670 y_offset_ordinal_ *= factor;
673 ////////////////////////////////////////////////////////////////////////////////
676 GestureEvent::GestureEvent(EventType type,
680 base::TimeDelta time_stamp,
681 const GestureEventDetails& details,
682 unsigned int touch_ids_bitfield)
687 flags | EF_FROM_TOUCH),
689 touch_ids_bitfield_(touch_ids_bitfield) {
692 GestureEvent::~GestureEvent() {
695 int GestureEvent::GetLowestTouchId() const {
696 if (touch_ids_bitfield_ == 0)
699 // Find the index of the least significant 1 bit
700 while (!(1 << ++i & touch_ids_bitfield_));