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>
9 #include <X11/keysym.h>
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"
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"
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
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
);
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.
92 bool IsX11SendEventTrue(const base::NativeEvent
& event
) {
94 return event
&& event
->xany
.send_event
;
100 bool X11EventHasNonStandardState(const base::NativeEvent
& event
) {
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;
116 ////////////////////////////////////////////////////////////////////////////////
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
));
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
177 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
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
185 // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
187 result_
= static_cast<EventResult
>(result_
| ER_HANDLED
);
190 Event::Event(EventType type
, base::TimeDelta time_stamp
, int flags
)
192 time_stamp_(time_stamp
),
194 native_event_(base::NativeEvent()),
195 delete_native_event_(false),
198 phase_(EP_PREDISPATCH
),
199 result_(ER_UNHANDLED
),
200 source_device_id_(ED_UNKNOWN_DEVICE
) {
202 name_
= EventTypeName(type_
);
205 Event::Event(const base::NativeEvent
& native_event
,
209 time_stamp_(EventTimeFromNative(native_event
)),
211 native_event_(native_event
),
212 delete_native_event_(false),
215 phase_(EP_PREDISPATCH
),
216 result_(ER_UNHANDLED
),
217 source_device_id_(ED_UNKNOWN_DEVICE
) {
218 base::TimeDelta delta
= EventTimeForNow() - time_stamp_
;
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,
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(
233 base::HistogramBase::kUmaTargetedHistogramFlag
);
234 counter_for_type
->Add(delta_sample
);
237 if (native_event
->type
== GenericEvent
) {
238 XIDeviceEvent
* xiev
=
239 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
240 source_device_id_
= xiev
->sourceid
;
243 #if defined(USE_OZONE)
245 static_cast<const Event
*>(native_event
)->source_device_id();
249 Event::Event(const Event
& copy
)
251 time_stamp_(copy
.time_stamp_
),
252 latency_(copy
.latency_
),
254 native_event_(CopyNativeEvent(copy
.native_event_
)),
255 delete_native_event_(true),
258 phase_(EP_PREDISPATCH
),
259 result_(ER_UNHANDLED
),
260 source_device_id_(copy
.source_device_id_
) {
262 name_
= EventTypeName(type_
);
265 void Event::SetType(EventType type
) {
267 name_
= std::string();
270 name_
= EventTypeName(type_
);
273 ////////////////////////////////////////////////////////////////////////////////
276 CancelModeEvent::CancelModeEvent()
277 : Event(ET_CANCEL_MODE
, base::TimeDelta(), 0) {
278 set_cancelable(false);
281 CancelModeEvent::~CancelModeEvent() {
284 ////////////////////////////////////////////////////////////////////////////////
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
,
303 : Event(type
, time_stamp
, flags
),
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 ////////////////////////////////////////////////////////////////////////////////
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
,
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
);
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
)
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
))
359 // The new event has been created from the same native event.
360 if (event1
.time_stamp() == event2
.time_stamp())
363 base::TimeDelta time_difference
= event2
.time_stamp() - event1
.time_stamp();
365 if (time_difference
.InMilliseconds() > kDoubleClickTimeMS
)
368 if (std::abs(event2
.x() - event1
.x()) > kDoubleClickWidth
/ 2)
371 if (std::abs(event2
.y() - event1
.y()) > kDoubleClickHeight
/ 2)
378 int MouseEvent::GetRepeatCount(const MouseEvent
& event
) {
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();
387 // If last_click_event_ has changed since this button was pressed
388 // return a click count of 1.
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;
406 last_click_event_
->SetClickCount(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;
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
)
426 if (flags() & EF_IS_TRIPLE_CLICK
)
428 else if (flags() & EF_IS_DOUBLE_CLICK
)
434 void MouseEvent::SetClickCount(int click_count
) {
435 if (type() != ET_MOUSE_PRESSED
&& type() != ET_MOUSE_RELEASED
)
438 DCHECK(click_count
> 0);
439 DCHECK(click_count
<= 3);
442 switch (click_count
) {
444 f
&= ~EF_IS_DOUBLE_CLICK
;
445 f
&= ~EF_IS_TRIPLE_CLICK
;
448 f
|= EF_IS_DOUBLE_CLICK
;
449 f
&= ~EF_IS_TRIPLE_CLICK
;
452 f
&= ~EF_IS_DOUBLE_CLICK
;
453 f
|= EF_IS_TRIPLE_CLICK
;
459 ////////////////////////////////////////////////////////////////////////////////
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
,
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
,
492 int changed_button_flags
)
493 : MouseEvent(ui::ET_MOUSEWHEEL
,
498 changed_button_flags
),
503 // This value matches windows WHEEL_DELTA.
505 const int MouseWheelEvent::kWheelDelta
= 120;
507 // This value matches GTK+ wheel scroll amount.
508 const int MouseWheelEvent::kWheelDelta
= 53;
511 ////////////////////////////////////////////////////////////////////////////////
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
),
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);
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
,
540 base::TimeDelta time_stamp
)
541 : LocatedEvent(type
, location
, location
, time_stamp
, 0),
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
,
555 base::TimeDelta time_stamp
,
560 : LocatedEvent(type
, location
, location
, time_stamp
, flags
),
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
,
571 /* tilt_y */ 0.0f
)) {
572 latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT
, 0, 0);
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
);
607 pointer_details_
.radius_x_
*= decomp
.scale
[0];
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 ////////////////////////////////////////////////////////////////////////////////
629 KeyEvent
* KeyEvent::last_key_event_
= NULL
;
632 bool KeyEvent::IsRepeated(const KeyEvent
& event
) {
633 // A safe guard in case if there were continous key pressed events that are
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()))
643 if (event
.type() == ui::ET_KEY_RELEASED
) {
644 delete last_key_event_
;
645 last_key_event_
= NULL
;
648 CHECK_EQ(ui::ET_KEY_PRESSED
, event
.type());
649 if (!last_key_event_
) {
650 last_key_event_
= new KeyEvent(event
);
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
);
664 delete last_key_event_
;
665 last_key_event_
= new KeyEvent(event
);
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
);
684 // Only Windows has native character events.
686 key_
= DomKey::FromCharacter(native_event
.wParam
);
690 KeyEvent::KeyEvent(EventType type
,
691 KeyboardCode key_code
,
693 : Event(type
, EventTimeForNow(), flags
),
695 code_(UsLayoutKeyboardCodeToDomCode(key_code
)) {
698 KeyEvent::KeyEvent(EventType type
,
699 KeyboardCode key_code
,
702 : Event(type
, EventTimeForNow(), flags
),
707 KeyEvent::KeyEvent(EventType type
,
708 KeyboardCode key_code
,
712 base::TimeDelta time_stamp
)
713 : Event(type
, time_stamp
, flags
),
719 KeyEvent::KeyEvent(base::char16 character
, KeyboardCode key_code
, int flags
)
720 : Event(ET_KEY_PRESSED
, EventTimeForNow(), flags
),
722 code_(DomCode::NONE
),
724 key_(DomKey::FromCharacter(character
)) {
727 KeyEvent::KeyEvent(const KeyEvent
& rhs
)
729 key_code_(rhs
.key_code_
),
731 is_char_(rhs
.is_char_
),
732 platform_keycode_(rhs
.platform_keycode_
),
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
) {
740 Event::operator=(rhs
);
741 key_code_
= rhs
.key_code_
;
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());
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
;
772 KeyboardCode dummy_key_code
;
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());
786 #elif defined(USE_OZONE)
787 if (KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
788 code
, flags(), &key_
, &dummy_key_code
, &platform_keycode_
)) {
792 if (native_event()) {
793 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED
||
794 EventTypeFromNative(native_event()) == ET_KEY_RELEASED
);
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
)
808 base::char16
KeyEvent::GetCharacter() const {
809 // Determination of key_ may be done lazily.
810 if (key_
== DomKey::NONE
)
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
;
823 base::char16
KeyEvent::GetText() const {
824 if ((flags() & EF_CONTROL_DOWN
) != 0) {
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
))
836 return GetCharacter();
839 bool KeyEvent::IsUnicodeKeyCode() const {
843 const int key
= key_code();
844 if (key
>= VKEY_NUMPAD0
&& key
<= VKEY_NUMPAD9
)
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
||
859 void KeyEvent::NormalizeFlags() {
861 switch (key_code()) {
863 mask
= EF_CONTROL_DOWN
;
866 mask
= EF_SHIFT_DOWN
;
872 mask
= EF_CAPS_LOCK_DOWN
;
877 if (type() == ET_KEY_PRESSED
)
878 set_flags(flags() | mask
);
880 set_flags(flags() & ~mask
);
883 KeyboardCode
KeyEvent::GetLocatedWindowsKeyboardCode() const {
884 return NonLocatedToLocatedKeyboardCode(key_code_
, code_
);
887 uint16
KeyEvent::GetConflatedWindowsKeyCode() const {
889 return key_
.ToCharacter();
893 std::string
KeyEvent::GetCodeString() const {
894 return KeycodeConverter::DomCodeToCodeString(code_
);
897 ////////////////////////////////////////////////////////////////////////////////
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_
,
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_
,
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
,
925 float x_offset_ordinal
,
926 float y_offset_ordinal
,
928 : MouseEvent(type
, location
, location
, time_stamp
, flags
, 0),
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
) {
940 x_offset_ordinal_
*= factor
;
941 y_offset_ordinal_
*= factor
;
944 ////////////////////////////////////////////////////////////////////////////////
947 GestureEvent::GestureEvent(float x
,
950 base::TimeDelta time_stamp
,
951 const GestureEventDetails
& details
)
952 : LocatedEvent(details
.type(),
956 flags
| EF_FROM_TOUCH
),
960 GestureEvent::~GestureEvent() {