ffmpeg_common: s/PIX_FMT/AV_PIX_FMT/
[chromium-blink-merge.git] / ui / events / event.cc
blob953220d0a634f1de2ae7ec3ca738dfc34a879839
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/base_event_utils.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/events/keycodes/dom/dom_code.h"
21 #include "ui/events/keycodes/dom/dom_key.h"
22 #include "ui/events/keycodes/dom/keycode_converter.h"
23 #include "ui/events/keycodes/keyboard_code_conversion.h"
24 #include "ui/gfx/geometry/point3_f.h"
25 #include "ui/gfx/geometry/point_conversions.h"
26 #include "ui/gfx/geometry/safe_integer_conversions.h"
27 #include "ui/gfx/transform.h"
28 #include "ui/gfx/transform_util.h"
30 #if defined(USE_X11)
31 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
32 #elif defined(USE_OZONE)
33 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
34 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
35 #endif
37 namespace {
39 std::string EventTypeName(ui::EventType type) {
40 #define RETURN_IF_TYPE(t) if (type == ui::t) return #t
41 #define CASE_TYPE(t) case ui::t: return #t
42 switch (type) {
43 CASE_TYPE(ET_UNKNOWN);
44 CASE_TYPE(ET_MOUSE_PRESSED);
45 CASE_TYPE(ET_MOUSE_DRAGGED);
46 CASE_TYPE(ET_MOUSE_RELEASED);
47 CASE_TYPE(ET_MOUSE_MOVED);
48 CASE_TYPE(ET_MOUSE_ENTERED);
49 CASE_TYPE(ET_MOUSE_EXITED);
50 CASE_TYPE(ET_KEY_PRESSED);
51 CASE_TYPE(ET_KEY_RELEASED);
52 CASE_TYPE(ET_MOUSEWHEEL);
53 CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED);
54 CASE_TYPE(ET_TOUCH_RELEASED);
55 CASE_TYPE(ET_TOUCH_PRESSED);
56 CASE_TYPE(ET_TOUCH_MOVED);
57 CASE_TYPE(ET_TOUCH_CANCELLED);
58 CASE_TYPE(ET_DROP_TARGET_EVENT);
59 CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
60 CASE_TYPE(ET_GESTURE_SCROLL_END);
61 CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
62 CASE_TYPE(ET_GESTURE_SHOW_PRESS);
63 CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE);
64 CASE_TYPE(ET_GESTURE_TAP);
65 CASE_TYPE(ET_GESTURE_TAP_DOWN);
66 CASE_TYPE(ET_GESTURE_TAP_CANCEL);
67 CASE_TYPE(ET_GESTURE_BEGIN);
68 CASE_TYPE(ET_GESTURE_END);
69 CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP);
70 CASE_TYPE(ET_GESTURE_PINCH_BEGIN);
71 CASE_TYPE(ET_GESTURE_PINCH_END);
72 CASE_TYPE(ET_GESTURE_PINCH_UPDATE);
73 CASE_TYPE(ET_GESTURE_LONG_PRESS);
74 CASE_TYPE(ET_GESTURE_LONG_TAP);
75 CASE_TYPE(ET_GESTURE_SWIPE);
76 CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED);
77 CASE_TYPE(ET_GESTURE_DOUBLE_TAP);
78 CASE_TYPE(ET_SCROLL);
79 CASE_TYPE(ET_SCROLL_FLING_START);
80 CASE_TYPE(ET_SCROLL_FLING_CANCEL);
81 CASE_TYPE(ET_CANCEL_MODE);
82 CASE_TYPE(ET_UMA_DATA);
83 case ui::ET_LAST: NOTREACHED(); return std::string();
84 // Don't include default, so that we get an error when new type is added.
86 #undef CASE_TYPE
88 NOTREACHED();
89 return std::string();
92 bool IsX11SendEventTrue(const base::NativeEvent& event) {
93 #if defined(USE_X11)
94 return event && event->xany.send_event;
95 #else
96 return false;
97 #endif
100 bool X11EventHasNonStandardState(const base::NativeEvent& event) {
101 #if defined(USE_X11)
102 const unsigned int kAllStateMask =
103 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask |
104 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask |
105 LockMask | ControlMask | AnyModifier;
106 return event && (event->xkey.state & ~kAllStateMask) != 0;
107 #else
108 return false;
109 #endif
112 } // namespace
114 namespace ui {
116 ////////////////////////////////////////////////////////////////////////////////
117 // Event
119 // static
120 scoped_ptr<Event> Event::Clone(const Event& event) {
121 if (event.IsKeyEvent()) {
122 return make_scoped_ptr(new KeyEvent(static_cast<const KeyEvent&>(event)));
125 if (event.IsMouseEvent()) {
126 if (event.IsMouseWheelEvent()) {
127 return make_scoped_ptr(
128 new MouseWheelEvent(static_cast<const MouseWheelEvent&>(event)));
131 return make_scoped_ptr(
132 new MouseEvent(static_cast<const MouseEvent&>(event)));
135 if (event.IsTouchEvent()) {
136 return make_scoped_ptr(
137 new TouchEvent(static_cast<const TouchEvent&>(event)));
140 if (event.IsGestureEvent()) {
141 return make_scoped_ptr(
142 new GestureEvent(static_cast<const GestureEvent&>(event)));
145 if (event.IsScrollEvent()) {
146 return make_scoped_ptr(
147 new ScrollEvent(static_cast<const ScrollEvent&>(event)));
150 return make_scoped_ptr(new Event(event));
153 Event::~Event() {
154 if (delete_native_event_)
155 ReleaseCopiedNativeEvent(native_event_);
158 GestureEvent* Event::AsGestureEvent() {
159 CHECK(IsGestureEvent());
160 return static_cast<GestureEvent*>(this);
163 const GestureEvent* Event::AsGestureEvent() const {
164 CHECK(IsGestureEvent());
165 return static_cast<const GestureEvent*>(this);
168 bool Event::HasNativeEvent() const {
169 base::NativeEvent null_event;
170 std::memset(&null_event, 0, sizeof(null_event));
171 return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
174 void Event::StopPropagation() {
175 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
176 // events.
177 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
178 CHECK(cancelable_);
179 result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
182 void Event::SetHandled() {
183 // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
184 // events.
185 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
186 CHECK(cancelable_);
187 result_ = static_cast<EventResult>(result_ | ER_HANDLED);
190 Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
191 : type_(type),
192 time_stamp_(time_stamp),
193 flags_(flags),
194 native_event_(base::NativeEvent()),
195 delete_native_event_(false),
196 cancelable_(true),
197 target_(NULL),
198 phase_(EP_PREDISPATCH),
199 result_(ER_UNHANDLED),
200 source_device_id_(ED_UNKNOWN_DEVICE) {
201 if (type_ < ET_LAST)
202 name_ = EventTypeName(type_);
205 Event::Event(const base::NativeEvent& native_event,
206 EventType type,
207 int flags)
208 : type_(type),
209 time_stamp_(EventTimeFromNative(native_event)),
210 flags_(flags),
211 native_event_(native_event),
212 delete_native_event_(false),
213 cancelable_(true),
214 target_(NULL),
215 phase_(EP_PREDISPATCH),
216 result_(ER_UNHANDLED),
217 source_device_id_(ED_UNKNOWN_DEVICE) {
218 base::TimeDelta delta = EventTimeForNow() - time_stamp_;
219 if (type_ < ET_LAST)
220 name_ = EventTypeName(type_);
221 base::HistogramBase::Sample delta_sample =
222 static_cast<base::HistogramBase::Sample>(delta.InMicroseconds());
223 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser", delta_sample, 1, 1000000,
224 100);
225 std::string name_for_event =
226 base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
227 base::HistogramBase* counter_for_type =
228 base::Histogram::FactoryGet(
229 name_for_event,
231 1000000,
232 100,
233 base::HistogramBase::kUmaTargetedHistogramFlag);
234 counter_for_type->Add(delta_sample);
236 #if defined(USE_X11)
237 if (native_event->type == GenericEvent) {
238 XIDeviceEvent* xiev =
239 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
240 source_device_id_ = xiev->sourceid;
242 #endif
243 #if defined(USE_OZONE)
244 source_device_id_ =
245 static_cast<const Event*>(native_event)->source_device_id();
246 #endif
249 Event::Event(const Event& copy)
250 : type_(copy.type_),
251 time_stamp_(copy.time_stamp_),
252 latency_(copy.latency_),
253 flags_(copy.flags_),
254 native_event_(CopyNativeEvent(copy.native_event_)),
255 delete_native_event_(true),
256 cancelable_(true),
257 target_(NULL),
258 phase_(EP_PREDISPATCH),
259 result_(ER_UNHANDLED),
260 source_device_id_(copy.source_device_id_) {
261 if (type_ < ET_LAST)
262 name_ = EventTypeName(type_);
265 void Event::SetType(EventType type) {
266 if (type_ < ET_LAST)
267 name_ = std::string();
268 type_ = type;
269 if (type_ < ET_LAST)
270 name_ = EventTypeName(type_);
273 ////////////////////////////////////////////////////////////////////////////////
274 // CancelModeEvent
276 CancelModeEvent::CancelModeEvent()
277 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
278 set_cancelable(false);
281 CancelModeEvent::~CancelModeEvent() {
284 ////////////////////////////////////////////////////////////////////////////////
285 // LocatedEvent
287 LocatedEvent::~LocatedEvent() {
290 LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
291 : Event(native_event,
292 EventTypeFromNative(native_event),
293 EventFlagsFromNative(native_event)),
294 location_(EventLocationFromNative(native_event)),
295 root_location_(location_) {
298 LocatedEvent::LocatedEvent(EventType type,
299 const gfx::PointF& location,
300 const gfx::PointF& root_location,
301 base::TimeDelta time_stamp,
302 int flags)
303 : Event(type, time_stamp, flags),
304 location_(location),
305 root_location_(root_location) {
308 void LocatedEvent::UpdateForRootTransform(
309 const gfx::Transform& reversed_root_transform) {
310 // Transform has to be done at root level.
311 gfx::Point3F p(location_);
312 reversed_root_transform.TransformPoint(&p);
313 location_ = p.AsPointF();
314 root_location_ = location_;
317 ////////////////////////////////////////////////////////////////////////////////
318 // MouseEvent
320 MouseEvent::MouseEvent(const base::NativeEvent& native_event)
321 : LocatedEvent(native_event),
322 changed_button_flags_(
323 GetChangedMouseButtonFlagsFromNative(native_event)) {
324 if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED)
325 SetClickCount(GetRepeatCount(*this));
328 MouseEvent::MouseEvent(EventType type,
329 const gfx::PointF& location,
330 const gfx::PointF& root_location,
331 base::TimeDelta time_stamp,
332 int flags,
333 int changed_button_flags)
334 : LocatedEvent(type, location, root_location, time_stamp, flags),
335 changed_button_flags_(changed_button_flags) {
336 if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
337 SetType(ET_MOUSE_DRAGGED);
340 // static
341 bool MouseEvent::IsRepeatedClickEvent(
342 const MouseEvent& event1,
343 const MouseEvent& event2) {
344 // These values match the Windows defaults.
345 static const int kDoubleClickTimeMS = 500;
346 static const int kDoubleClickWidth = 4;
347 static const int kDoubleClickHeight = 4;
349 if (event1.type() != ET_MOUSE_PRESSED ||
350 event2.type() != ET_MOUSE_PRESSED)
351 return false;
353 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
354 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
355 (event2.flags() & ~EF_IS_DOUBLE_CLICK))
356 return false;
358 // The new event has been created from the same native event.
359 if (event1.time_stamp() == event2.time_stamp())
360 return false;
362 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
364 if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
365 return false;
367 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
368 return false;
370 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
371 return false;
373 return true;
376 // static
377 int MouseEvent::GetRepeatCount(const MouseEvent& event) {
378 int click_count = 1;
379 if (last_click_event_) {
380 if (event.type() == ui::ET_MOUSE_RELEASED) {
381 if (event.changed_button_flags() ==
382 last_click_event_->changed_button_flags()) {
383 last_click_complete_ = true;
384 return last_click_event_->GetClickCount();
385 } else {
386 // If last_click_event_ has changed since this button was pressed
387 // return a click count of 1.
388 return click_count;
391 if (event.time_stamp() != last_click_event_->time_stamp())
392 last_click_complete_ = true;
393 if (!last_click_complete_ ||
394 IsX11SendEventTrue(event.native_event())) {
395 click_count = last_click_event_->GetClickCount();
396 } else if (IsRepeatedClickEvent(*last_click_event_, event)) {
397 click_count = last_click_event_->GetClickCount() + 1;
399 delete last_click_event_;
401 last_click_event_ = new MouseEvent(event);
402 last_click_complete_ = false;
403 if (click_count > 3)
404 click_count = 3;
405 last_click_event_->SetClickCount(click_count);
406 return click_count;
409 void MouseEvent::ResetLastClickForTest() {
410 if (last_click_event_) {
411 delete last_click_event_;
412 last_click_event_ = NULL;
413 last_click_complete_ = false;
417 // static
418 MouseEvent* MouseEvent::last_click_event_ = NULL;
419 bool MouseEvent::last_click_complete_ = false;
421 int MouseEvent::GetClickCount() const {
422 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
423 return 0;
425 if (flags() & EF_IS_TRIPLE_CLICK)
426 return 3;
427 else if (flags() & EF_IS_DOUBLE_CLICK)
428 return 2;
429 else
430 return 1;
433 void MouseEvent::SetClickCount(int click_count) {
434 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
435 return;
437 DCHECK(click_count > 0);
438 DCHECK(click_count <= 3);
440 int f = flags();
441 switch (click_count) {
442 case 1:
443 f &= ~EF_IS_DOUBLE_CLICK;
444 f &= ~EF_IS_TRIPLE_CLICK;
445 break;
446 case 2:
447 f |= EF_IS_DOUBLE_CLICK;
448 f &= ~EF_IS_TRIPLE_CLICK;
449 break;
450 case 3:
451 f &= ~EF_IS_DOUBLE_CLICK;
452 f |= EF_IS_TRIPLE_CLICK;
453 break;
455 set_flags(f);
458 ////////////////////////////////////////////////////////////////////////////////
459 // MouseWheelEvent
461 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
462 : MouseEvent(native_event),
463 offset_(GetMouseWheelOffset(native_event)) {
466 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
467 : MouseEvent(scroll_event),
468 offset_(gfx::ToRoundedInt(scroll_event.x_offset()),
469 gfx::ToRoundedInt(scroll_event.y_offset())) {
470 SetType(ET_MOUSEWHEEL);
473 MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
474 int x_offset,
475 int y_offset)
476 : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
477 DCHECK(type() == ET_MOUSEWHEEL);
480 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
481 : MouseEvent(mouse_wheel_event),
482 offset_(mouse_wheel_event.offset()) {
483 DCHECK(type() == ET_MOUSEWHEEL);
486 MouseWheelEvent::MouseWheelEvent(const gfx::Vector2d& offset,
487 const gfx::PointF& location,
488 const gfx::PointF& root_location,
489 base::TimeDelta time_stamp,
490 int flags,
491 int changed_button_flags)
492 : MouseEvent(ui::ET_MOUSEWHEEL,
493 location,
494 root_location,
495 time_stamp,
496 flags,
497 changed_button_flags),
498 offset_(offset) {
501 #if defined(OS_WIN)
502 // This value matches windows WHEEL_DELTA.
503 // static
504 const int MouseWheelEvent::kWheelDelta = 120;
505 #else
506 // This value matches GTK+ wheel scroll amount.
507 const int MouseWheelEvent::kWheelDelta = 53;
508 #endif
510 ////////////////////////////////////////////////////////////////////////////////
511 // TouchEvent
513 TouchEvent::TouchEvent(const base::NativeEvent& native_event)
514 : LocatedEvent(native_event),
515 touch_id_(GetTouchId(native_event)),
516 unique_event_id_(ui::GetNextTouchEventId()),
517 radius_x_(GetTouchRadiusX(native_event)),
518 radius_y_(GetTouchRadiusY(native_event)),
519 rotation_angle_(GetTouchAngle(native_event)),
520 force_(GetTouchForce(native_event)),
521 may_cause_scrolling_(false),
522 should_remove_native_touch_id_mapping_(false) {
523 latency()->AddLatencyNumberWithTimestamp(
524 INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0,
525 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1);
526 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
528 FixRotationAngle();
529 if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
530 should_remove_native_touch_id_mapping_ = true;
533 TouchEvent::TouchEvent(EventType type,
534 const gfx::PointF& location,
535 int touch_id,
536 base::TimeDelta time_stamp)
537 : LocatedEvent(type, location, location, time_stamp, 0),
538 touch_id_(touch_id),
539 unique_event_id_(ui::GetNextTouchEventId()),
540 radius_x_(0.0f),
541 radius_y_(0.0f),
542 rotation_angle_(0.0f),
543 force_(0.0f),
544 may_cause_scrolling_(false),
545 should_remove_native_touch_id_mapping_(false) {
546 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
549 TouchEvent::TouchEvent(EventType type,
550 const gfx::PointF& location,
551 int flags,
552 int touch_id,
553 base::TimeDelta time_stamp,
554 float radius_x,
555 float radius_y,
556 float angle,
557 float force)
558 : LocatedEvent(type, location, location, time_stamp, flags),
559 touch_id_(touch_id),
560 unique_event_id_(ui::GetNextTouchEventId()),
561 radius_x_(radius_x),
562 radius_y_(radius_y),
563 rotation_angle_(angle),
564 force_(force),
565 may_cause_scrolling_(false),
566 should_remove_native_touch_id_mapping_(false) {
567 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
568 FixRotationAngle();
571 TouchEvent::TouchEvent(const TouchEvent& copy)
572 : LocatedEvent(copy),
573 touch_id_(copy.touch_id_),
574 unique_event_id_(copy.unique_event_id_),
575 radius_x_(copy.radius_x_),
576 radius_y_(copy.radius_y_),
577 rotation_angle_(copy.rotation_angle_),
578 force_(copy.force_),
579 may_cause_scrolling_(copy.may_cause_scrolling_),
580 should_remove_native_touch_id_mapping_(false) {
581 // Copied events should not remove touch id mapping, as this either causes the
582 // mapping to be lost before the initial event has finished dispatching, or
583 // the copy to attempt to remove the mapping from a null |native_event_|.
586 TouchEvent::~TouchEvent() {
587 // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
588 // platform setups the tracking_id to slot mapping. So in dtor here,
589 // if this touch event is a release event, we clear the mapping accordingly.
590 if (should_remove_native_touch_id_mapping_) {
591 DCHECK(type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED);
592 if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
593 ClearTouchIdIfReleased(native_event());
597 void TouchEvent::UpdateForRootTransform(
598 const gfx::Transform& inverted_root_transform) {
599 LocatedEvent::UpdateForRootTransform(inverted_root_transform);
600 gfx::DecomposedTransform decomp;
601 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
602 DCHECK(success);
603 if (decomp.scale[0])
604 radius_x_ *= decomp.scale[0];
605 if (decomp.scale[1])
606 radius_y_ *= decomp.scale[1];
609 void TouchEvent::DisableSynchronousHandling() {
610 DispatcherApi dispatcher_api(this);
611 dispatcher_api.set_result(
612 static_cast<EventResult>(result() | ER_DISABLE_SYNC_HANDLING));
615 void TouchEvent::FixRotationAngle() {
616 while (rotation_angle_ < 0)
617 rotation_angle_ += 180;
618 while (rotation_angle_ >= 180)
619 rotation_angle_ -= 180;
622 ////////////////////////////////////////////////////////////////////////////////
623 // KeyEvent
625 // static
626 KeyEvent* KeyEvent::last_key_event_ = NULL;
628 // static
629 bool KeyEvent::IsRepeated(const KeyEvent& event) {
630 // A safe guard in case if there were continous key pressed events that are
631 // not auto repeat.
632 const int kMaxAutoRepeatTimeMs = 2000;
633 // Ignore key events that have non standard state masks as it may be
634 // reposted by an IME. IBUS-GTK uses this field to detect the
635 // re-posted event for example. crbug.com/385873.
636 if (X11EventHasNonStandardState(event.native_event()))
637 return false;
638 if (event.is_char())
639 return false;
640 if (event.type() == ui::ET_KEY_RELEASED) {
641 delete last_key_event_;
642 last_key_event_ = NULL;
643 return false;
645 CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
646 if (!last_key_event_) {
647 last_key_event_ = new KeyEvent(event);
648 return false;
649 } else if (event.time_stamp() == last_key_event_->time_stamp()) {
650 // The KeyEvent is created from the same native event.
651 return (last_key_event_->flags() & ui::EF_IS_REPEAT) != 0;
653 if (event.key_code() == last_key_event_->key_code() &&
654 event.flags() == (last_key_event_->flags() & ~ui::EF_IS_REPEAT) &&
655 (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() <
656 kMaxAutoRepeatTimeMs) {
657 last_key_event_->set_time_stamp(event.time_stamp());
658 last_key_event_->set_flags(last_key_event_->flags() | ui::EF_IS_REPEAT);
659 return true;
661 delete last_key_event_;
662 last_key_event_ = new KeyEvent(event);
663 return false;
666 KeyEvent::KeyEvent(const base::NativeEvent& native_event)
667 : Event(native_event,
668 EventTypeFromNative(native_event),
669 EventFlagsFromNative(native_event)),
670 key_code_(KeyboardCodeFromNative(native_event)),
671 code_(CodeFromNative(native_event)),
672 is_char_(IsCharFromNative(native_event)),
673 platform_keycode_(PlatformKeycodeFromNative(native_event)),
674 key_(DomKey::NONE),
675 character_(0) {
676 if (IsRepeated(*this))
677 set_flags(flags() | ui::EF_IS_REPEAT);
679 #if defined(USE_X11)
680 NormalizeFlags();
681 #endif
682 #if defined(OS_WIN)
683 // Only Windows has native character events.
684 if (is_char_)
685 character_ = native_event.wParam;
686 #endif
689 KeyEvent::KeyEvent(EventType type,
690 KeyboardCode key_code,
691 int flags)
692 : Event(type, EventTimeForNow(), flags),
693 key_code_(key_code),
694 code_(UsLayoutKeyboardCodeToDomCode(key_code)),
695 is_char_(false),
696 platform_keycode_(0),
697 key_(DomKey::NONE),
698 character_() {
701 KeyEvent::KeyEvent(EventType type,
702 KeyboardCode key_code,
703 DomCode code,
704 int flags)
705 : Event(type, EventTimeForNow(), flags),
706 key_code_(key_code),
707 code_(code),
708 is_char_(false),
709 platform_keycode_(0),
710 key_(DomKey::NONE),
711 character_(0) {
714 KeyEvent::KeyEvent(EventType type,
715 KeyboardCode key_code,
716 DomCode code,
717 int flags,
718 DomKey key,
719 base::char16 character,
720 base::TimeDelta time_stamp)
721 : Event(type, time_stamp, flags),
722 key_code_(key_code),
723 code_(code),
724 is_char_(false),
725 platform_keycode_(0),
726 key_(key),
727 character_(character) {
730 KeyEvent::KeyEvent(base::char16 character, KeyboardCode key_code, int flags)
731 : Event(ET_KEY_PRESSED, EventTimeForNow(), flags),
732 key_code_(key_code),
733 code_(DomCode::NONE),
734 is_char_(true),
735 platform_keycode_(0),
736 key_(DomKey::CHARACTER),
737 character_(character) {
740 KeyEvent::KeyEvent(const KeyEvent& rhs)
741 : Event(rhs),
742 key_code_(rhs.key_code_),
743 code_(rhs.code_),
744 is_char_(rhs.is_char_),
745 platform_keycode_(rhs.platform_keycode_),
746 key_(rhs.key_),
747 character_(rhs.character_) {
748 if (rhs.extended_key_event_data_)
749 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
752 KeyEvent& KeyEvent::operator=(const KeyEvent& rhs) {
753 if (this != &rhs) {
754 Event::operator=(rhs);
755 key_code_ = rhs.key_code_;
756 code_ = rhs.code_;
757 key_ = rhs.key_;
758 is_char_ = rhs.is_char_;
759 platform_keycode_ = rhs.platform_keycode_;
760 character_ = rhs.character_;
762 if (rhs.extended_key_event_data_)
763 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
765 return *this;
768 KeyEvent::~KeyEvent() {}
770 void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) {
771 extended_key_event_data_ = data.Pass();
774 void KeyEvent::ApplyLayout() const {
775 // If the client has set the character (e.g. faked key events from virtual
776 // keyboard), it's client's responsibility to set the dom key correctly.
777 // Otherwise, set the dom key as unidentified.
778 // Please refer to crbug.com/443889.
779 if (character_ != 0) {
780 key_ = DomKey::UNIDENTIFIED;
781 return;
783 ui::DomCode code = code_;
784 if (code == DomCode::NONE) {
785 // Catch old code that tries to do layout without a physical key, and try
786 // to recover using the KeyboardCode. Once key events are fully defined
787 // on construction (see TODO in event.h) this will go away.
788 LOG(WARNING) << "DomCode::NONE keycode=" << key_code_;
789 code = UsLayoutKeyboardCodeToDomCode(key_code_);
790 if (code == DomCode::NONE) {
791 key_ = DomKey::UNIDENTIFIED;
792 return;
795 KeyboardCode dummy_key_code;
796 #if defined(OS_WIN)
797 // Native Windows character events always have is_char_ == true,
798 // so this is a synthetic or native keystroke event.
799 // Therefore, perform only the fallback action.
800 #elif defined(USE_X11)
801 // When a control key is held, prefer ASCII characters to non ASCII
802 // characters in order to use it for shortcut keys. GetCharacterFromKeyCode
803 // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
804 // GetCharacterFromXEvent returns 'à' in that case.
805 if (!IsControlDown() && native_event()) {
806 GetMeaningFromXEvent(native_event(), &key_, &character_);
807 return;
809 #elif defined(USE_OZONE)
810 if (KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
811 code, flags(), &key_, &character_, &dummy_key_code,
812 &platform_keycode_)) {
813 return;
815 #else
816 if (native_event()) {
817 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
818 EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
820 #endif
821 if (!DomCodeToUsLayoutMeaning(code, flags(), &key_, &character_,
822 &dummy_key_code)) {
823 key_ = DomKey::UNIDENTIFIED;
827 DomKey KeyEvent::GetDomKey() const {
828 // Determination of character_ and key_ may be done lazily.
829 if (key_ == DomKey::NONE)
830 ApplyLayout();
831 return key_;
834 base::char16 KeyEvent::GetCharacter() const {
835 // Determination of character_ and key_ may be done lazily.
836 if (key_ == DomKey::NONE)
837 ApplyLayout();
838 return character_;
841 base::char16 KeyEvent::GetText() const {
842 if ((flags() & EF_CONTROL_DOWN) != 0) {
843 base::char16 character;
844 ui::DomKey key;
845 ui::KeyboardCode key_code;
846 if (DomCodeToControlCharacter(code_, flags(), &key, &character, &key_code))
847 return character;
849 return GetUnmodifiedText();
852 base::char16 KeyEvent::GetUnmodifiedText() const {
853 if (!is_char_ && (key_code_ == VKEY_RETURN))
854 return '\r';
855 return GetCharacter();
858 bool KeyEvent::IsUnicodeKeyCode() const {
859 #if defined(OS_WIN)
860 if (!IsAltDown())
861 return false;
862 const int key = key_code();
863 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
864 return true;
865 // Check whether the user is using the numeric keypad with num-lock off.
866 // In that case, EF_EXTENDED will not be set; if it is set, the key event
867 // originated from the relevant non-numpad dedicated key, e.g. [Insert].
868 return (!(flags() & EF_EXTENDED) &&
869 (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN ||
870 key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR ||
871 key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP ||
872 key == VKEY_PRIOR));
873 #else
874 return false;
875 #endif
878 void KeyEvent::NormalizeFlags() {
879 int mask = 0;
880 switch (key_code()) {
881 case VKEY_CONTROL:
882 mask = EF_CONTROL_DOWN;
883 break;
884 case VKEY_SHIFT:
885 mask = EF_SHIFT_DOWN;
886 break;
887 case VKEY_MENU:
888 mask = EF_ALT_DOWN;
889 break;
890 case VKEY_CAPITAL:
891 mask = EF_CAPS_LOCK_DOWN;
892 break;
893 default:
894 return;
896 if (type() == ET_KEY_PRESSED)
897 set_flags(flags() | mask);
898 else
899 set_flags(flags() & ~mask);
902 KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
903 return NonLocatedToLocatedKeyboardCode(key_code_, code_);
906 uint16 KeyEvent::GetConflatedWindowsKeyCode() const {
907 if (is_char_)
908 return character_;
909 return key_code_;
912 std::string KeyEvent::GetCodeString() const {
913 return KeycodeConverter::DomCodeToCodeString(code_);
916 ////////////////////////////////////////////////////////////////////////////////
917 // ScrollEvent
919 ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
920 : MouseEvent(native_event) {
921 if (type() == ET_SCROLL) {
922 GetScrollOffsets(native_event,
923 &x_offset_, &y_offset_,
924 &x_offset_ordinal_, &y_offset_ordinal_,
925 &finger_count_);
926 } else if (type() == ET_SCROLL_FLING_START ||
927 type() == ET_SCROLL_FLING_CANCEL) {
928 GetFlingData(native_event,
929 &x_offset_, &y_offset_,
930 &x_offset_ordinal_, &y_offset_ordinal_,
931 NULL);
932 } else {
933 NOTREACHED() << "Unexpected event type " << type()
934 << " when constructing a ScrollEvent.";
938 ScrollEvent::ScrollEvent(EventType type,
939 const gfx::PointF& location,
940 base::TimeDelta time_stamp,
941 int flags,
942 float x_offset,
943 float y_offset,
944 float x_offset_ordinal,
945 float y_offset_ordinal,
946 int finger_count)
947 : MouseEvent(type, location, location, time_stamp, flags, 0),
948 x_offset_(x_offset),
949 y_offset_(y_offset),
950 x_offset_ordinal_(x_offset_ordinal),
951 y_offset_ordinal_(y_offset_ordinal),
952 finger_count_(finger_count) {
953 CHECK(IsScrollEvent());
956 void ScrollEvent::Scale(const float factor) {
957 x_offset_ *= factor;
958 y_offset_ *= factor;
959 x_offset_ordinal_ *= factor;
960 y_offset_ordinal_ *= factor;
963 ////////////////////////////////////////////////////////////////////////////////
964 // GestureEvent
966 GestureEvent::GestureEvent(float x,
967 float y,
968 int flags,
969 base::TimeDelta time_stamp,
970 const GestureEventDetails& details)
971 : LocatedEvent(details.type(),
972 gfx::PointF(x, y),
973 gfx::PointF(x, y),
974 time_stamp,
975 flags | EF_FROM_TOUCH),
976 details_(details) {
979 GestureEvent::~GestureEvent() {
982 } // namespace ui