Index: ui/events/event.cc |
diff --git a/ui/events/event.cc b/ui/events/event.cc |
index ebecbfe443b4de08793a46e5ff430a37cc79ce06..953220d0a634f1de2ae7ec3ca738dfc34a879839 100644 |
--- a/ui/events/event.cc |
+++ b/ui/events/event.cc |
@@ -6,22 +6,111 @@ |
#if defined(USE_X11) |
#include <X11/extensions/XInput2.h> |
-#include <X11/Xlib.h> |
#include <X11/keysym.h> |
+#include <X11/Xlib.h> |
#endif |
#include <cmath> |
#include <cstring> |
+#include "base/metrics/histogram.h" |
#include "base/strings/stringprintf.h" |
+#include "ui/events/base_event_utils.h" |
#include "ui/events/event_utils.h" |
+#include "ui/events/keycodes/dom/dom_code.h" |
+#include "ui/events/keycodes/dom/dom_key.h" |
+#include "ui/events/keycodes/dom/keycode_converter.h" |
#include "ui/events/keycodes/keyboard_code_conversion.h" |
+#include "ui/gfx/geometry/point3_f.h" |
+#include "ui/gfx/geometry/point_conversions.h" |
#include "ui/gfx/geometry/safe_integer_conversions.h" |
-#include "ui/gfx/point3_f.h" |
-#include "ui/gfx/point_conversions.h" |
#include "ui/gfx/transform.h" |
#include "ui/gfx/transform_util.h" |
+#if defined(USE_X11) |
+#include "ui/events/keycodes/keyboard_code_conversion_x.h" |
+#elif defined(USE_OZONE) |
+#include "ui/events/ozone/layout/keyboard_layout_engine.h" |
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" |
+#endif |
+ |
+namespace { |
+ |
+std::string EventTypeName(ui::EventType type) { |
+#define RETURN_IF_TYPE(t) if (type == ui::t) return #t |
+#define CASE_TYPE(t) case ui::t: return #t |
+ switch (type) { |
+ CASE_TYPE(ET_UNKNOWN); |
+ CASE_TYPE(ET_MOUSE_PRESSED); |
+ CASE_TYPE(ET_MOUSE_DRAGGED); |
+ CASE_TYPE(ET_MOUSE_RELEASED); |
+ CASE_TYPE(ET_MOUSE_MOVED); |
+ CASE_TYPE(ET_MOUSE_ENTERED); |
+ CASE_TYPE(ET_MOUSE_EXITED); |
+ CASE_TYPE(ET_KEY_PRESSED); |
+ CASE_TYPE(ET_KEY_RELEASED); |
+ CASE_TYPE(ET_MOUSEWHEEL); |
+ CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED); |
+ CASE_TYPE(ET_TOUCH_RELEASED); |
+ CASE_TYPE(ET_TOUCH_PRESSED); |
+ CASE_TYPE(ET_TOUCH_MOVED); |
+ CASE_TYPE(ET_TOUCH_CANCELLED); |
+ CASE_TYPE(ET_DROP_TARGET_EVENT); |
+ CASE_TYPE(ET_GESTURE_SCROLL_BEGIN); |
+ CASE_TYPE(ET_GESTURE_SCROLL_END); |
+ CASE_TYPE(ET_GESTURE_SCROLL_UPDATE); |
+ CASE_TYPE(ET_GESTURE_SHOW_PRESS); |
+ CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE); |
+ CASE_TYPE(ET_GESTURE_TAP); |
+ CASE_TYPE(ET_GESTURE_TAP_DOWN); |
+ CASE_TYPE(ET_GESTURE_TAP_CANCEL); |
+ CASE_TYPE(ET_GESTURE_BEGIN); |
+ CASE_TYPE(ET_GESTURE_END); |
+ CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP); |
+ CASE_TYPE(ET_GESTURE_PINCH_BEGIN); |
+ CASE_TYPE(ET_GESTURE_PINCH_END); |
+ CASE_TYPE(ET_GESTURE_PINCH_UPDATE); |
+ CASE_TYPE(ET_GESTURE_LONG_PRESS); |
+ CASE_TYPE(ET_GESTURE_LONG_TAP); |
+ CASE_TYPE(ET_GESTURE_SWIPE); |
+ CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED); |
+ CASE_TYPE(ET_GESTURE_DOUBLE_TAP); |
+ CASE_TYPE(ET_SCROLL); |
+ CASE_TYPE(ET_SCROLL_FLING_START); |
+ CASE_TYPE(ET_SCROLL_FLING_CANCEL); |
+ CASE_TYPE(ET_CANCEL_MODE); |
+ CASE_TYPE(ET_UMA_DATA); |
+ case ui::ET_LAST: NOTREACHED(); return std::string(); |
+ // Don't include default, so that we get an error when new type is added. |
+ } |
+#undef CASE_TYPE |
+ |
+ NOTREACHED(); |
+ return std::string(); |
+} |
+ |
+bool IsX11SendEventTrue(const base::NativeEvent& event) { |
+#if defined(USE_X11) |
+ return event && event->xany.send_event; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+bool X11EventHasNonStandardState(const base::NativeEvent& event) { |
+#if defined(USE_X11) |
+ const unsigned int kAllStateMask = |
+ Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask | |
+ Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | |
+ LockMask | ControlMask | AnyModifier; |
+ return event && (event->xkey.state & ~kAllStateMask) != 0; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+} // namespace |
+ |
namespace ui { |
//////////////////////////////////////////////////////////////////////////////// |
@@ -30,38 +119,40 @@ namespace ui { |
// static |
scoped_ptr<Event> Event::Clone(const Event& event) { |
if (event.IsKeyEvent()) { |
- return scoped_ptr<Event>(new KeyEvent(static_cast<const KeyEvent&>(event))); |
+ return make_scoped_ptr(new KeyEvent(static_cast<const KeyEvent&>(event))); |
} |
if (event.IsMouseEvent()) { |
if (event.IsMouseWheelEvent()) { |
- return scoped_ptr<Event>( |
+ return make_scoped_ptr( |
new MouseWheelEvent(static_cast<const MouseWheelEvent&>(event))); |
} |
- return scoped_ptr<Event>( |
+ return make_scoped_ptr( |
new MouseEvent(static_cast<const MouseEvent&>(event))); |
} |
if (event.IsTouchEvent()) { |
- return scoped_ptr<Event>( |
+ return make_scoped_ptr( |
new TouchEvent(static_cast<const TouchEvent&>(event))); |
} |
if (event.IsGestureEvent()) { |
- return scoped_ptr<Event>( |
+ return make_scoped_ptr( |
new GestureEvent(static_cast<const GestureEvent&>(event))); |
} |
if (event.IsScrollEvent()) { |
- return scoped_ptr<Event>( |
+ return make_scoped_ptr( |
new ScrollEvent(static_cast<const ScrollEvent&>(event))); |
} |
- return scoped_ptr<Event>(new Event(event)); |
+ return make_scoped_ptr(new Event(event)); |
} |
Event::~Event() { |
+ if (delete_native_event_) |
+ ReleaseCopiedNativeEvent(native_event_); |
} |
GestureEvent* Event::AsGestureEvent() { |
@@ -74,6 +165,12 @@ const GestureEvent* Event::AsGestureEvent() const { |
return static_cast<const GestureEvent*>(this); |
} |
+bool Event::HasNativeEvent() const { |
+ base::NativeEvent null_event; |
+ std::memset(&null_event, 0, sizeof(null_event)); |
+ return !!std::memcmp(&native_event_, &null_event, sizeof(null_event)); |
+} |
+ |
void Event::StopPropagation() { |
// TODO(sad): Re-enable these checks once View uses dispatcher to dispatch |
// events. |
@@ -90,26 +187,63 @@ void Event::SetHandled() { |
result_ = static_cast<EventResult>(result_ | ER_HANDLED); |
} |
-Event::Event() |
- : type_(ET_UNKNOWN), |
- time_stamp_(base::TimeDelta()), |
- flags_(EF_NONE), |
+Event::Event(EventType type, base::TimeDelta time_stamp, int flags) |
+ : type_(type), |
+ time_stamp_(time_stamp), |
+ flags_(flags), |
+ native_event_(base::NativeEvent()), |
+ delete_native_event_(false), |
cancelable_(true), |
target_(NULL), |
phase_(EP_PREDISPATCH), |
result_(ER_UNHANDLED), |
source_device_id_(ED_UNKNOWN_DEVICE) { |
+ if (type_ < ET_LAST) |
+ name_ = EventTypeName(type_); |
} |
-Event::Event(EventType type, base::TimeDelta time_stamp, int flags) |
+Event::Event(const base::NativeEvent& native_event, |
+ EventType type, |
+ int flags) |
: type_(type), |
- time_stamp_(time_stamp), |
+ time_stamp_(EventTimeFromNative(native_event)), |
flags_(flags), |
+ native_event_(native_event), |
+ delete_native_event_(false), |
cancelable_(true), |
target_(NULL), |
phase_(EP_PREDISPATCH), |
result_(ER_UNHANDLED), |
source_device_id_(ED_UNKNOWN_DEVICE) { |
+ base::TimeDelta delta = EventTimeForNow() - time_stamp_; |
+ if (type_ < ET_LAST) |
+ name_ = EventTypeName(type_); |
+ base::HistogramBase::Sample delta_sample = |
+ static_cast<base::HistogramBase::Sample>(delta.InMicroseconds()); |
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser", delta_sample, 1, 1000000, |
+ 100); |
+ std::string name_for_event = |
+ base::StringPrintf("Event.Latency.Browser.%s", name_.c_str()); |
+ base::HistogramBase* counter_for_type = |
+ base::Histogram::FactoryGet( |
+ name_for_event, |
+ 1, |
+ 1000000, |
+ 100, |
+ base::HistogramBase::kUmaTargetedHistogramFlag); |
+ counter_for_type->Add(delta_sample); |
+ |
+#if defined(USE_X11) |
+ if (native_event->type == GenericEvent) { |
+ XIDeviceEvent* xiev = |
+ static_cast<XIDeviceEvent*>(native_event->xcookie.data); |
+ source_device_id_ = xiev->sourceid; |
+ } |
+#endif |
+#if defined(USE_OZONE) |
+ source_device_id_ = |
+ static_cast<const Event*>(native_event)->source_device_id(); |
+#endif |
} |
Event::Event(const Event& copy) |
@@ -117,15 +251,23 @@ Event::Event(const Event& copy) |
time_stamp_(copy.time_stamp_), |
latency_(copy.latency_), |
flags_(copy.flags_), |
+ native_event_(CopyNativeEvent(copy.native_event_)), |
+ delete_native_event_(true), |
cancelable_(true), |
target_(NULL), |
phase_(EP_PREDISPATCH), |
result_(ER_UNHANDLED), |
source_device_id_(copy.source_device_id_) { |
+ if (type_ < ET_LAST) |
+ name_ = EventTypeName(type_); |
} |
void Event::SetType(EventType type) { |
+ if (type_ < ET_LAST) |
+ name_ = std::string(); |
type_ = type; |
+ if (type_ < ET_LAST) |
+ name_ = EventTypeName(type_); |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -142,10 +284,15 @@ CancelModeEvent::~CancelModeEvent() { |
//////////////////////////////////////////////////////////////////////////////// |
// LocatedEvent |
-LocatedEvent::LocatedEvent() : Event() { |
+LocatedEvent::~LocatedEvent() { |
} |
-LocatedEvent::~LocatedEvent() { |
+LocatedEvent::LocatedEvent(const base::NativeEvent& native_event) |
+ : Event(native_event, |
+ EventTypeFromNative(native_event), |
+ EventFlagsFromNative(native_event)), |
+ location_(EventLocationFromNative(native_event)), |
+ root_location_(location_) { |
} |
LocatedEvent::LocatedEvent(EventType type, |
@@ -170,15 +317,21 @@ void LocatedEvent::UpdateForRootTransform( |
//////////////////////////////////////////////////////////////////////////////// |
// MouseEvent |
-MouseEvent::MouseEvent() : LocatedEvent(), changed_button_flags_(0) { |
+MouseEvent::MouseEvent(const base::NativeEvent& native_event) |
+ : LocatedEvent(native_event), |
+ changed_button_flags_( |
+ GetChangedMouseButtonFlagsFromNative(native_event)) { |
+ if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED) |
+ SetClickCount(GetRepeatCount(*this)); |
} |
MouseEvent::MouseEvent(EventType type, |
const gfx::PointF& location, |
const gfx::PointF& root_location, |
+ base::TimeDelta time_stamp, |
int flags, |
int changed_button_flags) |
- : LocatedEvent(type, location, root_location, EventTimeForNow(), flags), |
+ : LocatedEvent(type, location, root_location, time_stamp, flags), |
changed_button_flags_(changed_button_flags) { |
if (this->type() == ET_MOUSE_MOVED && IsAnyButton()) |
SetType(ET_MOUSE_DRAGGED); |
@@ -202,6 +355,10 @@ bool MouseEvent::IsRepeatedClickEvent( |
(event2.flags() & ~EF_IS_DOUBLE_CLICK)) |
return false; |
+ // The new event has been created from the same native event. |
+ if (event1.time_stamp() == event2.time_stamp()) |
+ return false; |
+ |
base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp(); |
if (time_difference.InMilliseconds() > kDoubleClickTimeMS) |
@@ -216,6 +373,51 @@ bool MouseEvent::IsRepeatedClickEvent( |
return true; |
} |
+// static |
+int MouseEvent::GetRepeatCount(const MouseEvent& event) { |
+ int click_count = 1; |
+ if (last_click_event_) { |
+ if (event.type() == ui::ET_MOUSE_RELEASED) { |
+ if (event.changed_button_flags() == |
+ last_click_event_->changed_button_flags()) { |
+ last_click_complete_ = true; |
+ return last_click_event_->GetClickCount(); |
+ } else { |
+ // If last_click_event_ has changed since this button was pressed |
+ // return a click count of 1. |
+ return click_count; |
+ } |
+ } |
+ if (event.time_stamp() != last_click_event_->time_stamp()) |
+ last_click_complete_ = true; |
+ if (!last_click_complete_ || |
+ IsX11SendEventTrue(event.native_event())) { |
+ click_count = last_click_event_->GetClickCount(); |
+ } else if (IsRepeatedClickEvent(*last_click_event_, event)) { |
+ click_count = last_click_event_->GetClickCount() + 1; |
+ } |
+ delete last_click_event_; |
+ } |
+ last_click_event_ = new MouseEvent(event); |
+ last_click_complete_ = false; |
+ if (click_count > 3) |
+ click_count = 3; |
+ last_click_event_->SetClickCount(click_count); |
+ return click_count; |
+} |
+ |
+void MouseEvent::ResetLastClickForTest() { |
+ if (last_click_event_) { |
+ delete last_click_event_; |
+ last_click_event_ = NULL; |
+ last_click_complete_ = false; |
+ } |
+} |
+ |
+// static |
+MouseEvent* MouseEvent::last_click_event_ = NULL; |
+bool MouseEvent::last_click_complete_ = false; |
+ |
int MouseEvent::GetClickCount() const { |
if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED) |
return 0; |
@@ -256,7 +458,9 @@ void MouseEvent::SetClickCount(int click_count) { |
//////////////////////////////////////////////////////////////////////////////// |
// MouseWheelEvent |
-MouseWheelEvent::MouseWheelEvent() : MouseEvent(), offset_() { |
+MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event) |
+ : MouseEvent(native_event), |
+ offset_(GetMouseWheelOffset(native_event)) { |
} |
MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event) |
@@ -282,42 +486,48 @@ MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event) |
MouseWheelEvent::MouseWheelEvent(const gfx::Vector2d& offset, |
const gfx::PointF& location, |
const gfx::PointF& root_location, |
+ base::TimeDelta time_stamp, |
int flags, |
int changed_button_flags) |
- : MouseEvent(ui::ET_MOUSEWHEEL, location, root_location, flags, |
+ : MouseEvent(ui::ET_MOUSEWHEEL, |
+ location, |
+ root_location, |
+ time_stamp, |
+ flags, |
changed_button_flags), |
offset_(offset) { |
} |
+#if defined(OS_WIN) |
+// This value matches windows WHEEL_DELTA. |
+// static |
+const int MouseWheelEvent::kWheelDelta = 120; |
+#else |
// This value matches GTK+ wheel scroll amount. |
const int MouseWheelEvent::kWheelDelta = 53; |
- |
-void MouseWheelEvent::UpdateForRootTransform( |
- const gfx::Transform& inverted_root_transform) { |
- LocatedEvent::UpdateForRootTransform(inverted_root_transform); |
- gfx::DecomposedTransform decomp; |
- bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform); |
- DCHECK(success); |
- if (decomp.scale[0]) { |
- offset_.set_x( |
- gfx::ToRoundedInt(SkMScalarToFloat(offset_.x() * decomp.scale[0]))); |
- } |
- if (decomp.scale[1]) { |
- offset_.set_y( |
- gfx::ToRoundedInt(SkMScalarToFloat(offset_.y() * decomp.scale[1]))); |
- } |
-} |
+#endif |
//////////////////////////////////////////////////////////////////////////////// |
// TouchEvent |
-TouchEvent::TouchEvent() |
- : LocatedEvent(), |
- touch_id_(0), |
- radius_x_(0), |
- radius_y_(0), |
- rotation_angle_(0), |
- force_(0) { |
+TouchEvent::TouchEvent(const base::NativeEvent& native_event) |
+ : LocatedEvent(native_event), |
+ touch_id_(GetTouchId(native_event)), |
+ unique_event_id_(ui::GetNextTouchEventId()), |
+ radius_x_(GetTouchRadiusX(native_event)), |
+ radius_y_(GetTouchRadiusY(native_event)), |
+ rotation_angle_(GetTouchAngle(native_event)), |
+ force_(GetTouchForce(native_event)), |
+ may_cause_scrolling_(false), |
+ should_remove_native_touch_id_mapping_(false) { |
+ latency()->AddLatencyNumberWithTimestamp( |
+ INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, |
+ base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1); |
+ latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); |
+ |
+ FixRotationAngle(); |
+ if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED) |
+ should_remove_native_touch_id_mapping_ = true; |
} |
TouchEvent::TouchEvent(EventType type, |
@@ -326,10 +536,13 @@ TouchEvent::TouchEvent(EventType type, |
base::TimeDelta time_stamp) |
: LocatedEvent(type, location, location, time_stamp, 0), |
touch_id_(touch_id), |
+ unique_event_id_(ui::GetNextTouchEventId()), |
radius_x_(0.0f), |
radius_y_(0.0f), |
rotation_angle_(0.0f), |
- force_(0.0f) { |
+ force_(0.0f), |
+ may_cause_scrolling_(false), |
+ should_remove_native_touch_id_mapping_(false) { |
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); |
} |
@@ -344,14 +557,41 @@ TouchEvent::TouchEvent(EventType type, |
float force) |
: LocatedEvent(type, location, location, time_stamp, flags), |
touch_id_(touch_id), |
+ unique_event_id_(ui::GetNextTouchEventId()), |
radius_x_(radius_x), |
radius_y_(radius_y), |
rotation_angle_(angle), |
- force_(force) { |
+ force_(force), |
+ may_cause_scrolling_(false), |
+ should_remove_native_touch_id_mapping_(false) { |
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); |
+ FixRotationAngle(); |
+} |
+ |
+TouchEvent::TouchEvent(const TouchEvent& copy) |
+ : LocatedEvent(copy), |
+ touch_id_(copy.touch_id_), |
+ unique_event_id_(copy.unique_event_id_), |
+ radius_x_(copy.radius_x_), |
+ radius_y_(copy.radius_y_), |
+ rotation_angle_(copy.rotation_angle_), |
+ force_(copy.force_), |
+ may_cause_scrolling_(copy.may_cause_scrolling_), |
+ should_remove_native_touch_id_mapping_(false) { |
+ // Copied events should not remove touch id mapping, as this either causes the |
+ // mapping to be lost before the initial event has finished dispatching, or |
+ // the copy to attempt to remove the mapping from a null |native_event_|. |
} |
TouchEvent::~TouchEvent() { |
+ // In ctor TouchEvent(native_event) we call GetTouchId() which in X11 |
+ // platform setups the tracking_id to slot mapping. So in dtor here, |
+ // if this touch event is a release event, we clear the mapping accordingly. |
+ if (should_remove_native_touch_id_mapping_) { |
+ DCHECK(type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED); |
+ if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED) |
+ ClearTouchIdIfReleased(native_event()); |
+ } |
} |
void TouchEvent::UpdateForRootTransform( |
@@ -366,16 +606,84 @@ void TouchEvent::UpdateForRootTransform( |
radius_y_ *= decomp.scale[1]; |
} |
+void TouchEvent::DisableSynchronousHandling() { |
+ DispatcherApi dispatcher_api(this); |
+ dispatcher_api.set_result( |
+ static_cast<EventResult>(result() | ER_DISABLE_SYNC_HANDLING)); |
+} |
+ |
+void TouchEvent::FixRotationAngle() { |
+ while (rotation_angle_ < 0) |
+ rotation_angle_ += 180; |
+ while (rotation_angle_ >= 180) |
+ rotation_angle_ -= 180; |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// KeyEvent |
-KeyEvent::KeyEvent() |
- : Event(), |
- key_code_(VKEY_UNKNOWN), |
- code_(), |
- is_char_(false), |
- platform_keycode_(0), |
+// static |
+KeyEvent* KeyEvent::last_key_event_ = NULL; |
+ |
+// static |
+bool KeyEvent::IsRepeated(const KeyEvent& event) { |
+ // A safe guard in case if there were continous key pressed events that are |
+ // not auto repeat. |
+ const int kMaxAutoRepeatTimeMs = 2000; |
+ // Ignore key events that have non standard state masks as it may be |
+ // reposted by an IME. IBUS-GTK uses this field to detect the |
+ // re-posted event for example. crbug.com/385873. |
+ if (X11EventHasNonStandardState(event.native_event())) |
+ return false; |
+ if (event.is_char()) |
+ return false; |
+ if (event.type() == ui::ET_KEY_RELEASED) { |
+ delete last_key_event_; |
+ last_key_event_ = NULL; |
+ return false; |
+ } |
+ CHECK_EQ(ui::ET_KEY_PRESSED, event.type()); |
+ if (!last_key_event_) { |
+ last_key_event_ = new KeyEvent(event); |
+ return false; |
+ } else if (event.time_stamp() == last_key_event_->time_stamp()) { |
+ // The KeyEvent is created from the same native event. |
+ return (last_key_event_->flags() & ui::EF_IS_REPEAT) != 0; |
+ } |
+ if (event.key_code() == last_key_event_->key_code() && |
+ event.flags() == (last_key_event_->flags() & ~ui::EF_IS_REPEAT) && |
+ (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() < |
+ kMaxAutoRepeatTimeMs) { |
+ last_key_event_->set_time_stamp(event.time_stamp()); |
+ last_key_event_->set_flags(last_key_event_->flags() | ui::EF_IS_REPEAT); |
+ return true; |
+ } |
+ delete last_key_event_; |
+ last_key_event_ = new KeyEvent(event); |
+ return false; |
+} |
+ |
+KeyEvent::KeyEvent(const base::NativeEvent& native_event) |
+ : Event(native_event, |
+ EventTypeFromNative(native_event), |
+ EventFlagsFromNative(native_event)), |
+ key_code_(KeyboardCodeFromNative(native_event)), |
+ code_(CodeFromNative(native_event)), |
+ is_char_(IsCharFromNative(native_event)), |
+ platform_keycode_(PlatformKeycodeFromNative(native_event)), |
+ key_(DomKey::NONE), |
character_(0) { |
+ if (IsRepeated(*this)) |
+ set_flags(flags() | ui::EF_IS_REPEAT); |
+ |
+#if defined(USE_X11) |
+ NormalizeFlags(); |
+#endif |
+#if defined(OS_WIN) |
+ // Only Windows has native character events. |
+ if (is_char_) |
+ character_ = native_event.wParam; |
+#endif |
} |
KeyEvent::KeyEvent(EventType type, |
@@ -383,29 +691,49 @@ KeyEvent::KeyEvent(EventType type, |
int flags) |
: Event(type, EventTimeForNow(), flags), |
key_code_(key_code), |
+ code_(UsLayoutKeyboardCodeToDomCode(key_code)), |
is_char_(false), |
platform_keycode_(0), |
+ key_(DomKey::NONE), |
character_() { |
} |
KeyEvent::KeyEvent(EventType type, |
KeyboardCode key_code, |
- const std::string& code, |
+ DomCode code, |
int flags) |
: Event(type, EventTimeForNow(), flags), |
key_code_(key_code), |
code_(code), |
is_char_(false), |
platform_keycode_(0), |
+ key_(DomKey::NONE), |
character_(0) { |
} |
+KeyEvent::KeyEvent(EventType type, |
+ KeyboardCode key_code, |
+ DomCode code, |
+ int flags, |
+ DomKey key, |
+ base::char16 character, |
+ base::TimeDelta time_stamp) |
+ : Event(type, time_stamp, flags), |
+ key_code_(key_code), |
+ code_(code), |
+ is_char_(false), |
+ platform_keycode_(0), |
+ key_(key), |
+ character_(character) { |
+} |
+ |
KeyEvent::KeyEvent(base::char16 character, KeyboardCode key_code, int flags) |
: Event(ET_KEY_PRESSED, EventTimeForNow(), flags), |
key_code_(key_code), |
- code_(""), |
+ code_(DomCode::NONE), |
is_char_(true), |
platform_keycode_(0), |
+ key_(DomKey::CHARACTER), |
character_(character) { |
} |
@@ -415,6 +743,7 @@ KeyEvent::KeyEvent(const KeyEvent& rhs) |
code_(rhs.code_), |
is_char_(rhs.is_char_), |
platform_keycode_(rhs.platform_keycode_), |
+ key_(rhs.key_), |
character_(rhs.character_) { |
if (rhs.extended_key_event_data_) |
extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone()); |
@@ -425,6 +754,7 @@ KeyEvent& KeyEvent::operator=(const KeyEvent& rhs) { |
Event::operator=(rhs); |
key_code_ = rhs.key_code_; |
code_ = rhs.code_; |
+ key_ = rhs.key_; |
is_char_ = rhs.is_char_; |
platform_keycode_ = rhs.platform_keycode_; |
character_ = rhs.character_; |
@@ -441,24 +771,80 @@ void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) { |
extended_key_event_data_ = data.Pass(); |
} |
-base::char16 KeyEvent::GetCharacter() const { |
- if (is_char_ || character_) |
- return character_; |
- |
- // TODO(kpschoedel): streamline these cases after settling Ozone |
- // positional coding. |
-#if defined(USE_X11) |
- character_ = GetCharacterFromKeyCode(key_code_, flags()); |
- return character_; |
+void KeyEvent::ApplyLayout() const { |
+ // If the client has set the character (e.g. faked key events from virtual |
+ // keyboard), it's client's responsibility to set the dom key correctly. |
+ // Otherwise, set the dom key as unidentified. |
+ // Please refer to crbug.com/443889. |
+ if (character_ != 0) { |
+ key_ = DomKey::UNIDENTIFIED; |
+ return; |
+ } |
+ ui::DomCode code = code_; |
+ if (code == DomCode::NONE) { |
+ // Catch old code that tries to do layout without a physical key, and try |
+ // to recover using the KeyboardCode. Once key events are fully defined |
+ // on construction (see TODO in event.h) this will go away. |
+ LOG(WARNING) << "DomCode::NONE keycode=" << key_code_; |
+ code = UsLayoutKeyboardCodeToDomCode(key_code_); |
+ if (code == DomCode::NONE) { |
+ key_ = DomKey::UNIDENTIFIED; |
+ return; |
+ } |
+ } |
+ KeyboardCode dummy_key_code; |
+#if defined(OS_WIN) |
+// Native Windows character events always have is_char_ == true, |
+// so this is a synthetic or native keystroke event. |
+// Therefore, perform only the fallback action. |
+#elif defined(USE_X11) |
+ // When a control key is held, prefer ASCII characters to non ASCII |
+ // characters in order to use it for shortcut keys. GetCharacterFromKeyCode |
+ // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11. |
+ // GetCharacterFromXEvent returns 'à' in that case. |
+ if (!IsControlDown() && native_event()) { |
+ GetMeaningFromXEvent(native_event(), &key_, &character_); |
+ return; |
+ } |
+#elif defined(USE_OZONE) |
+ if (KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup( |
+ code, flags(), &key_, &character_, &dummy_key_code, |
+ &platform_keycode_)) { |
+ return; |
+ } |
#else |
- return GetCharacterFromKeyCode(key_code_, flags()); |
+ if (native_event()) { |
+ DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED || |
+ EventTypeFromNative(native_event()) == ET_KEY_RELEASED); |
+ } |
#endif |
+ if (!DomCodeToUsLayoutMeaning(code, flags(), &key_, &character_, |
+ &dummy_key_code)) { |
+ key_ = DomKey::UNIDENTIFIED; |
+ } |
+} |
+ |
+DomKey KeyEvent::GetDomKey() const { |
+ // Determination of character_ and key_ may be done lazily. |
+ if (key_ == DomKey::NONE) |
+ ApplyLayout(); |
+ return key_; |
+} |
+ |
+base::char16 KeyEvent::GetCharacter() const { |
+ // Determination of character_ and key_ may be done lazily. |
+ if (key_ == DomKey::NONE) |
+ ApplyLayout(); |
+ return character_; |
} |
base::char16 KeyEvent::GetText() const { |
if ((flags() & EF_CONTROL_DOWN) != 0) { |
- return GetControlCharacterForKeycode(key_code_, |
- (flags() & EF_SHIFT_DOWN) != 0); |
+ base::char16 character; |
+ ui::DomKey key; |
+ ui::KeyboardCode key_code; |
+ if (DomCodeToControlCharacter(code_, flags(), &key, &character, &key_code)) |
+ return character; |
} |
return GetUnmodifiedText(); |
} |
@@ -470,7 +856,23 @@ base::char16 KeyEvent::GetUnmodifiedText() const { |
} |
bool KeyEvent::IsUnicodeKeyCode() const { |
+#if defined(OS_WIN) |
+ if (!IsAltDown()) |
+ return false; |
+ const int key = key_code(); |
+ if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9) |
+ return true; |
+ // Check whether the user is using the numeric keypad with num-lock off. |
+ // In that case, EF_EXTENDED will not be set; if it is set, the key event |
+ // originated from the relevant non-numpad dedicated key, e.g. [Insert]. |
+ return (!(flags() & EF_EXTENDED) && |
+ (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN || |
+ key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR || |
+ key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP || |
+ key == VKEY_PRIOR)); |
+#else |
return false; |
+#endif |
} |
void KeyEvent::NormalizeFlags() { |
@@ -497,104 +899,8 @@ void KeyEvent::NormalizeFlags() { |
set_flags(flags() & ~mask); |
} |
-bool KeyEvent::IsTranslated() const { |
- switch (type()) { |
- case ET_KEY_PRESSED: |
- case ET_KEY_RELEASED: |
- return false; |
- case ET_TRANSLATED_KEY_PRESS: |
- case ET_TRANSLATED_KEY_RELEASE: |
- return true; |
- default: |
- NOTREACHED(); |
- return false; |
- } |
-} |
- |
-void KeyEvent::SetTranslated(bool translated) { |
- switch (type()) { |
- case ET_KEY_PRESSED: |
- case ET_TRANSLATED_KEY_PRESS: |
- SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED); |
- break; |
- case ET_KEY_RELEASED: |
- case ET_TRANSLATED_KEY_RELEASE: |
- SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED); |
- break; |
- default: |
- NOTREACHED(); |
- } |
-} |
- |
-bool KeyEvent::IsRightSideKey() const { |
- switch (key_code_) { |
- case VKEY_CONTROL: |
- case VKEY_SHIFT: |
- case VKEY_MENU: |
- case VKEY_LWIN: |
-#if defined(USE_X11) |
- // Under X11, setting code_ requires platform-dependent information, and |
- // currently assumes that X keycodes are based on Linux evdev keycodes. |
- // In certain test environments this is not the case, and code_ is not |
- // set accurately, so we need a different mechanism. Fortunately X11 key |
- // mapping preserves the left-right distinction, so testing keysyms works |
- // if the value is available (as it is for all X11 native-based events). |
- if (platform_keycode_) { |
- return (platform_keycode_ == XK_Shift_R) || |
- (platform_keycode_ == XK_Control_R) || |
- (platform_keycode_ == XK_Alt_R) || |
- (platform_keycode_ == XK_Meta_R) || |
- (platform_keycode_ == XK_Super_R) || |
- (platform_keycode_ == XK_Hyper_R); |
- } |
- // Fall through to the generic code if we have no platform_keycode_. |
- // Under X11, this must be a synthetic event, so we can require that |
- // code_ be set correctly. |
-#endif |
- return ((code_.size() > 5) && |
- (code_.compare(code_.size() - 5, 5, "Right", 5)) == 0); |
- default: |
- return false; |
- } |
-} |
- |
KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const { |
- switch (key_code_) { |
- case VKEY_SHIFT: |
- return IsRightSideKey() ? VKEY_RSHIFT : VKEY_LSHIFT; |
- case VKEY_CONTROL: |
- return IsRightSideKey() ? VKEY_RCONTROL : VKEY_LCONTROL; |
- case VKEY_MENU: |
- return IsRightSideKey() ? VKEY_RMENU : VKEY_LMENU; |
- case VKEY_LWIN: |
- return IsRightSideKey() ? VKEY_RWIN : VKEY_LWIN; |
- // TODO(kpschoedel): EF_NUMPAD_KEY is present only on X11. Currently this |
- // function is only called on X11. Likely the tests here will be replaced |
- // with a DOM-based code enumeration test in the course of Ozone |
- // platform-indpendent key event work. |
- case VKEY_0: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD0 : VKEY_0; |
- case VKEY_1: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD1 : VKEY_1; |
- case VKEY_2: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD2 : VKEY_2; |
- case VKEY_3: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD3 : VKEY_3; |
- case VKEY_4: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD4 : VKEY_4; |
- case VKEY_5: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD5 : VKEY_5; |
- case VKEY_6: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD6 : VKEY_6; |
- case VKEY_7: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD7 : VKEY_7; |
- case VKEY_8: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD8 : VKEY_8; |
- case VKEY_9: |
- return (flags() & EF_NUMPAD_KEY) ? VKEY_NUMPAD9 : VKEY_9; |
- default: |
- return key_code_; |
- } |
+ return NonLocatedToLocatedKeyboardCode(key_code_, code_); |
} |
uint16 KeyEvent::GetConflatedWindowsKeyCode() const { |
@@ -603,10 +909,30 @@ uint16 KeyEvent::GetConflatedWindowsKeyCode() const { |
return key_code_; |
} |
+std::string KeyEvent::GetCodeString() const { |
+ return KeycodeConverter::DomCodeToCodeString(code_); |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// ScrollEvent |
-ScrollEvent::ScrollEvent() : MouseEvent() { |
+ScrollEvent::ScrollEvent(const base::NativeEvent& native_event) |
+ : MouseEvent(native_event) { |
+ if (type() == ET_SCROLL) { |
+ GetScrollOffsets(native_event, |
+ &x_offset_, &y_offset_, |
+ &x_offset_ordinal_, &y_offset_ordinal_, |
+ &finger_count_); |
+ } else if (type() == ET_SCROLL_FLING_START || |
+ type() == ET_SCROLL_FLING_CANCEL) { |
+ GetFlingData(native_event, |
+ &x_offset_, &y_offset_, |
+ &x_offset_ordinal_, &y_offset_ordinal_, |
+ NULL); |
+ } else { |
+ NOTREACHED() << "Unexpected event type " << type() |
+ << " when constructing a ScrollEvent."; |
+ } |
} |
ScrollEvent::ScrollEvent(EventType type, |
@@ -618,13 +944,12 @@ ScrollEvent::ScrollEvent(EventType type, |
float x_offset_ordinal, |
float y_offset_ordinal, |
int finger_count) |
- : MouseEvent(type, location, location, flags, 0), |
+ : MouseEvent(type, location, location, time_stamp, flags, 0), |
x_offset_(x_offset), |
y_offset_(y_offset), |
x_offset_ordinal_(x_offset_ordinal), |
y_offset_ordinal_(y_offset_ordinal), |
finger_count_(finger_count) { |
- set_time_stamp(time_stamp); |
CHECK(IsScrollEvent()); |
} |