Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / events / event.cc
blob1ca065943948cb6f53211c155ddb61ec9608abbe
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/keysym.h>
10 #include <X11/Xlib.h>
11 #endif
13 #include <cmath>
14 #include <cstring>
16 #include "base/metrics/histogram.h"
17 #include "base/strings/stringprintf.h"
18 #include "ui/events/event_utils.h"
19 #include "ui/events/keycodes/dom3/dom_code.h"
20 #include "ui/events/keycodes/dom3/dom_key.h"
21 #include "ui/events/keycodes/dom4/keycode_converter.h"
22 #include "ui/events/keycodes/keyboard_code_conversion.h"
23 #include "ui/gfx/geometry/point3_f.h"
24 #include "ui/gfx/geometry/point_conversions.h"
25 #include "ui/gfx/geometry/safe_integer_conversions.h"
26 #include "ui/gfx/transform.h"
27 #include "ui/gfx/transform_util.h"
29 #if defined(USE_X11)
30 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
31 #elif defined(USE_OZONE)
32 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
33 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
34 #endif
36 namespace {
38 std::string EventTypeName(ui::EventType type) {
39 #define RETURN_IF_TYPE(t) if (type == ui::t) return #t
40 #define CASE_TYPE(t) case ui::t: return #t
41 switch (type) {
42 CASE_TYPE(ET_UNKNOWN);
43 CASE_TYPE(ET_MOUSE_PRESSED);
44 CASE_TYPE(ET_MOUSE_DRAGGED);
45 CASE_TYPE(ET_MOUSE_RELEASED);
46 CASE_TYPE(ET_MOUSE_MOVED);
47 CASE_TYPE(ET_MOUSE_ENTERED);
48 CASE_TYPE(ET_MOUSE_EXITED);
49 CASE_TYPE(ET_KEY_PRESSED);
50 CASE_TYPE(ET_KEY_RELEASED);
51 CASE_TYPE(ET_MOUSEWHEEL);
52 CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED);
53 CASE_TYPE(ET_TOUCH_RELEASED);
54 CASE_TYPE(ET_TOUCH_PRESSED);
55 CASE_TYPE(ET_TOUCH_MOVED);
56 CASE_TYPE(ET_TOUCH_CANCELLED);
57 CASE_TYPE(ET_DROP_TARGET_EVENT);
58 CASE_TYPE(ET_TRANSLATED_KEY_PRESS);
59 CASE_TYPE(ET_TRANSLATED_KEY_RELEASE);
60 CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
61 CASE_TYPE(ET_GESTURE_SCROLL_END);
62 CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
63 CASE_TYPE(ET_GESTURE_SHOW_PRESS);
64 CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE);
65 CASE_TYPE(ET_GESTURE_TAP);
66 CASE_TYPE(ET_GESTURE_TAP_DOWN);
67 CASE_TYPE(ET_GESTURE_TAP_CANCEL);
68 CASE_TYPE(ET_GESTURE_BEGIN);
69 CASE_TYPE(ET_GESTURE_END);
70 CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP);
71 CASE_TYPE(ET_GESTURE_PINCH_BEGIN);
72 CASE_TYPE(ET_GESTURE_PINCH_END);
73 CASE_TYPE(ET_GESTURE_PINCH_UPDATE);
74 CASE_TYPE(ET_GESTURE_LONG_PRESS);
75 CASE_TYPE(ET_GESTURE_LONG_TAP);
76 CASE_TYPE(ET_GESTURE_SWIPE);
77 CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED);
78 CASE_TYPE(ET_GESTURE_DOUBLE_TAP);
79 CASE_TYPE(ET_SCROLL);
80 CASE_TYPE(ET_SCROLL_FLING_START);
81 CASE_TYPE(ET_SCROLL_FLING_CANCEL);
82 CASE_TYPE(ET_CANCEL_MODE);
83 CASE_TYPE(ET_UMA_DATA);
84 case ui::ET_LAST: NOTREACHED(); return std::string();
85 // Don't include default, so that we get an error when new type is added.
87 #undef CASE_TYPE
89 NOTREACHED();
90 return std::string();
93 bool IsX11SendEventTrue(const base::NativeEvent& event) {
94 #if defined(USE_X11)
95 return event && event->xany.send_event;
96 #else
97 return false;
98 #endif
101 bool X11EventHasNonStandardState(const base::NativeEvent& event) {
102 #if defined(USE_X11)
103 const unsigned int kAllStateMask =
104 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask |
105 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask |
106 LockMask | ControlMask | AnyModifier;
107 return event && (event->xkey.state & ~kAllStateMask) != 0;
108 #else
109 return false;
110 #endif
113 unsigned long long get_next_touch_event_id() {
114 static unsigned long long id = 0;
115 return id++;
118 } // namespace
120 namespace ui {
122 ////////////////////////////////////////////////////////////////////////////////
123 // Event
125 // static
126 scoped_ptr<Event> Event::Clone(const Event& event) {
127 if (event.IsKeyEvent()) {
128 return make_scoped_ptr(new KeyEvent(static_cast<const KeyEvent&>(event)));
131 if (event.IsMouseEvent()) {
132 if (event.IsMouseWheelEvent()) {
133 return make_scoped_ptr(
134 new MouseWheelEvent(static_cast<const MouseWheelEvent&>(event)));
137 return make_scoped_ptr(
138 new MouseEvent(static_cast<const MouseEvent&>(event)));
141 if (event.IsTouchEvent()) {
142 return make_scoped_ptr(
143 new TouchEvent(static_cast<const TouchEvent&>(event)));
146 if (event.IsGestureEvent()) {
147 return make_scoped_ptr(
148 new GestureEvent(static_cast<const GestureEvent&>(event)));
151 if (event.IsScrollEvent()) {
152 return make_scoped_ptr(
153 new ScrollEvent(static_cast<const ScrollEvent&>(event)));
156 return make_scoped_ptr(new Event(event));
159 Event::~Event() {
160 if (delete_native_event_)
161 ReleaseCopiedNativeEvent(native_event_);
164 GestureEvent* Event::AsGestureEvent() {
165 CHECK(IsGestureEvent());
166 return static_cast<GestureEvent*>(this);
169 const GestureEvent* Event::AsGestureEvent() const {
170 CHECK(IsGestureEvent());
171 return static_cast<const GestureEvent*>(this);
174 bool Event::HasNativeEvent() const {
175 base::NativeEvent null_event;
176 std::memset(&null_event, 0, sizeof(null_event));
177 return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
180 void Event::StopPropagation() {
181 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
182 // events.
183 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
184 CHECK(cancelable_);
185 result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
188 void Event::SetHandled() {
189 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
190 // events.
191 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
192 CHECK(cancelable_);
193 result_ = static_cast<EventResult>(result_ | ER_HANDLED);
196 Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
197 : type_(type),
198 time_stamp_(time_stamp),
199 flags_(flags),
200 native_event_(base::NativeEvent()),
201 delete_native_event_(false),
202 cancelable_(true),
203 target_(NULL),
204 phase_(EP_PREDISPATCH),
205 result_(ER_UNHANDLED),
206 source_device_id_(ED_UNKNOWN_DEVICE) {
207 if (type_ < ET_LAST)
208 name_ = EventTypeName(type_);
211 Event::Event(const base::NativeEvent& native_event,
212 EventType type,
213 int flags)
214 : type_(type),
215 time_stamp_(EventTimeFromNative(native_event)),
216 flags_(flags),
217 native_event_(native_event),
218 delete_native_event_(false),
219 cancelable_(true),
220 target_(NULL),
221 phase_(EP_PREDISPATCH),
222 result_(ER_UNHANDLED),
223 source_device_id_(ED_UNKNOWN_DEVICE) {
224 base::TimeDelta delta = EventTimeForNow() - time_stamp_;
225 if (type_ < ET_LAST)
226 name_ = EventTypeName(type_);
227 base::HistogramBase::Sample delta_sample =
228 static_cast<base::HistogramBase::Sample>(delta.InMicroseconds());
229 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser", delta_sample, 1, 1000000,
230 100);
231 std::string name_for_event =
232 base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
233 base::HistogramBase* counter_for_type =
234 base::Histogram::FactoryGet(
235 name_for_event,
237 1000000,
238 100,
239 base::HistogramBase::kUmaTargetedHistogramFlag);
240 counter_for_type->Add(delta_sample);
242 #if defined(USE_X11)
243 if (native_event->type == GenericEvent) {
244 XIDeviceEvent* xiev =
245 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
246 source_device_id_ = xiev->sourceid;
248 #endif
251 Event::Event(const Event& copy)
252 : type_(copy.type_),
253 time_stamp_(copy.time_stamp_),
254 latency_(copy.latency_),
255 flags_(copy.flags_),
256 native_event_(CopyNativeEvent(copy.native_event_)),
257 delete_native_event_(true),
258 cancelable_(true),
259 target_(NULL),
260 phase_(EP_PREDISPATCH),
261 result_(ER_UNHANDLED),
262 source_device_id_(copy.source_device_id_) {
263 if (type_ < ET_LAST)
264 name_ = EventTypeName(type_);
267 void Event::SetType(EventType type) {
268 if (type_ < ET_LAST)
269 name_ = std::string();
270 type_ = type;
271 if (type_ < ET_LAST)
272 name_ = EventTypeName(type_);
275 ////////////////////////////////////////////////////////////////////////////////
276 // CancelModeEvent
278 CancelModeEvent::CancelModeEvent()
279 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
280 set_cancelable(false);
283 CancelModeEvent::~CancelModeEvent() {
286 ////////////////////////////////////////////////////////////////////////////////
287 // LocatedEvent
289 LocatedEvent::~LocatedEvent() {
292 LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
293 : Event(native_event,
294 EventTypeFromNative(native_event),
295 EventFlagsFromNative(native_event)),
296 location_(EventLocationFromNative(native_event)),
297 root_location_(location_) {
300 LocatedEvent::LocatedEvent(EventType type,
301 const gfx::PointF& location,
302 const gfx::PointF& root_location,
303 base::TimeDelta time_stamp,
304 int flags)
305 : Event(type, time_stamp, flags),
306 location_(location),
307 root_location_(root_location) {
310 void LocatedEvent::UpdateForRootTransform(
311 const gfx::Transform& reversed_root_transform) {
312 // Transform has to be done at root level.
313 gfx::Point3F p(location_);
314 reversed_root_transform.TransformPoint(&p);
315 location_ = p.AsPointF();
316 root_location_ = location_;
319 ////////////////////////////////////////////////////////////////////////////////
320 // MouseEvent
322 MouseEvent::MouseEvent(const base::NativeEvent& native_event)
323 : LocatedEvent(native_event),
324 changed_button_flags_(
325 GetChangedMouseButtonFlagsFromNative(native_event)) {
326 if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED)
327 SetClickCount(GetRepeatCount(*this));
330 MouseEvent::MouseEvent(EventType type,
331 const gfx::PointF& location,
332 const gfx::PointF& root_location,
333 base::TimeDelta time_stamp,
334 int flags,
335 int changed_button_flags)
336 : LocatedEvent(type, location, root_location, time_stamp, flags),
337 changed_button_flags_(changed_button_flags) {
338 if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
339 SetType(ET_MOUSE_DRAGGED);
342 // static
343 bool MouseEvent::IsRepeatedClickEvent(
344 const MouseEvent& event1,
345 const MouseEvent& event2) {
346 // These values match the Windows defaults.
347 static const int kDoubleClickTimeMS = 500;
348 static const int kDoubleClickWidth = 4;
349 static const int kDoubleClickHeight = 4;
351 if (event1.type() != ET_MOUSE_PRESSED ||
352 event2.type() != ET_MOUSE_PRESSED)
353 return false;
355 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
356 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
357 (event2.flags() & ~EF_IS_DOUBLE_CLICK))
358 return false;
360 // The new event has been created from the same native event.
361 if (event1.time_stamp() == event2.time_stamp())
362 return false;
364 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
366 if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
367 return false;
369 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
370 return false;
372 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
373 return false;
375 return true;
378 // static
379 int MouseEvent::GetRepeatCount(const MouseEvent& event) {
380 int click_count = 1;
381 if (last_click_event_) {
382 if (event.type() == ui::ET_MOUSE_RELEASED) {
383 if (event.changed_button_flags() ==
384 last_click_event_->changed_button_flags()) {
385 last_click_complete_ = true;
386 return last_click_event_->GetClickCount();
387 } else {
388 // If last_click_event_ has changed since this button was pressed
389 // return a click count of 1.
390 return click_count;
393 if (event.time_stamp() != last_click_event_->time_stamp())
394 last_click_complete_ = true;
395 if (!last_click_complete_ ||
396 IsX11SendEventTrue(event.native_event())) {
397 click_count = last_click_event_->GetClickCount();
398 } else if (IsRepeatedClickEvent(*last_click_event_, event)) {
399 click_count = last_click_event_->GetClickCount() + 1;
401 delete last_click_event_;
403 last_click_event_ = new MouseEvent(event);
404 last_click_complete_ = false;
405 if (click_count > 3)
406 click_count = 3;
407 last_click_event_->SetClickCount(click_count);
408 return click_count;
411 void MouseEvent::ResetLastClickForTest() {
412 if (last_click_event_) {
413 delete last_click_event_;
414 last_click_event_ = NULL;
415 last_click_complete_ = false;
419 // static
420 MouseEvent* MouseEvent::last_click_event_ = NULL;
421 bool MouseEvent::last_click_complete_ = false;
423 int MouseEvent::GetClickCount() const {
424 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
425 return 0;
427 if (flags() & EF_IS_TRIPLE_CLICK)
428 return 3;
429 else if (flags() & EF_IS_DOUBLE_CLICK)
430 return 2;
431 else
432 return 1;
435 void MouseEvent::SetClickCount(int click_count) {
436 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
437 return;
439 DCHECK(click_count > 0);
440 DCHECK(click_count <= 3);
442 int f = flags();
443 switch (click_count) {
444 case 1:
445 f &= ~EF_IS_DOUBLE_CLICK;
446 f &= ~EF_IS_TRIPLE_CLICK;
447 break;
448 case 2:
449 f |= EF_IS_DOUBLE_CLICK;
450 f &= ~EF_IS_TRIPLE_CLICK;
451 break;
452 case 3:
453 f &= ~EF_IS_DOUBLE_CLICK;
454 f |= EF_IS_TRIPLE_CLICK;
455 break;
457 set_flags(f);
460 ////////////////////////////////////////////////////////////////////////////////
461 // MouseWheelEvent
463 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
464 : MouseEvent(native_event),
465 offset_(GetMouseWheelOffset(native_event)) {
468 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
469 : MouseEvent(scroll_event),
470 offset_(gfx::ToRoundedInt(scroll_event.x_offset()),
471 gfx::ToRoundedInt(scroll_event.y_offset())) {
472 SetType(ET_MOUSEWHEEL);
475 MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
476 int x_offset,
477 int y_offset)
478 : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
479 DCHECK(type() == ET_MOUSEWHEEL);
482 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
483 : MouseEvent(mouse_wheel_event),
484 offset_(mouse_wheel_event.offset()) {
485 DCHECK(type() == ET_MOUSEWHEEL);
488 MouseWheelEvent::MouseWheelEvent(const gfx::Vector2d& offset,
489 const gfx::PointF& location,
490 const gfx::PointF& root_location,
491 base::TimeDelta time_stamp,
492 int flags,
493 int changed_button_flags)
494 : MouseEvent(ui::ET_MOUSEWHEEL,
495 location,
496 root_location,
497 time_stamp,
498 flags,
499 changed_button_flags),
500 offset_(offset) {
503 #if defined(OS_WIN)
504 // This value matches windows WHEEL_DELTA.
505 // static
506 const int MouseWheelEvent::kWheelDelta = 120;
507 #else
508 // This value matches GTK+ wheel scroll amount.
509 const int MouseWheelEvent::kWheelDelta = 53;
510 #endif
512 ////////////////////////////////////////////////////////////////////////////////
513 // TouchEvent
515 TouchEvent::TouchEvent(const base::NativeEvent& native_event)
516 : LocatedEvent(native_event),
517 touch_id_(GetTouchId(native_event)),
518 unique_event_id_(get_next_touch_event_id()),
519 radius_x_(GetTouchRadiusX(native_event)),
520 radius_y_(GetTouchRadiusY(native_event)),
521 rotation_angle_(GetTouchAngle(native_event)),
522 force_(GetTouchForce(native_event)),
523 may_cause_scrolling_(false),
524 should_remove_native_touch_id_mapping_(false) {
525 latency()->AddLatencyNumberWithTimestamp(
526 INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0,
527 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1);
528 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
530 FixRotationAngle();
531 if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
532 should_remove_native_touch_id_mapping_ = true;
535 TouchEvent::TouchEvent(EventType type,
536 const gfx::PointF& location,
537 int touch_id,
538 base::TimeDelta time_stamp)
539 : LocatedEvent(type, location, location, time_stamp, 0),
540 touch_id_(touch_id),
541 unique_event_id_(get_next_touch_event_id()),
542 radius_x_(0.0f),
543 radius_y_(0.0f),
544 rotation_angle_(0.0f),
545 force_(0.0f),
546 may_cause_scrolling_(false),
547 should_remove_native_touch_id_mapping_(false) {
548 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
551 TouchEvent::TouchEvent(EventType type,
552 const gfx::PointF& location,
553 int flags,
554 int touch_id,
555 base::TimeDelta time_stamp,
556 float radius_x,
557 float radius_y,
558 float angle,
559 float force)
560 : LocatedEvent(type, location, location, time_stamp, flags),
561 touch_id_(touch_id),
562 unique_event_id_(get_next_touch_event_id()),
563 radius_x_(radius_x),
564 radius_y_(radius_y),
565 rotation_angle_(angle),
566 force_(force),
567 may_cause_scrolling_(false),
568 should_remove_native_touch_id_mapping_(false) {
569 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
570 FixRotationAngle();
573 TouchEvent::TouchEvent(const TouchEvent& copy)
574 : LocatedEvent(copy),
575 touch_id_(copy.touch_id_),
576 unique_event_id_(copy.unique_event_id_),
577 radius_x_(copy.radius_x_),
578 radius_y_(copy.radius_y_),
579 rotation_angle_(copy.rotation_angle_),
580 force_(copy.force_),
581 may_cause_scrolling_(copy.may_cause_scrolling_),
582 should_remove_native_touch_id_mapping_(false) {
583 // Copied events should not remove touch id mapping, as this either causes the
584 // mapping to be lost before the initial event has finished dispatching, or
585 // the copy to attempt to remove the mapping from a null |native_event_|.
588 TouchEvent::~TouchEvent() {
589 // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
590 // platform setups the tracking_id to slot mapping. So in dtor here,
591 // if this touch event is a release event, we clear the mapping accordingly.
592 if (should_remove_native_touch_id_mapping_) {
593 DCHECK(type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED);
594 if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
595 ClearTouchIdIfReleased(native_event());
599 void TouchEvent::UpdateForRootTransform(
600 const gfx::Transform& inverted_root_transform) {
601 LocatedEvent::UpdateForRootTransform(inverted_root_transform);
602 gfx::DecomposedTransform decomp;
603 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
604 DCHECK(success);
605 if (decomp.scale[0])
606 radius_x_ *= decomp.scale[0];
607 if (decomp.scale[1])
608 radius_y_ *= decomp.scale[1];
611 void TouchEvent::DisableSynchronousHandling() {
612 DispatcherApi dispatcher_api(this);
613 dispatcher_api.set_result(
614 static_cast<EventResult>(result() | ER_DISABLE_SYNC_HANDLING));
617 void TouchEvent::FixRotationAngle() {
618 while (rotation_angle_ < 0)
619 rotation_angle_ += 180;
620 while (rotation_angle_ >= 180)
621 rotation_angle_ -= 180;
624 ////////////////////////////////////////////////////////////////////////////////
625 // KeyEvent
627 // static
628 KeyEvent* KeyEvent::last_key_event_ = NULL;
630 // static
631 bool KeyEvent::IsRepeated(const KeyEvent& event) {
632 // A safe guard in case if there were continous key pressed events that are
633 // not auto repeat.
634 const int kMaxAutoRepeatTimeMs = 2000;
635 // Ignore key events that have non standard state masks as it may be
636 // reposted by an IME. IBUS-GTK uses this field to detect the
637 // re-posted event for example. crbug.com/385873.
638 if (X11EventHasNonStandardState(event.native_event()))
639 return false;
640 if (event.is_char())
641 return false;
642 if (event.type() == ui::ET_KEY_RELEASED) {
643 delete last_key_event_;
644 last_key_event_ = NULL;
645 return false;
647 CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
648 if (!last_key_event_) {
649 last_key_event_ = new KeyEvent(event);
650 return false;
651 } else if (event.time_stamp() == last_key_event_->time_stamp()) {
652 // The KeyEvent is created from the same native event.
653 return (last_key_event_->flags() & ui::EF_IS_REPEAT) != 0;
655 if (event.key_code() == last_key_event_->key_code() &&
656 event.flags() == (last_key_event_->flags() & ~ui::EF_IS_REPEAT) &&
657 (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() <
658 kMaxAutoRepeatTimeMs) {
659 last_key_event_->set_time_stamp(event.time_stamp());
660 last_key_event_->set_flags(last_key_event_->flags() | ui::EF_IS_REPEAT);
661 return true;
663 delete last_key_event_;
664 last_key_event_ = new KeyEvent(event);
665 return false;
668 KeyEvent::KeyEvent(const base::NativeEvent& native_event)
669 : Event(native_event,
670 EventTypeFromNative(native_event),
671 EventFlagsFromNative(native_event)),
672 key_code_(KeyboardCodeFromNative(native_event)),
673 code_(CodeFromNative(native_event)),
674 is_char_(IsCharFromNative(native_event)),
675 platform_keycode_(PlatformKeycodeFromNative(native_event)),
676 key_(DomKey::NONE),
677 character_(0) {
678 if (IsRepeated(*this))
679 set_flags(flags() | ui::EF_IS_REPEAT);
681 #if defined(USE_X11)
682 NormalizeFlags();
683 #endif
684 #if defined(OS_WIN)
685 // Only Windows has native character events.
686 if (is_char_)
687 character_ = native_event.wParam;
688 #endif
691 KeyEvent::KeyEvent(EventType type,
692 KeyboardCode key_code,
693 int flags)
694 : Event(type, EventTimeForNow(), flags),
695 key_code_(key_code),
696 code_(UsLayoutKeyboardCodeToDomCode(key_code)),
697 is_char_(false),
698 platform_keycode_(0),
699 key_(DomKey::NONE),
700 character_() {
703 KeyEvent::KeyEvent(EventType type,
704 KeyboardCode key_code,
705 DomCode code,
706 int flags)
707 : Event(type, EventTimeForNow(), flags),
708 key_code_(key_code),
709 code_(code),
710 is_char_(false),
711 platform_keycode_(0),
712 key_(DomKey::NONE),
713 character_(0) {
716 KeyEvent::KeyEvent(EventType type,
717 KeyboardCode key_code,
718 DomCode code,
719 int flags,
720 DomKey key,
721 base::char16 character,
722 base::TimeDelta time_stamp)
723 : Event(type, time_stamp, flags),
724 key_code_(key_code),
725 code_(code),
726 is_char_(false),
727 platform_keycode_(0),
728 key_(key),
729 character_(character) {
732 KeyEvent::KeyEvent(base::char16 character, KeyboardCode key_code, int flags)
733 : Event(ET_KEY_PRESSED, EventTimeForNow(), flags),
734 key_code_(key_code),
735 code_(DomCode::NONE),
736 is_char_(true),
737 platform_keycode_(0),
738 key_(DomKey::CHARACTER),
739 character_(character) {
742 KeyEvent::KeyEvent(const KeyEvent& rhs)
743 : Event(rhs),
744 key_code_(rhs.key_code_),
745 code_(rhs.code_),
746 is_char_(rhs.is_char_),
747 platform_keycode_(rhs.platform_keycode_),
748 key_(rhs.key_),
749 character_(rhs.character_) {
750 if (rhs.extended_key_event_data_)
751 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
754 KeyEvent& KeyEvent::operator=(const KeyEvent& rhs) {
755 if (this != &rhs) {
756 Event::operator=(rhs);
757 key_code_ = rhs.key_code_;
758 code_ = rhs.code_;
759 key_ = rhs.key_;
760 is_char_ = rhs.is_char_;
761 platform_keycode_ = rhs.platform_keycode_;
762 character_ = rhs.character_;
764 if (rhs.extended_key_event_data_)
765 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
767 return *this;
770 KeyEvent::~KeyEvent() {}
772 void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) {
773 extended_key_event_data_ = data.Pass();
776 void KeyEvent::ApplyLayout() const {
777 // If the client has set the character (e.g. faked key events from virtual
778 // keyboard), it's client's responsibility to set the dom key correctly.
779 // Otherwise, set the dom key as unidentified.
780 // Please refer to crbug.com/443889.
781 if (character_ != 0) {
782 key_ = DomKey::UNIDENTIFIED;
783 return;
785 ui::DomCode code = code_;
786 if (code == DomCode::NONE) {
787 // Catch old code that tries to do layout without a physical key, and try
788 // to recover using the KeyboardCode. Once key events are fully defined
789 // on construction (see TODO in event.h) this will go away.
790 LOG(WARNING) << "DomCode::NONE keycode=" << key_code_;
791 code = UsLayoutKeyboardCodeToDomCode(key_code_);
792 if (code == DomCode::NONE) {
793 key_ = DomKey::UNIDENTIFIED;
794 return;
797 KeyboardCode dummy_key_code;
798 #if defined(OS_WIN)
799 // Native Windows character events always have is_char_ == true,
800 // so this is a synthetic or native keystroke event.
801 // Therefore, perform only the fallback action.
802 #elif defined(USE_X11)
803 // When a control key is held, prefer ASCII characters to non ASCII
804 // characters in order to use it for shortcut keys. GetCharacterFromKeyCode
805 // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
806 // GetCharacterFromXEvent returns 'à' in that case.
807 if (!IsControlDown() && native_event()) {
808 character_ = GetCharacterFromXEvent(native_event());
809 // TODO(kpschoedel): set key_ field for X11.
810 return;
812 #elif defined(USE_OZONE)
813 if (KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
814 code, flags(), &key_, &character_, &dummy_key_code,
815 &platform_keycode_)) {
816 return;
818 #else
819 if (native_event()) {
820 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
821 EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
823 #endif
824 if (!DomCodeToUsLayoutMeaning(code, flags(), &key_, &character_,
825 &dummy_key_code)) {
826 key_ = DomKey::UNIDENTIFIED;
830 DomKey KeyEvent::GetDomKey() const {
831 // Determination of character_ and key_ may be done lazily.
832 if (key_ == DomKey::NONE)
833 ApplyLayout();
834 return key_;
837 base::char16 KeyEvent::GetCharacter() const {
838 // Determination of character_ and key_ may be done lazily.
839 if (key_ == DomKey::NONE)
840 ApplyLayout();
841 return character_;
844 base::char16 KeyEvent::GetText() const {
845 if ((flags() & EF_CONTROL_DOWN) != 0) {
846 base::char16 character;
847 ui::DomKey key;
848 ui::KeyboardCode key_code;
849 if (DomCodeToControlCharacter(code_, flags(), &key, &character, &key_code))
850 return character;
852 return GetUnmodifiedText();
855 base::char16 KeyEvent::GetUnmodifiedText() const {
856 if (!is_char_ && (key_code_ == VKEY_RETURN))
857 return '\r';
858 return GetCharacter();
861 bool KeyEvent::IsUnicodeKeyCode() const {
862 #if defined(OS_WIN)
863 if (!IsAltDown())
864 return false;
865 const int key = key_code();
866 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
867 return true;
868 // Check whether the user is using the numeric keypad with num-lock off.
869 // In that case, EF_EXTENDED will not be set; if it is set, the key event
870 // originated from the relevant non-numpad dedicated key, e.g. [Insert].
871 return (!(flags() & EF_EXTENDED) &&
872 (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN ||
873 key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR ||
874 key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP ||
875 key == VKEY_PRIOR));
876 #else
877 return false;
878 #endif
881 void KeyEvent::NormalizeFlags() {
882 int mask = 0;
883 switch (key_code()) {
884 case VKEY_CONTROL:
885 mask = EF_CONTROL_DOWN;
886 break;
887 case VKEY_SHIFT:
888 mask = EF_SHIFT_DOWN;
889 break;
890 case VKEY_MENU:
891 mask = EF_ALT_DOWN;
892 break;
893 case VKEY_CAPITAL:
894 mask = EF_CAPS_LOCK_DOWN;
895 break;
896 default:
897 return;
899 if (type() == ET_KEY_PRESSED)
900 set_flags(flags() | mask);
901 else
902 set_flags(flags() & ~mask);
905 bool KeyEvent::IsTranslated() const {
906 switch (type()) {
907 case ET_KEY_PRESSED:
908 case ET_KEY_RELEASED:
909 return false;
910 case ET_TRANSLATED_KEY_PRESS:
911 case ET_TRANSLATED_KEY_RELEASE:
912 return true;
913 default:
914 NOTREACHED();
915 return false;
919 void KeyEvent::SetTranslated(bool translated) {
920 switch (type()) {
921 case ET_KEY_PRESSED:
922 case ET_TRANSLATED_KEY_PRESS:
923 SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED);
924 break;
925 case ET_KEY_RELEASED:
926 case ET_TRANSLATED_KEY_RELEASE:
927 SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED);
928 break;
929 default:
930 NOTREACHED();
934 KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
935 return NonLocatedToLocatedKeyboardCode(key_code_, code_);
938 uint16 KeyEvent::GetConflatedWindowsKeyCode() const {
939 if (is_char_)
940 return character_;
941 return key_code_;
944 std::string KeyEvent::GetCodeString() const {
945 return KeycodeConverter::DomCodeToCodeString(code_);
948 ////////////////////////////////////////////////////////////////////////////////
949 // ScrollEvent
951 ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
952 : MouseEvent(native_event) {
953 if (type() == ET_SCROLL) {
954 GetScrollOffsets(native_event,
955 &x_offset_, &y_offset_,
956 &x_offset_ordinal_, &y_offset_ordinal_,
957 &finger_count_);
958 } else if (type() == ET_SCROLL_FLING_START ||
959 type() == ET_SCROLL_FLING_CANCEL) {
960 GetFlingData(native_event,
961 &x_offset_, &y_offset_,
962 &x_offset_ordinal_, &y_offset_ordinal_,
963 NULL);
964 } else {
965 NOTREACHED() << "Unexpected event type " << type()
966 << " when constructing a ScrollEvent.";
970 ScrollEvent::ScrollEvent(EventType type,
971 const gfx::PointF& location,
972 base::TimeDelta time_stamp,
973 int flags,
974 float x_offset,
975 float y_offset,
976 float x_offset_ordinal,
977 float y_offset_ordinal,
978 int finger_count)
979 : MouseEvent(type, location, location, time_stamp, flags, 0),
980 x_offset_(x_offset),
981 y_offset_(y_offset),
982 x_offset_ordinal_(x_offset_ordinal),
983 y_offset_ordinal_(y_offset_ordinal),
984 finger_count_(finger_count) {
985 CHECK(IsScrollEvent());
988 void ScrollEvent::Scale(const float factor) {
989 x_offset_ *= factor;
990 y_offset_ *= factor;
991 x_offset_ordinal_ *= factor;
992 y_offset_ordinal_ *= factor;
995 ////////////////////////////////////////////////////////////////////////////////
996 // GestureEvent
998 GestureEvent::GestureEvent(float x,
999 float y,
1000 int flags,
1001 base::TimeDelta time_stamp,
1002 const GestureEventDetails& details)
1003 : LocatedEvent(details.type(),
1004 gfx::PointF(x, y),
1005 gfx::PointF(x, y),
1006 time_stamp,
1007 flags | EF_FROM_TOUCH),
1008 details_(details) {
1011 GestureEvent::~GestureEvent() {
1014 } // namespace ui