Index: ui/events/platform/platform_event_builder.cc |
diff --git a/ui/events/platform/platform_event_builder.cc b/ui/events/platform/platform_event_builder.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c5460114cbeb142cad7c815ace14dd9a8b79797d |
--- /dev/null |
+++ b/ui/events/platform/platform_event_builder.cc |
@@ -0,0 +1,282 @@ |
+// Copyright 2015 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/events/platform/platform_event_builder.h" |
+ |
+#if defined(USE_X11) |
+#include <X11/extensions/XInput2.h> |
+#include <X11/Xlib.h> |
+#include <X11/keysym.h> |
+#endif |
+ |
+#include "ui/events/event.h" |
+#include "ui/events/event_utils.h" |
+ |
+namespace ui { |
+namespace { |
+ |
+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 |
+} |
+ |
+bool IsX11SendEventTrue(const base::NativeEvent& event) { |
+#if defined(USE_X11) |
+ return event && event->xany.send_event; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+KeyEvent* last_key_event_ = nullptr; |
+MouseEvent* last_click_event_ = nullptr; |
+ |
+// We can create a MouseEvent for a native event more than once. We set this |
+// to true when the next event either has a different timestamp or we see a |
+// release signalling that the press (click) event was completed. |
+bool last_click_complete_ = false; |
+ |
+bool IsRepeated(const base::NativeEvent& native_event, 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(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; |
+ } |
+ if (event.key_code() == last_key_event_->key_code() && |
+ event.flags() == last_key_event_->flags() && |
+ (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() < |
+ kMaxAutoRepeatTimeMs) { |
+ return true; |
+ } |
+ delete last_key_event_; |
+ last_key_event_ = new KeyEvent(event); |
+ return false; |
+} |
+ |
+} // namespace |
+ |
+// static |
+MouseEvent PlatformEventBuilder::BuildMouseEvent( |
+ const base::NativeEvent& native_event) { |
+ MouseEvent mouse_event; |
+ FillEventFrom(native_event, &mouse_event); |
+ FillLocatedEventFrom(native_event, &mouse_event); |
+ FillMouseEventFrom(native_event, &mouse_event); |
+ return mouse_event; |
+} |
+ |
+// static |
+MouseWheelEvent PlatformEventBuilder::BuildMouseWheelEvent( |
+ const base::NativeEvent& native_event) { |
+ MouseWheelEvent mouse_wheel_event; |
+ FillEventFrom(native_event, &mouse_wheel_event); |
+ FillLocatedEventFrom(native_event, &mouse_wheel_event); |
+ FillMouseEventFrom(native_event, &mouse_wheel_event); |
+ FillMouseWheelEventFrom(native_event, &mouse_wheel_event); |
+ return mouse_wheel_event; |
+} |
+ |
+// static |
+TouchEvent PlatformEventBuilder::BuildTouchEvent( |
+ const base::NativeEvent& native_event) { |
+ TouchEvent touch_event; |
+ FillEventFrom(native_event, &touch_event); |
+ FillLocatedEventFrom(native_event, &touch_event); |
+ FillTouchEventFrom(native_event, &touch_event); |
+ return touch_event; |
+} |
+ |
+// static |
+KeyEvent PlatformEventBuilder::BuildKeyEvent( |
+ const base::NativeEvent& native_event) { |
+ KeyEvent key_event; |
+ FillEventFrom(native_event, &key_event); |
+ FillKeyEventFrom(native_event, &key_event); |
+ return key_event; |
+} |
+ |
+// static |
+ScrollEvent PlatformEventBuilder::BuildScrollEvent( |
+ const base::NativeEvent& native_event) { |
+ ScrollEvent scroll_event; |
+ FillEventFrom(native_event, &scroll_event); |
+ FillLocatedEventFrom(native_event, &scroll_event); |
+ FillMouseEventFrom(native_event, &scroll_event); |
+ FillScrollEventFrom(native_event, &scroll_event); |
+ return scroll_event; |
+} |
+ |
+// static |
+int PlatformEventBuilder::GetRepeatCount(const base::NativeEvent& native_event, |
+ 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(native_event)) { |
+ click_count = last_click_event_->GetClickCount(); |
+ } else if (MouseEvent::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; |
+} |
+ |
+// static |
+void PlatformEventBuilder::ResetLastClickForTest() { |
+ if (last_click_event_) { |
+ delete last_click_event_; |
+ last_click_event_ = NULL; |
+ last_click_complete_ = false; |
+ } |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillEventFrom(const base::NativeEvent& native_event, |
+ Event* event) { |
+ event->set_type(EventTypeFromNative(native_event)); |
+ event->set_time_stamp(EventTimeFromNative(native_event)); |
+ event->set_flags(EventFlagsFromNative(native_event)); |
+ |
+#if defined(USE_X11) |
+ if (native_event->type == GenericEvent) { |
+ XIDeviceEvent* xiev = |
+ static_cast<XIDeviceEvent*>(native_event->xcookie.data); |
+ event->set_source_device_id(xiev->sourceid); |
+ } |
+#endif |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillLocatedEventFrom( |
+ const base::NativeEvent& native_event, |
+ LocatedEvent* located_event) { |
+ gfx::PointF event_location = EventLocationFromNative(native_event); |
+ located_event->set_location(event_location); |
+ located_event->set_root_location(event_location); |
+ located_event->set_screen_location( |
+ EventSystemLocationFromNative(native_event)); |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillMouseEventFrom( |
+ const base::NativeEvent& native_event, |
+ MouseEvent* mouse_event) { |
+ mouse_event->set_changed_button_flags( |
+ GetChangedMouseButtonFlagsFromNative(native_event)); |
+ |
+ if (mouse_event->type() == ET_MOUSE_PRESSED || |
+ mouse_event->type() == ET_MOUSE_RELEASED) { |
+ mouse_event->SetClickCount(GetRepeatCount(native_event, *mouse_event)); |
+ } |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillMouseWheelEventFrom( |
+ const base::NativeEvent& native_event, |
+ MouseWheelEvent* mouse_wheel_event) { |
+ mouse_wheel_event->set_offset(GetMouseWheelOffset(native_event)); |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillTouchEventFrom( |
+ const base::NativeEvent& native_event, |
+ TouchEvent* touch_event) { |
+ touch_event->set_touch_id(GetTouchId(native_event)); |
+ touch_event->set_radius_x(GetTouchRadiusX(native_event)); |
+ touch_event->set_radius_y(GetTouchRadiusY(native_event)); |
+ touch_event->set_rotation_angle(GetTouchAngle(native_event)); |
+ touch_event->set_force(GetTouchForce(native_event)); |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillKeyEventFrom( |
+ const base::NativeEvent& native_event, |
+ KeyEvent* key_event) { |
+ key_event->set_key_code(KeyboardCodeFromNative(native_event)); |
+ key_event->set_code(CodeFromNative(native_event)); |
+ key_event->set_is_char(IsCharFromNative(native_event)); |
+ key_event->set_platform_keycode(PlatformKeycodeFromNative(native_event)); |
+ |
+ if (IsRepeated(native_event, *key_event)) |
+ key_event->set_flags(key_event->flags() | ui::EF_IS_REPEAT); |
+ |
+#if defined(USE_X11) |
+ key_event->NormalizeFlags(); |
+#endif |
+#if defined(OS_WIN) |
+ // Only Windows has native character events. |
+ if (key_event->is_char()) |
+ key_event->set_character(native_event.wParam); |
+#endif |
+} |
+ |
+// static |
+void PlatformEventBuilder::FillScrollEventFrom( |
+ const base::NativeEvent& native_event, |
+ ScrollEvent* scroll_event) { |
+ float x_offset = 0; |
+ float y_offset = 0; |
+ float x_offset_ordinal = 0; |
+ float y_offset_ordinal = 0; |
+ int finger_count = 0; |
+ |
+ if (scroll_event->type() == ET_SCROLL) { |
+ GetScrollOffsets(native_event, &x_offset, &y_offset, &x_offset_ordinal, |
+ &y_offset_ordinal, &finger_count); |
+ scroll_event->set_offset(x_offset, y_offset); |
+ scroll_event->set_offset_ordinal(x_offset_ordinal, y_offset_ordinal); |
+ scroll_event->set_finger_count(finger_count); |
+ } else if (scroll_event->type() == ET_SCROLL_FLING_START || |
+ scroll_event->type() == ET_SCROLL_FLING_CANCEL) { |
+ GetFlingData(native_event, &x_offset, &y_offset, &x_offset_ordinal, |
+ &y_offset_ordinal, NULL); |
+ scroll_event->set_offset(x_offset, y_offset); |
+ scroll_event->set_offset_ordinal(x_offset_ordinal, y_offset_ordinal); |
+ } else { |
+ NOTREACHED() << "Unexpected event type " << scroll_event->type() |
+ << " when constructing a ScrollEvent."; |
+ } |
+} |
+ |
+} // namespace ui |