| 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());
|
| }
|
|
|
|
|