| 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 | 
|  |