MD Downloads: prevent search text from overlapping with the cancel search (X)
[chromium-blink-merge.git] / ui / events / event.cc
blob383e3736c38c42bdcff6b8159ad1576170982421
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_(GetChangedMouseButtonFlagsFromNative(native_event)),
323 pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_MOUSE)) {
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 pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_MOUSE)) {
337 if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
338 SetType(ET_MOUSE_DRAGGED);
341 // static
342 bool MouseEvent::IsRepeatedClickEvent(
343 const MouseEvent& event1,
344 const MouseEvent& event2) {
345 // These values match the Windows defaults.
346 static const int kDoubleClickTimeMS = 500;
347 static const int kDoubleClickWidth = 4;
348 static const int kDoubleClickHeight = 4;
350 if (event1.type() != ET_MOUSE_PRESSED ||
351 event2.type() != ET_MOUSE_PRESSED)
352 return false;
354 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
355 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
356 (event2.flags() & ~EF_IS_DOUBLE_CLICK))
357 return false;
359 // The new event has been created from the same native event.
360 if (event1.time_stamp() == event2.time_stamp())
361 return false;
363 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
365 if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
366 return false;
368 if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
369 return false;
371 if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
372 return false;
374 return true;
377 // static
378 int MouseEvent::GetRepeatCount(const MouseEvent& event) {
379 int click_count = 1;
380 if (last_click_event_) {
381 if (event.type() == ui::ET_MOUSE_RELEASED) {
382 if (event.changed_button_flags() ==
383 last_click_event_->changed_button_flags()) {
384 last_click_complete_ = true;
385 return last_click_event_->GetClickCount();
386 } else {
387 // If last_click_event_ has changed since this button was pressed
388 // return a click count of 1.
389 return click_count;
392 if (event.time_stamp() != last_click_event_->time_stamp())
393 last_click_complete_ = true;
394 if (!last_click_complete_ ||
395 IsX11SendEventTrue(event.native_event())) {
396 click_count = last_click_event_->GetClickCount();
397 } else if (IsRepeatedClickEvent(*last_click_event_, event)) {
398 click_count = last_click_event_->GetClickCount() + 1;
400 delete last_click_event_;
402 last_click_event_ = new MouseEvent(event);
403 last_click_complete_ = false;
404 if (click_count > 3)
405 click_count = 3;
406 last_click_event_->SetClickCount(click_count);
407 return click_count;
410 void MouseEvent::ResetLastClickForTest() {
411 if (last_click_event_) {
412 delete last_click_event_;
413 last_click_event_ = NULL;
414 last_click_complete_ = false;
418 // static
419 MouseEvent* MouseEvent::last_click_event_ = NULL;
420 bool MouseEvent::last_click_complete_ = false;
422 int MouseEvent::GetClickCount() const {
423 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
424 return 0;
426 if (flags() & EF_IS_TRIPLE_CLICK)
427 return 3;
428 else if (flags() & EF_IS_DOUBLE_CLICK)
429 return 2;
430 else
431 return 1;
434 void MouseEvent::SetClickCount(int click_count) {
435 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
436 return;
438 DCHECK(click_count > 0);
439 DCHECK(click_count <= 3);
441 int f = flags();
442 switch (click_count) {
443 case 1:
444 f &= ~EF_IS_DOUBLE_CLICK;
445 f &= ~EF_IS_TRIPLE_CLICK;
446 break;
447 case 2:
448 f |= EF_IS_DOUBLE_CLICK;
449 f &= ~EF_IS_TRIPLE_CLICK;
450 break;
451 case 3:
452 f &= ~EF_IS_DOUBLE_CLICK;
453 f |= EF_IS_TRIPLE_CLICK;
454 break;
456 set_flags(f);
459 ////////////////////////////////////////////////////////////////////////////////
460 // MouseWheelEvent
462 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
463 : MouseEvent(native_event),
464 offset_(GetMouseWheelOffset(native_event)) {
467 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
468 : MouseEvent(scroll_event),
469 offset_(gfx::ToRoundedInt(scroll_event.x_offset()),
470 gfx::ToRoundedInt(scroll_event.y_offset())) {
471 SetType(ET_MOUSEWHEEL);
474 MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
475 int x_offset,
476 int y_offset)
477 : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
478 DCHECK(type() == ET_MOUSEWHEEL);
481 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
482 : MouseEvent(mouse_wheel_event),
483 offset_(mouse_wheel_event.offset()) {
484 DCHECK(type() == ET_MOUSEWHEEL);
487 MouseWheelEvent::MouseWheelEvent(const gfx::Vector2d& offset,
488 const gfx::PointF& location,
489 const gfx::PointF& root_location,
490 base::TimeDelta time_stamp,
491 int flags,
492 int changed_button_flags)
493 : MouseEvent(ui::ET_MOUSEWHEEL,
494 location,
495 root_location,
496 time_stamp,
497 flags,
498 changed_button_flags),
499 offset_(offset) {
502 #if defined(OS_WIN)
503 // This value matches windows WHEEL_DELTA.
504 // static
505 const int MouseWheelEvent::kWheelDelta = 120;
506 #else
507 // This value matches GTK+ wheel scroll amount.
508 const int MouseWheelEvent::kWheelDelta = 53;
509 #endif
511 ////////////////////////////////////////////////////////////////////////////////
512 // TouchEvent
514 TouchEvent::TouchEvent(const base::NativeEvent& native_event)
515 : LocatedEvent(native_event),
516 touch_id_(GetTouchId(native_event)),
517 unique_event_id_(ui::GetNextTouchEventId()),
518 rotation_angle_(GetTouchAngle(native_event)),
519 may_cause_scrolling_(false),
520 should_remove_native_touch_id_mapping_(false),
521 pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_TOUCH,
522 GetTouchRadiusX(native_event),
523 GetTouchRadiusY(native_event),
524 GetTouchForce(native_event),
525 /* tilt_x */ 0.0f,
526 /* tilt_y */ 0.0f)) {
527 latency()->AddLatencyNumberWithTimestamp(
528 INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0,
529 base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1);
530 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
532 FixRotationAngle();
533 if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
534 should_remove_native_touch_id_mapping_ = true;
537 TouchEvent::TouchEvent(EventType type,
538 const gfx::PointF& location,
539 int touch_id,
540 base::TimeDelta time_stamp)
541 : LocatedEvent(type, location, location, time_stamp, 0),
542 touch_id_(touch_id),
543 unique_event_id_(ui::GetNextTouchEventId()),
544 rotation_angle_(0.0f),
545 may_cause_scrolling_(false),
546 should_remove_native_touch_id_mapping_(false),
547 pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_TOUCH)) {
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_(ui::GetNextTouchEventId()),
563 rotation_angle_(angle),
564 may_cause_scrolling_(false),
565 should_remove_native_touch_id_mapping_(false),
566 pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_TOUCH,
567 radius_x,
568 radius_y,
569 force,
570 /* tilt_x */ 0.0f,
571 /* tilt_y */ 0.0f)) {
572 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
573 FixRotationAngle();
576 TouchEvent::TouchEvent(const TouchEvent& copy)
577 : LocatedEvent(copy),
578 touch_id_(copy.touch_id_),
579 unique_event_id_(copy.unique_event_id_),
580 rotation_angle_(copy.rotation_angle_),
581 may_cause_scrolling_(copy.may_cause_scrolling_),
582 should_remove_native_touch_id_mapping_(false),
583 pointer_details_(copy.pointer_details_) {
584 // Copied events should not remove touch id mapping, as this either causes the
585 // mapping to be lost before the initial event has finished dispatching, or
586 // the copy to attempt to remove the mapping from a null |native_event_|.
589 TouchEvent::~TouchEvent() {
590 // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
591 // platform setups the tracking_id to slot mapping. So in dtor here,
592 // if this touch event is a release event, we clear the mapping accordingly.
593 if (should_remove_native_touch_id_mapping_) {
594 DCHECK(type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED);
595 if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
596 ClearTouchIdIfReleased(native_event());
600 void TouchEvent::UpdateForRootTransform(
601 const gfx::Transform& inverted_root_transform) {
602 LocatedEvent::UpdateForRootTransform(inverted_root_transform);
603 gfx::DecomposedTransform decomp;
604 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
605 DCHECK(success);
606 if (decomp.scale[0])
607 pointer_details_.radius_x_ *= decomp.scale[0];
608 if (decomp.scale[1])
609 pointer_details_.radius_y_ *= decomp.scale[1];
612 void TouchEvent::DisableSynchronousHandling() {
613 DispatcherApi dispatcher_api(this);
614 dispatcher_api.set_result(
615 static_cast<EventResult>(result() | ER_DISABLE_SYNC_HANDLING));
618 void TouchEvent::FixRotationAngle() {
619 while (rotation_angle_ < 0)
620 rotation_angle_ += 180;
621 while (rotation_angle_ >= 180)
622 rotation_angle_ -= 180;
625 ////////////////////////////////////////////////////////////////////////////////
626 // KeyEvent
628 // static
629 KeyEvent* KeyEvent::last_key_event_ = NULL;
631 // static
632 bool KeyEvent::IsRepeated(const KeyEvent& event) {
633 // A safe guard in case if there were continous key pressed events that are
634 // not auto repeat.
635 const int kMaxAutoRepeatTimeMs = 2000;
636 // Ignore key events that have non standard state masks as it may be
637 // reposted by an IME. IBUS-GTK uses this field to detect the
638 // re-posted event for example. crbug.com/385873.
639 if (X11EventHasNonStandardState(event.native_event()))
640 return false;
641 if (event.is_char())
642 return false;
643 if (event.type() == ui::ET_KEY_RELEASED) {
644 delete last_key_event_;
645 last_key_event_ = NULL;
646 return false;
648 CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
649 if (!last_key_event_) {
650 last_key_event_ = new KeyEvent(event);
651 return false;
652 } else if (event.time_stamp() == last_key_event_->time_stamp()) {
653 // The KeyEvent is created from the same native event.
654 return (last_key_event_->flags() & ui::EF_IS_REPEAT) != 0;
656 if (event.key_code() == last_key_event_->key_code() &&
657 event.flags() == (last_key_event_->flags() & ~ui::EF_IS_REPEAT) &&
658 (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() <
659 kMaxAutoRepeatTimeMs) {
660 last_key_event_->set_time_stamp(event.time_stamp());
661 last_key_event_->set_flags(last_key_event_->flags() | ui::EF_IS_REPEAT);
662 return true;
664 delete last_key_event_;
665 last_key_event_ = new KeyEvent(event);
666 return false;
669 KeyEvent::KeyEvent(const base::NativeEvent& native_event)
670 : Event(native_event,
671 EventTypeFromNative(native_event),
672 EventFlagsFromNative(native_event)),
673 key_code_(KeyboardCodeFromNative(native_event)),
674 code_(CodeFromNative(native_event)),
675 is_char_(IsCharFromNative(native_event)),
676 platform_keycode_(PlatformKeycodeFromNative(native_event)) {
677 if (IsRepeated(*this))
678 set_flags(flags() | ui::EF_IS_REPEAT);
680 #if defined(USE_X11)
681 NormalizeFlags();
682 #endif
683 #if defined(OS_WIN)
684 // Only Windows has native character events.
685 if (is_char_)
686 key_ = DomKey::FromCharacter(native_event.wParam);
687 #endif
690 KeyEvent::KeyEvent(EventType type,
691 KeyboardCode key_code,
692 int flags)
693 : Event(type, EventTimeForNow(), flags),
694 key_code_(key_code),
695 code_(UsLayoutKeyboardCodeToDomCode(key_code)) {
698 KeyEvent::KeyEvent(EventType type,
699 KeyboardCode key_code,
700 DomCode code,
701 int flags)
702 : Event(type, EventTimeForNow(), flags),
703 key_code_(key_code),
704 code_(code) {
707 KeyEvent::KeyEvent(EventType type,
708 KeyboardCode key_code,
709 DomCode code,
710 int flags,
711 DomKey key,
712 base::TimeDelta time_stamp)
713 : Event(type, time_stamp, flags),
714 key_code_(key_code),
715 code_(code),
716 key_(key) {
719 KeyEvent::KeyEvent(base::char16 character, KeyboardCode key_code, int flags)
720 : Event(ET_KEY_PRESSED, EventTimeForNow(), flags),
721 key_code_(key_code),
722 code_(DomCode::NONE),
723 is_char_(true),
724 key_(DomKey::FromCharacter(character)) {
727 KeyEvent::KeyEvent(const KeyEvent& rhs)
728 : Event(rhs),
729 key_code_(rhs.key_code_),
730 code_(rhs.code_),
731 is_char_(rhs.is_char_),
732 platform_keycode_(rhs.platform_keycode_),
733 key_(rhs.key_) {
734 if (rhs.extended_key_event_data_)
735 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
738 KeyEvent& KeyEvent::operator=(const KeyEvent& rhs) {
739 if (this != &rhs) {
740 Event::operator=(rhs);
741 key_code_ = rhs.key_code_;
742 code_ = rhs.code_;
743 key_ = rhs.key_;
744 is_char_ = rhs.is_char_;
745 platform_keycode_ = rhs.platform_keycode_;
747 if (rhs.extended_key_event_data_)
748 extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
750 return *this;
753 KeyEvent::~KeyEvent() {}
755 void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) {
756 extended_key_event_data_ = data.Pass();
759 void KeyEvent::ApplyLayout() const {
760 ui::DomCode code = code_;
761 if (code == DomCode::NONE) {
762 // Catch old code that tries to do layout without a physical key, and try
763 // to recover using the KeyboardCode. Once key events are fully defined
764 // on construction (see TODO in event.h) this will go away.
765 LOG(WARNING) << "DomCode::NONE keycode=" << key_code_;
766 code = UsLayoutKeyboardCodeToDomCode(key_code_);
767 if (code == DomCode::NONE) {
768 key_ = DomKey::UNIDENTIFIED;
769 return;
772 KeyboardCode dummy_key_code;
773 #if defined(OS_WIN)
774 // Native Windows character events always have is_char_ == true,
775 // so this is a synthetic or native keystroke event.
776 // Therefore, perform only the fallback action.
777 #elif defined(USE_X11)
778 // When a control key is held, prefer ASCII characters to non ASCII
779 // characters in order to use it for shortcut keys. GetCharacterFromKeyCode
780 // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
781 // GetCharacterFromXEvent returns 'à' in that case.
782 if (!IsControlDown() && native_event()) {
783 key_ = GetDomKeyFromXEvent(native_event());
784 return;
786 #elif defined(USE_OZONE)
787 if (KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
788 code, flags(), &key_, &dummy_key_code, &platform_keycode_)) {
789 return;
791 #else
792 if (native_event()) {
793 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
794 EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
796 #endif
797 if (!DomCodeToUsLayoutDomKey(code, flags(), &key_, &dummy_key_code))
798 key_ = DomKey::UNIDENTIFIED;
801 DomKey KeyEvent::GetDomKey() const {
802 // Determination of key_ may be done lazily.
803 if (key_ == DomKey::NONE)
804 ApplyLayout();
805 return key_;
808 base::char16 KeyEvent::GetCharacter() const {
809 // Determination of key_ may be done lazily.
810 if (key_ == DomKey::NONE)
811 ApplyLayout();
812 if (key_.IsCharacter()) {
813 // Historically ui::KeyEvent has held only BMP characters.
814 // Until this explicitly changes, require |key_| to hold a BMP character.
815 DomKey::Base utf32_character = key_.ToCharacter();
816 base::char16 ucs2_character = static_cast<base::char16>(utf32_character);
817 DCHECK(static_cast<DomKey::Base>(ucs2_character) == utf32_character);
818 return ucs2_character;
820 return 0;
823 base::char16 KeyEvent::GetText() const {
824 if ((flags() & EF_CONTROL_DOWN) != 0) {
825 ui::DomKey key;
826 ui::KeyboardCode key_code;
827 if (DomCodeToControlCharacter(code_, flags(), &key, &key_code))
828 return key.ToCharacter();
830 return GetUnmodifiedText();
833 base::char16 KeyEvent::GetUnmodifiedText() const {
834 if (!is_char_ && (key_code_ == VKEY_RETURN))
835 return '\r';
836 return GetCharacter();
839 bool KeyEvent::IsUnicodeKeyCode() const {
840 #if defined(OS_WIN)
841 if (!IsAltDown())
842 return false;
843 const int key = key_code();
844 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
845 return true;
846 // Check whether the user is using the numeric keypad with num-lock off.
847 // In that case, EF_EXTENDED will not be set; if it is set, the key event
848 // originated from the relevant non-numpad dedicated key, e.g. [Insert].
849 return (!(flags() & EF_EXTENDED) &&
850 (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN ||
851 key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR ||
852 key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP ||
853 key == VKEY_PRIOR));
854 #else
855 return false;
856 #endif
859 void KeyEvent::NormalizeFlags() {
860 int mask = 0;
861 switch (key_code()) {
862 case VKEY_CONTROL:
863 mask = EF_CONTROL_DOWN;
864 break;
865 case VKEY_SHIFT:
866 mask = EF_SHIFT_DOWN;
867 break;
868 case VKEY_MENU:
869 mask = EF_ALT_DOWN;
870 break;
871 case VKEY_CAPITAL:
872 mask = EF_CAPS_LOCK_DOWN;
873 break;
874 default:
875 return;
877 if (type() == ET_KEY_PRESSED)
878 set_flags(flags() | mask);
879 else
880 set_flags(flags() & ~mask);
883 KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
884 return NonLocatedToLocatedKeyboardCode(key_code_, code_);
887 uint16 KeyEvent::GetConflatedWindowsKeyCode() const {
888 if (is_char_)
889 return key_.ToCharacter();
890 return key_code_;
893 std::string KeyEvent::GetCodeString() const {
894 return KeycodeConverter::DomCodeToCodeString(code_);
897 ////////////////////////////////////////////////////////////////////////////////
898 // ScrollEvent
900 ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
901 : MouseEvent(native_event) {
902 if (type() == ET_SCROLL) {
903 GetScrollOffsets(native_event,
904 &x_offset_, &y_offset_,
905 &x_offset_ordinal_, &y_offset_ordinal_,
906 &finger_count_);
907 } else if (type() == ET_SCROLL_FLING_START ||
908 type() == ET_SCROLL_FLING_CANCEL) {
909 GetFlingData(native_event,
910 &x_offset_, &y_offset_,
911 &x_offset_ordinal_, &y_offset_ordinal_,
912 NULL);
913 } else {
914 NOTREACHED() << "Unexpected event type " << type()
915 << " when constructing a ScrollEvent.";
919 ScrollEvent::ScrollEvent(EventType type,
920 const gfx::PointF& location,
921 base::TimeDelta time_stamp,
922 int flags,
923 float x_offset,
924 float y_offset,
925 float x_offset_ordinal,
926 float y_offset_ordinal,
927 int finger_count)
928 : MouseEvent(type, location, location, time_stamp, flags, 0),
929 x_offset_(x_offset),
930 y_offset_(y_offset),
931 x_offset_ordinal_(x_offset_ordinal),
932 y_offset_ordinal_(y_offset_ordinal),
933 finger_count_(finger_count) {
934 CHECK(IsScrollEvent());
937 void ScrollEvent::Scale(const float factor) {
938 x_offset_ *= factor;
939 y_offset_ *= factor;
940 x_offset_ordinal_ *= factor;
941 y_offset_ordinal_ *= factor;
944 ////////////////////////////////////////////////////////////////////////////////
945 // GestureEvent
947 GestureEvent::GestureEvent(float x,
948 float y,
949 int flags,
950 base::TimeDelta time_stamp,
951 const GestureEventDetails& details)
952 : LocatedEvent(details.type(),
953 gfx::PointF(x, y),
954 gfx::PointF(x, y),
955 time_stamp,
956 flags | EF_FROM_TOUCH),
957 details_(details) {
960 GestureEvent::~GestureEvent() {
963 } // namespace ui