diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-03 22:43:55 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-03 22:43:55 +0000 |
commit | 4967673d6412cbaa11e212da26742eba445cc1f9 (patch) | |
tree | cdee0a6d42949f8cabf8f5ccd3ce746b39f8b2a1 /ui/base | |
parent | 1bb25e0e19ec7e8fab908efa70a9fc16c02ae287 (diff) | |
download | chromium_src-4967673d6412cbaa11e212da26742eba445cc1f9.zip chromium_src-4967673d6412cbaa11e212da26742eba445cc1f9.tar.gz chromium_src-4967673d6412cbaa11e212da26742eba445cc1f9.tar.bz2 |
Copy aura::Event into ui::Event.
http://crbug.com/125937
TEST=existing
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=149888
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=149916
Review URL: https://chromiumcodereview.appspot.com/10831137
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149954 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-rw-r--r-- | ui/base/event.cc | 428 | ||||
-rw-r--r-- | ui/base/event.h | 422 | ||||
-rw-r--r-- | ui/base/event_unittest.cc | 102 |
3 files changed, 952 insertions, 0 deletions
diff --git a/ui/base/event.cc b/ui/base/event.cc new file mode 100644 index 0000000..1433f02 --- /dev/null +++ b/ui/base/event.cc @@ -0,0 +1,428 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/event.h" + +#if defined(USE_X11) +#include <X11/Xlib.h> +#endif + +#include <cstring> + +#include "ui/base/keycodes/keyboard_code_conversion.h" +#include "ui/gfx/point3.h" +#include "ui/gfx/interpolated_transform.h" +#include "ui/gfx/transform.h" + +#if defined(USE_X11) +#include "ui/base/keycodes/keyboard_code_conversion_x.h" +#endif + +namespace { + +base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { +#if defined(USE_X11) + XEvent* copy = new XEvent; + *copy = *event; + return copy; +#elif defined(OS_WIN) + return event; +#else + NOTREACHED() << + "Don't know how to copy base::NativeEvent for this platform"; + return NULL; +#endif +} + +} // namespace + +namespace ui { + +Event::~Event() { +#if defined(USE_X11) + if (delete_native_event_) + delete native_event_; +#endif +} + +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)); +} + +Event::Event(EventType type, int flags) + : type_(type), + time_stamp_(base::Time::NowFromSystemTime() - base::Time()), + flags_(flags), + delete_native_event_(false) { + Init(); +} + +Event::Event(const base::NativeEvent& native_event, + EventType type, + int flags) + : type_(type), + time_stamp_(EventTimeFromNative(native_event)), + flags_(flags), + delete_native_event_(false) { + InitWithNativeEvent(native_event); +} + +Event::Event(const Event& copy) + : native_event_(copy.native_event_), + type_(copy.type_), + time_stamp_(copy.time_stamp_), + flags_(copy.flags_), + delete_native_event_(false) { +} + +void Event::Init() { + std::memset(&native_event_, 0, sizeof(native_event_)); +} + +void Event::InitWithNativeEvent(const base::NativeEvent& native_event) { + native_event_ = native_event; +} + +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, + const gfx::Point& location, + const gfx::Point& root_location, + int flags) + : Event(type, flags), + location_(location), + root_location_(root_location) { +} + +void LocatedEvent::UpdateForRootTransform(const Transform& root_transform) { + // Transform has to be done at root level. + DCHECK_EQ(root_location_.x(), location_.x()); + DCHECK_EQ(root_location_.y(), location_.y()); + gfx::Point3f p(location_); + root_transform.TransformPointReverse(p); + root_location_ = location_ = p.AsPoint(); +} + +MouseEvent::MouseEvent(const base::NativeEvent& native_event) + : LocatedEvent(native_event) { + if (type() == ET_MOUSE_PRESSED) + SetClickCount(GetRepeatCount(*this)); +} + +MouseEvent::MouseEvent(EventType type, + const gfx::Point& location, + const gfx::Point& root_location, + int flags) + : LocatedEvent(type, location, root_location, flags) { +} + +// static +bool MouseEvent::IsRepeatedClickEvent( + const MouseEvent& event1, + const MouseEvent& event2) { + // These values match the Windows defaults. + static const int kDoubleClickTimeMS = 500; + static const int kDoubleClickWidth = 4; + static const int kDoubleClickHeight = 4; + + if (event1.type() != ET_MOUSE_PRESSED || + event2.type() != ET_MOUSE_PRESSED) + return false; + + // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks. + if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) != + (event2.flags() & ~EF_IS_DOUBLE_CLICK)) + return false; + + base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp(); + + if (time_difference.InMilliseconds() > kDoubleClickTimeMS) + return false; + + if (abs(event2.x() - event1.x()) > kDoubleClickWidth / 2) + return false; + + if (abs(event2.y() - event1.y()) > kDoubleClickHeight / 2) + return false; + + return true; +} + +// static +int MouseEvent::GetRepeatCount(const MouseEvent& event) { + int click_count = 1; + if (last_click_event_) { + if (IsRepeatedClickEvent(*last_click_event_, event)) + click_count = last_click_event_->GetClickCount() + 1; + delete last_click_event_; + } + last_click_event_ = new MouseEvent(event.native_event()); + if (click_count > 3) + click_count = 3; + last_click_event_->SetClickCount(click_count); + return click_count; +} + +// static +MouseEvent* MouseEvent::last_click_event_ = NULL; + +int MouseEvent::GetClickCount() const { + if (type() != ET_MOUSE_PRESSED) + return 0; + + if (flags() & EF_IS_TRIPLE_CLICK) + return 3; + else if (flags() & EF_IS_DOUBLE_CLICK) + return 2; + else + return 1; +} + +void MouseEvent::SetClickCount(int click_count) { + if (type() != ET_MOUSE_PRESSED) + return; + + DCHECK(click_count > 0); + DCHECK(click_count <= 3); + + int f = flags(); + switch (click_count) { + case 1: + f &= ~EF_IS_DOUBLE_CLICK; + f &= ~EF_IS_TRIPLE_CLICK; + break; + case 2: + f |= EF_IS_DOUBLE_CLICK; + f &= ~EF_IS_TRIPLE_CLICK; + break; + case 3: + f &= ~EF_IS_DOUBLE_CLICK; + f |= EF_IS_TRIPLE_CLICK; + break; + } + set_flags(f); +} + +TouchEventImpl::TouchEventImpl(const base::NativeEvent& native_event) + : LocatedEvent(native_event), + touch_id_(ui::GetTouchId(native_event)), + radius_x_(GetTouchRadiusX(native_event)), + radius_y_(GetTouchRadiusY(native_event)), + rotation_angle_(GetTouchAngle(native_event)), + force_(GetTouchForce(native_event)) { +} + +TouchEventImpl::TouchEventImpl(EventType type, + const gfx::Point& location, + int touch_id, + base::TimeDelta time_stamp) + : LocatedEvent(type, location, location, 0), + touch_id_(touch_id), + radius_x_(0.0f), + radius_y_(0.0f), + rotation_angle_(0.0f), + force_(0.0f) { + set_time_stamp(time_stamp); +} + +TouchEventImpl::~TouchEventImpl() { +} + +void TouchEventImpl::UpdateForRootTransform(const Transform& root_transform) { + LocatedEvent::UpdateForRootTransform(root_transform); + gfx::Point3f scale; + InterpolatedTransform::FactorTRS(root_transform, NULL, NULL, &scale); + if (scale.x()) + radius_x_ /= scale.x(); + if (scale.y()) + radius_y_ /= scale.y(); +} + +EventType TouchEventImpl::GetEventType() const { + return type(); +} + +gfx::Point TouchEventImpl::GetLocation() const { + return location(); +} + +int TouchEventImpl::GetTouchId() const { + return touch_id_; +} + +int TouchEventImpl::GetEventFlags() const { + return flags(); +} + +base::TimeDelta TouchEventImpl::GetTimestamp() const { + return time_stamp(); +} + +float TouchEventImpl::RadiusX() const { + return radius_x_; +} + +float TouchEventImpl::RadiusY() const { + return radius_y_; +} + +float TouchEventImpl::RotationAngle() const { + return rotation_angle_; +} + +float TouchEventImpl::Force() const { + return force_; +} + +KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char) + : Event(native_event, + EventTypeFromNative(native_event), + EventFlagsFromNative(native_event)), + key_code_(KeyboardCodeFromNative(native_event)), + is_char_(is_char), + character_(0), + unmodified_character_(0) { +} + +KeyEvent::KeyEvent(EventType type, + KeyboardCode key_code, + int flags) + : Event(type, flags), + key_code_(key_code), + is_char_(false), + character_(GetCharacterFromKeyCode(key_code, flags)), + unmodified_character_(0) { +} + +uint16 KeyEvent::GetCharacter() const { + if (character_) + return character_; + +#if defined(OS_WIN) + return (native_event().message == WM_CHAR) ? key_code_ : + GetCharacterFromKeyCode(key_code_, flags()); +#elif defined(USE_X11) + if (!native_event()) + return GetCharacterFromKeyCode(key_code_, flags()); + + DCHECK(native_event()->type == KeyPress || + native_event()->type == KeyRelease); + + uint16 ch = 0; + if (!IsControlDown()) + ch = GetCharacterFromXEvent(native_event()); + return ch ? ch : GetCharacterFromKeyCode(key_code_, flags()); +#else + NOTIMPLEMENTED(); + return 0; +#endif +} + +uint16 KeyEvent::GetUnmodifiedCharacter() const { + if (unmodified_character_) + return unmodified_character_; + +#if defined(OS_WIN) + // Looks like there is no way to get unmodified character on Windows. + return (native_event().message == WM_CHAR) ? key_code_ : + GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN); +#elif defined(USE_X11) + if (!native_event()) + return GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN); + + DCHECK(native_event()->type == KeyPress || + native_event()->type == KeyRelease); + + static const unsigned int kIgnoredModifiers = ControlMask | LockMask | + Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask; + + XKeyEvent copy = native_event()->xkey; // bit-wise copy is safe. + // We can't use things like (native_event()->xkey.state & ShiftMask), as it + // may mask out bits used by X11 internally. + copy.state &= ~kIgnoredModifiers; + uint16 ch = GetCharacterFromXEvent(reinterpret_cast<XEvent*>(©)); + return ch ? ch : GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN); +#else + NOTIMPLEMENTED(); + return 0; +#endif +} + +KeyEvent* KeyEvent::Copy() { + KeyEvent* copy = new KeyEvent(::CopyNativeEvent(native_event()), is_char()); +#if defined(USE_X11) + copy->set_delete_native_event(true); +#endif + return copy; +} + +TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event, + bool is_char) + : KeyEvent(native_event, is_char) { + set_type(type() == ET_KEY_PRESSED ? + ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE); +} + +TranslatedKeyEvent::TranslatedKeyEvent(bool is_press, + KeyboardCode key_code, + int flags) + : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE), + key_code, + flags) { +} + +void TranslatedKeyEvent::ConvertToKeyEvent() { + set_type(type() == ET_TRANSLATED_KEY_PRESS ? + ET_KEY_PRESSED : ET_KEY_RELEASED); +} + +ScrollEvent::ScrollEvent(const base::NativeEvent& native_event) + : MouseEvent(native_event) { + if (type() == ET_SCROLL) { + GetScrollOffsets(native_event, &x_offset_, &y_offset_); + double start, end; + GetGestureTimes(native_event, &start, &end); + } else if (type() == ET_SCROLL_FLING_START) { + bool is_cancel; + GetFlingData(native_event, &x_offset_, &y_offset_, &is_cancel); + } +} + +GestureEventImpl::GestureEventImpl(EventType type, + int x, + int y, + int flags, + base::Time time_stamp, + const GestureEventDetails& details, + unsigned int touch_ids_bitfield) + : LocatedEvent(type, gfx::Point(x, y), gfx::Point(x, y), flags), + details_(details), + touch_ids_bitfield_(touch_ids_bitfield) { + set_time_stamp(base::TimeDelta::FromSeconds(time_stamp.ToDoubleT())); +} + +GestureEventImpl::~GestureEventImpl() { +} + +int GestureEventImpl::GetLowestTouchId() const { + if (touch_ids_bitfield_ == 0) + return -1; + int i = -1; + // Find the index of the least significant 1 bit + while (!(1 << ++i & touch_ids_bitfield_)); + return i; +} + +} // namespace ui diff --git a/ui/base/event.h b/ui/base/event.h new file mode 100644 index 0000000..1e20fa1 --- /dev/null +++ b/ui/base/event.h @@ -0,0 +1,422 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_EVENT_H_ +#define UI_BASE_EVENT_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/event_types.h" +#include "base/logging.h" +#include "base/time.h" +#include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/base/events.h" +#include "ui/base/gestures/gesture_types.h" +#include "ui/base/keycodes/keyboard_codes.h" +#include "ui/base/ui_export.h" +#include "ui/gfx/point.h" + +namespace ui { +class Transform; + +class UI_EXPORT Event { + public: + virtual ~Event(); + + // For testing. + class TestApi { + public: + explicit TestApi(Event* event) : event_(event) {} + + void set_time_stamp(const base::TimeDelta& time_stamp) { + event_->time_stamp_ = time_stamp; + } + + private: + TestApi(); + Event* event_; + }; + + const base::NativeEvent& native_event() const { return native_event_; } + EventType type() const { return type_; } + // time_stamp represents time since machine was booted. + const base::TimeDelta& time_stamp() const { return time_stamp_; } + int flags() const { return flags_; } + + // This is only intended to be used externally by classes that are modifying + // events in EventFilter::PreHandleKeyEvent(). + void set_flags(int flags) { flags_ = flags; } + + // The following methods return true if the respective keys were pressed at + // the time the event was created. + bool IsShiftDown() const { return (flags_ & EF_SHIFT_DOWN) != 0; } + bool IsControlDown() const { return (flags_ & EF_CONTROL_DOWN) != 0; } + bool IsCapsLockDown() const { return (flags_ & EF_CAPS_LOCK_DOWN) != 0; } + bool IsAltDown() const { return (flags_ & EF_ALT_DOWN) != 0; } + + // Returns true if the event has a valid |native_event_|. + bool HasNativeEvent() const; + + protected: + Event(EventType type, int flags); + Event(const base::NativeEvent& native_event, EventType type, int flags); + Event(const Event& copy); + void set_type(EventType type) { type_ = type; } + void set_delete_native_event(bool delete_native_event) { + delete_native_event_ = delete_native_event; + } + void set_time_stamp(base::TimeDelta time_stamp) { time_stamp_ = time_stamp; } + + private: + void operator=(const Event&); + + // Safely initializes the native event members of this class. + void Init(); + void InitWithNativeEvent(const base::NativeEvent& native_event); + + base::NativeEvent native_event_; + EventType type_; + base::TimeDelta time_stamp_; + int flags_; + bool delete_native_event_; +}; + +class UI_EXPORT LocatedEvent : public Event { + public: + // For testing. + class TestApi : public Event::TestApi { + public: + explicit TestApi(LocatedEvent* located_event) + : Event::TestApi(located_event), + located_event_(located_event) {} + + void set_location(const gfx::Point& location) { + located_event_->location_ = location; + } + + private: + TestApi(); + LocatedEvent* located_event_; + }; + + virtual ~LocatedEvent(); + + int x() const { return location_.x(); } + int y() const { return location_.y(); } + gfx::Point location() const { return location_; } + gfx::Point root_location() const { return root_location_; } + + // Applies |root_transform| to the event. + // This is applied to both |location_| and |root_location_|. + virtual void UpdateForRootTransform(const Transform& root_transform); + + protected: + explicit LocatedEvent(const base::NativeEvent& native_event); + + // Create a new LocatedEvent which is identical to the provided model. + // If source / target windows are provided, the model location will be + // converted from |source| coordinate system to |target| coordinate system. + template <class T> + LocatedEvent(const LocatedEvent& model, T* source, T* target) + : Event(model), + location_(model.location_), + root_location_(model.root_location_) { + if (target && target != source) + T::ConvertPointToTarget(source, target, &location_); + } + + // Used for synthetic events in testing. + LocatedEvent(EventType type, + const gfx::Point& location, + const gfx::Point& root_location, + int flags); + + gfx::Point location_; + + gfx::Point root_location_; + + private: + DISALLOW_COPY_AND_ASSIGN(LocatedEvent); +}; + +class UI_EXPORT MouseEvent : public LocatedEvent { + public: + explicit MouseEvent(const base::NativeEvent& native_event); + + // Create a new MouseEvent based on the provided model. + // Uses the provided |type| and |flags| for the new event. + // If source / target windows are provided, the model location will be + // converted from |source| coordinate system to |target| coordinate system. + template <class T> + MouseEvent(const MouseEvent& model, T* source, T* target) + : LocatedEvent(model, source, target) { + } + + template <class T> + MouseEvent(const MouseEvent& model, + T* source, + T* target, + EventType type, + int flags) + : LocatedEvent(model, source, target) { + set_type(type); + set_flags(flags); + } + + // Used for synthetic events in testing and by the gesture recognizer. + MouseEvent(EventType type, + const gfx::Point& location, + const gfx::Point& root_location, + int flags); + + // Compares two mouse down events and returns true if the second one should + // be considered a repeat of the first. + static bool IsRepeatedClickEvent( + const MouseEvent& event1, + const MouseEvent& event2); + + // Get the click count. Can be 1, 2 or 3 for mousedown messages, 0 otherwise. + int GetClickCount() const; + + // Set the click count for a mousedown message. Can be 1, 2 or 3. + void SetClickCount(int click_count); + + private: + gfx::Point root_location_; + + static MouseEvent* last_click_event_; + // Returns the repeat count based on the previous mouse click, if it is + // recent enough and within a small enough distance. + static int GetRepeatCount(const MouseEvent& click_event); + + DISALLOW_COPY_AND_ASSIGN(MouseEvent); +}; + +// TODO(beng): rename to TouchEvent after conversion is complete. +class UI_EXPORT TouchEventImpl : public LocatedEvent, + public TouchEvent { + public: + explicit TouchEventImpl(const base::NativeEvent& native_event); + + // Create a new TouchEventImpl which is identical to the provided model. + // If source / target windows are provided, the model location will be + // converted from |source| coordinate system to |target| coordinate system. + template <class T> + TouchEventImpl(const TouchEventImpl& model, T* source, T* target) + : LocatedEvent(model, source, target), + touch_id_(model.touch_id_), + radius_x_(model.radius_x_), + radius_y_(model.radius_y_), + rotation_angle_(model.rotation_angle_), + force_(model.force_) { + } + + TouchEventImpl(EventType type, + const gfx::Point& root_location, + int touch_id, + base::TimeDelta time_stamp); + + virtual ~TouchEventImpl(); + + int touch_id() const { return touch_id_; } + float radius_x() const { return radius_x_; } + float radius_y() const { return radius_y_; } + float rotation_angle() const { return rotation_angle_; } + float force() const { return force_; } + + // Used for unit tests. + void set_radius_x(const float r) { radius_x_ = r; } + void set_radius_y(const float r) { radius_y_ = r; } + + // Overridden from LocatedEvent. + virtual void UpdateForRootTransform(const Transform& root_transform) OVERRIDE; + + // Overridden from TouchEvent. + virtual EventType GetEventType() const OVERRIDE; + virtual gfx::Point GetLocation() const OVERRIDE; + virtual int GetTouchId() const OVERRIDE; + virtual int GetEventFlags() const OVERRIDE; + virtual base::TimeDelta GetTimestamp() const OVERRIDE; + virtual float RadiusX() const OVERRIDE; + virtual float RadiusY() const OVERRIDE; + virtual float RotationAngle() const OVERRIDE; + virtual float Force() const OVERRIDE; + + private: + // The identity (typically finger) of the touch starting at 0 and incrementing + // for each separable additional touch that the hardware can detect. + const int touch_id_; + + // Radius of the X (major) axis of the touch ellipse. 0.0 if unknown. + float radius_x_; + + // Radius of the Y (minor) axis of the touch ellipse. 0.0 if unknown. + float radius_y_; + + // Angle of the major axis away from the X axis. Default 0.0. + const float rotation_angle_; + + // Force (pressure) of the touch. Normalized to be [0, 1]. Default to be 0.0. + const float force_; + + DISALLOW_COPY_AND_ASSIGN(TouchEventImpl); +}; + +class UI_EXPORT KeyEvent : public Event { + public: + KeyEvent(const base::NativeEvent& native_event, bool is_char); + + // Used for synthetic events in testing. + KeyEvent(EventType type, KeyboardCode key_code, int flags); + + // These setters allow an I18N virtual keyboard to fabricate a keyboard event + // which does not have a corresponding KeyboardCode (example: U+00E1 Latin + // small letter A with acute, U+0410 Cyrillic capital letter A.) + // GetCharacter() and GetUnmodifiedCharacter() return the character. + void set_character(uint16 character) { character_ = character; } + void set_unmodified_character(uint16 unmodified_character) { + unmodified_character_ = unmodified_character; + } + + // Gets the character generated by this key event. It only supports Unicode + // BMP characters. + uint16 GetCharacter() const; + + // Gets the character generated by this key event ignoring concurrently-held + // modifiers (except shift). + uint16 GetUnmodifiedCharacter() const; + + // Returns the copy of this key event. Used in NativeWebKeyboardEvent. + KeyEvent* Copy(); + + KeyboardCode key_code() const { return key_code_; } + bool is_char() const { return is_char_; } + + // This is only intended to be used externally by classes that are modifying + // events in EventFilter::PreHandleKeyEvent(). set_character() should also be + // called. + void set_key_code(KeyboardCode key_code) { key_code_ = key_code; } + + private: + KeyboardCode key_code_; + // True if this is a translated character event (vs. a raw key down). Both + // share the same type: ET_KEY_PRESSED. + bool is_char_; + + uint16 character_; + uint16 unmodified_character_; +}; + +// A key event which is translated by an input method (IME). +// For example, if an IME receives a KeyEvent(VKEY_SPACE), and it does not +// consume the key, the IME usually generates and dispatches a +// TranslatedKeyEvent(VKEY_SPACE) event. If the IME receives a KeyEvent and +// it does consume the event, it might dispatch a +// TranslatedKeyEvent(VKEY_PROCESSKEY) event as defined in the DOM spec. +class UI_EXPORT TranslatedKeyEvent : public KeyEvent { + public: + TranslatedKeyEvent(const base::NativeEvent& native_event, bool is_char); + + // Used for synthetic events such as a VKEY_PROCESSKEY key event. + TranslatedKeyEvent(bool is_press, KeyboardCode key_code, int flags); + + // Changes the type() of the object from ET_TRANSLATED_KEY_* to ET_KEY_* so + // that RenderWidgetHostViewAura and NativeWidgetAura could handle the event. + void ConvertToKeyEvent(); +}; + +class UI_EXPORT DropTargetEvent : public LocatedEvent { + public: + DropTargetEvent(const OSExchangeData& data, + const gfx::Point& location, + const gfx::Point& root_location, + int source_operations) + : LocatedEvent(ET_DROP_TARGET_EVENT, location, root_location, 0), + data_(data), + source_operations_(source_operations) { + } + + const OSExchangeData& data() const { return data_; } + int source_operations() const { return source_operations_; } + + private: + // Data associated with the drag/drop session. + const OSExchangeData& data_; + + // Bitmask of supported DragDropTypes::DragOperation by the source. + int source_operations_; + + DISALLOW_COPY_AND_ASSIGN(DropTargetEvent); +}; + +class UI_EXPORT ScrollEvent : public MouseEvent { + public: + explicit ScrollEvent(const base::NativeEvent& native_event); + template <class T> + ScrollEvent(const ScrollEvent& model, + T* source, + T* target, + EventType type, + int flags) + : MouseEvent(model, source, target, type, flags), + x_offset_(model.x_offset_), + y_offset_(model.y_offset_) { + } + + float x_offset() const { return x_offset_; } + float y_offset() const { return y_offset_; } + + private: + float x_offset_; + float y_offset_; + + DISALLOW_COPY_AND_ASSIGN(ScrollEvent); +}; + +// TODO(beng): rename to GestureEvent after conversion is complete. +class UI_EXPORT GestureEventImpl : public LocatedEvent, + public GestureEvent { + public: + GestureEventImpl(EventType type, + int x, + int y, + int flags, + base::Time time_stamp, + const GestureEventDetails& details, + unsigned int touch_ids_bitfield); + + // Create a new GestureEventImpl which is identical to the provided model. + // If source / target windows are provided, the model location will be + // converted from |source| coordinate system to |target| coordinate system. + template <typename T> + GestureEventImpl(const GestureEventImpl& model, T* source, T* target) + : LocatedEvent(model, source, target), + details_(model.details_), + touch_ids_bitfield_(model.touch_ids_bitfield_) { + } + + virtual ~GestureEventImpl(); + + const GestureEventDetails& details() const { return details_; } + + // Returns the lowest touch-id of any of the touches which make up this + // gesture. + // If there are no touches associated with this gesture, returns -1. + virtual int GetLowestTouchId() const OVERRIDE; + + private: + GestureEventDetails details_; + + // The set of indices of ones in the binary representation of + // touch_ids_bitfield_ is the set of touch_ids associate with this gesture. + // This value is stored as a bitfield because the number of touch ids varies, + // but we currently don't need more than 32 touches at a time. + const unsigned int touch_ids_bitfield_; + + DISALLOW_COPY_AND_ASSIGN(GestureEventImpl); +}; + +} // namespace ui + +#endif // UI_BASE_EVENT_H_ diff --git a/ui/base/event_unittest.cc b/ui/base/event_unittest.cc new file mode 100644 index 0000000..7411859 --- /dev/null +++ b/ui/base/event_unittest.cc @@ -0,0 +1,102 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/event.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(USE_X11) +#include <X11/Xlib.h> +#include "ui/base/x/x11_util.h" +#endif + +namespace ui { + +TEST(EventTest, NoNativeEvent) { + KeyEvent keyev(ET_KEY_PRESSED, VKEY_SPACE, 0); + EXPECT_FALSE(keyev.HasNativeEvent()); +} + +TEST(EventTest, NativeEvent) { +#if defined(OS_WIN) + MSG native_event = { NULL, WM_KEYUP, VKEY_A, 0 }; + KeyEvent keyev(native_event, false); + EXPECT_TRUE(keyev.HasNativeEvent()); +#elif defined(USE_X11) + scoped_ptr<XEvent> native_event(new XEvent); + InitXKeyEventForTesting(ET_KEY_RELEASED, VKEY_A, 0, native_event.get()); + KeyEvent keyev(native_event.get(), false); + EXPECT_TRUE(keyev.HasNativeEvent()); +#endif +} + +TEST(EventTest, GetCharacter) { + // Check if Control+Enter returns 10. + KeyEvent keyev1(ET_KEY_PRESSED, VKEY_RETURN, EF_CONTROL_DOWN); + EXPECT_EQ(10, keyev1.GetCharacter()); + EXPECT_EQ(13, keyev1.GetUnmodifiedCharacter()); + // Check if Enter returns 13. + KeyEvent keyev2(ET_KEY_PRESSED, VKEY_RETURN, 0); + EXPECT_EQ(13, keyev2.GetCharacter()); + EXPECT_EQ(13, keyev2.GetUnmodifiedCharacter()); + +#if defined(USE_X11) + // For X11, test the functions with native_event() as well. crbug.com/107837 + scoped_ptr<XEvent> native_event(new XEvent); + + InitXKeyEventForTesting(ET_KEY_PRESSED, VKEY_RETURN, EF_CONTROL_DOWN, + native_event.get()); + KeyEvent keyev3(native_event.get(), false); + EXPECT_EQ(10, keyev3.GetCharacter()); + EXPECT_EQ(13, keyev3.GetUnmodifiedCharacter()); + + InitXKeyEventForTesting(ET_KEY_PRESSED, VKEY_RETURN, 0, native_event.get()); + KeyEvent keyev4(native_event.get(), false); + EXPECT_EQ(13, keyev4.GetCharacter()); + EXPECT_EQ(13, keyev4.GetUnmodifiedCharacter()); +#endif +} + +TEST(EventTest, ClickCount) { + const gfx::Point origin(0, 0); + MouseEvent mouseev(ET_MOUSE_PRESSED, origin, origin, 0); + for (int i = 1; i <=3 ; ++i) { + mouseev.SetClickCount(i); + EXPECT_EQ(i, mouseev.GetClickCount()); + } +} + +TEST(EventTest, Repeated) { + const gfx::Point origin(0, 0); + MouseEvent mouse_ev1(ET_MOUSE_PRESSED, origin, origin, 0); + MouseEvent mouse_ev2(ET_MOUSE_PRESSED, origin, origin, 0); + MouseEvent::TestApi test_ev1(&mouse_ev1); + MouseEvent::TestApi test_ev2(&mouse_ev2); + + base::TimeDelta start = base::TimeDelta::FromMilliseconds(0); + base::TimeDelta soon = start + base::TimeDelta::FromMilliseconds(1); + base::TimeDelta later = start + base::TimeDelta::FromMilliseconds(1000); + + // Close point. + test_ev1.set_location(gfx::Point(0, 0)); + test_ev2.set_location(gfx::Point(1, 0)); + test_ev1.set_time_stamp(start); + test_ev2.set_time_stamp(soon); + EXPECT_TRUE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2)); + + // Too far. + test_ev1.set_location(gfx::Point(0, 0)); + test_ev2.set_location(gfx::Point(10, 0)); + test_ev1.set_time_stamp(start); + test_ev2.set_time_stamp(soon); + EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2)); + + // Too long a time between clicks. + test_ev1.set_location(gfx::Point(0, 0)); + test_ev2.set_location(gfx::Point(0, 0)); + test_ev1.set_time_stamp(start); + test_ev2.set_time_stamp(later); + EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2)); +} + +} // namespace ui |