summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorrjkroege@chromium.org <rjkroege@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-10 22:11:17 +0000
committerrjkroege@chromium.org <rjkroege@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-10 22:11:17 +0000
commitce83ede3e7f5176deca43bb2d83d07f77944ad02 (patch)
tree2b2b789f00e14d648d182ef77e2a94cf6edc9b91 /ui
parent374806bbff3c92885a11afc6520e3118faecff47 (diff)
downloadchromium_src-ce83ede3e7f5176deca43bb2d83d07f77944ad02.zip
chromium_src-ce83ede3e7f5176deca43bb2d83d07f77944ad02.tar.gz
chromium_src-ce83ede3e7f5176deca43bb2d83d07f77944ad02.tar.bz2
Event handling support for ozone.
Basic framework for handling events in ozone. Touch events are recognized and dispatched. Some button events are supported. BUG=178543 R=sadrul@chromium.org, sky@chromium.org Review URL: https://codereview.chromium.org/16466003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205324 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/aura/root_window_host_ozone.cc7
-rw-r--r--ui/aura/root_window_host_ozone.h3
-rw-r--r--ui/base/ozone/event_converter_ozone.cc33
-rw-r--r--ui/base/ozone/event_converter_ozone.h38
-rw-r--r--ui/base/ozone/event_factory_ozone.cc66
-rw-r--r--ui/base/ozone/event_factory_ozone.h35
-rw-r--r--ui/base/ozone/events_ozone.cc84
-rw-r--r--ui/base/ozone/key_event_converter_ozone.cc64
-rw-r--r--ui/base/ozone/key_event_converter_ozone.h27
-rw-r--r--ui/base/ozone/surface_factory_ozone.h7
-rw-r--r--ui/base/ozone/touch_event_converter_ozone.cc181
-rw-r--r--ui/base/ozone/touch_event_converter_ozone.h77
-rw-r--r--ui/base/ozone/touch_event_converter_ozone_unittest.cc397
-rw-r--r--ui/gl/gl_implementation_ozone.cc10
-rw-r--r--ui/ui.gyp9
-rw-r--r--ui/ui_unittests.gypi1
16 files changed, 1010 insertions, 29 deletions
diff --git a/ui/aura/root_window_host_ozone.cc b/ui/aura/root_window_host_ozone.cc
index b822a84..2e046bc 100644
--- a/ui/aura/root_window_host_ozone.cc
+++ b/ui/aura/root_window_host_ozone.cc
@@ -105,13 +105,6 @@ bool RootWindowHostOzone::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
return false;
}
-bool RootWindowHostOzone::GrabSnapshot(
- const gfx::Rect& snapshot_bounds,
- std::vector<unsigned char>* png_representation) {
- NOTIMPLEMENTED();
- return false;
-}
-
void RootWindowHostOzone::PostNativeEvent(
const base::NativeEvent& native_event) {
NOTIMPLEMENTED();
diff --git a/ui/aura/root_window_host_ozone.h b/ui/aura/root_window_host_ozone.h
index 857d8c5..107f2bf 100644
--- a/ui/aura/root_window_host_ozone.h
+++ b/ui/aura/root_window_host_ozone.h
@@ -49,9 +49,6 @@ class RootWindowHostOzone : public RootWindowHost,
virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
const gfx::Point& dest_offset,
SkCanvas* canvas) OVERRIDE;
- virtual bool GrabSnapshot(const gfx::Rect& snapshot_bounds,
- std::vector<unsigned char>* png_representation)
- OVERRIDE;
virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
virtual void PrepareForShutdown() OVERRIDE;
diff --git a/ui/base/ozone/event_converter_ozone.cc b/ui/base/ozone/event_converter_ozone.cc
new file mode 100644
index 0000000..0be5036
--- /dev/null
+++ b/ui/base/ozone/event_converter_ozone.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2013 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/ozone/event_converter_ozone.h"
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/message_pump_ozone.h"
+#include "ui/base/events/event.h"
+
+namespace {
+
+void DispatchEventHelper(scoped_ptr<ui::Event> key) {
+ base::MessagePumpOzone::Current()->Dispatch(key.get());
+}
+
+} // namespace
+
+namespace ui {
+
+EventConverterOzone::EventConverterOzone() {
+}
+
+EventConverterOzone::~EventConverterOzone() {
+}
+
+void EventConverterOzone::DispatchEvent(scoped_ptr<ui::Event> event) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&DispatchEventHelper, base::Passed(&event)));
+}
+
+} // namespace ui
diff --git a/ui/base/ozone/event_converter_ozone.h b/ui/base/ozone/event_converter_ozone.h
new file mode 100644
index 0000000..766b1df
--- /dev/null
+++ b/ui/base/ozone/event_converter_ozone.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2013 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_OZONE_EVENT_CONVERTER_OZONE_H_
+#define UI_BASE_OZONE_EVENT_CONVERTER_OZONE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_pump_libevent.h"
+
+namespace ui {
+class Event;
+
+// In ozone, Chrome reads events from file descriptors created from Linux device
+// drivers. The |MessagePumpLibevent::Watcher| parent class provides the
+// functionality to watch a file descriptor for the arrival of new data and
+// notify its subclasses. Device-specific event converters turn bytes read from
+// the file descriptor into |ui::Event| instances. This class provides the
+// functionality needed in common across all converters: dispatching the
+// |ui::Event| to aura.
+class EventConverterOzone : public base::MessagePumpLibevent::Watcher {
+ public:
+ EventConverterOzone();
+ virtual ~EventConverterOzone();
+
+ protected:
+ // Subclasses should use this method to post a task that will dispatch
+ // |event| from the UI message loop. This method takes ownership of
+ // |event|. |event| will be deleted at the end of the posted task.
+ void DispatchEvent(scoped_ptr<ui::Event> event);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EventConverterOzone);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_OZONE_EVENT_CONVERTER_OZONE_H_
diff --git a/ui/base/ozone/event_factory_ozone.cc b/ui/base/ozone/event_factory_ozone.cc
new file mode 100644
index 0000000..3189f1d
--- /dev/null
+++ b/ui/base/ozone/event_factory_ozone.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2013 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/ozone/event_factory_ozone.h"
+
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "base/message_pump_ozone.h"
+#include "base/stringprintf.h"
+#include "ui/base/ozone/key_event_converter_ozone.h"
+#include "ui/base/ozone/touch_event_converter_ozone.h"
+
+namespace ui {
+
+EventFactoryOzone::EventFactoryOzone() {}
+
+EventFactoryOzone::~EventFactoryOzone() {
+ for (unsigned i = 0; i < fd_controllers_.size(); i++) {
+ fd_controllers_[i]->StopWatchingFileDescriptor();
+ }
+}
+
+void EventFactoryOzone::CreateEvdevWatchers() {
+ // The number of devices in the directory is unknown without reading
+ // the contents of the directory. Further, with hot-plugging, the entries
+ // might decrease during the execution of this loop. So exciting from the
+ // loop on the first failure of open below is both cheaper and more
+ // reliable.
+ for (int id = 0; true; id++) {
+ std::string path = base::StringPrintf("/dev/input/event%d", id);
+ int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ break;
+ size_t evtype = 0;
+ COMPILE_ASSERT(sizeof(evtype) * 8 >= EV_MAX, evtype_wide_enough);
+ if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype)), &evtype) == -1) {
+ DLOG(ERROR) << "failed ioctl EVIOCGBIT 0" << path;
+ close(fd);
+ continue;
+ }
+
+ EventConverterOzone* watcher = NULL;
+ // TODO(rjkroege) Add more device types. Support hot-plugging.
+ if (evtype & (1 << EV_ABS))
+ watcher = new TouchEventConverterOzone(fd, id);
+ else if (evtype & (1 << EV_KEY))
+ watcher = new KeyEventConverterOzone();
+
+ if (watcher) {
+ base::MessagePumpLibevent::FileDescriptorWatcher* controller =
+ new base::MessagePumpLibevent::FileDescriptorWatcher();
+ base::MessagePumpOzone::Current()->WatchFileDescriptor(
+ fd, true, base::MessagePumpLibevent::WATCH_READ, controller, watcher);
+ evdev_watchers_.push_back(watcher);
+ fd_controllers_.push_back(controller);
+ } else {
+ close(fd);
+ }
+ }
+}
+
+} // namespace ui
diff --git a/ui/base/ozone/event_factory_ozone.h b/ui/base/ozone/event_factory_ozone.h
new file mode 100644
index 0000000..adf5b81
--- /dev/null
+++ b/ui/base/ozone/event_factory_ozone.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2013 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_OZONE_EVENT_FACTORY_OZONE_H_
+#define UI_BASE_OZONE_EVENT_FACTORY_OZONE_H_
+
+#include "base/memory/scoped_vector.h"
+#include "base/message_pump_libevent.h"
+#include "ui/base/ozone/event_converter_ozone.h"
+#include "ui/base/ui_export.h"
+
+namespace ui {
+
+// Sets up and manages watcher instances for event sources in /dev/input/*.
+class UI_EXPORT EventFactoryOzone {
+ public:
+ EventFactoryOzone();
+ virtual ~EventFactoryOzone();
+
+ // Opens /dev/input/* event sources as appropriate and set up watchers.
+ void CreateEvdevWatchers();
+
+ private:
+ // FileDescriptorWatcher instances for each watched source of events.
+ ScopedVector<EventConverterOzone> evdev_watchers_;
+ ScopedVector<base::MessagePumpLibevent::FileDescriptorWatcher>
+ fd_controllers_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventFactoryOzone);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_OZONE_EVENT_FACTORY_OZONE_H_
diff --git a/ui/base/ozone/events_ozone.cc b/ui/base/ozone/events_ozone.cc
index 8732ddb..f5481ce 100644
--- a/ui/base/ozone/events_ozone.cc
+++ b/ui/base/ozone/events_ozone.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 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.
@@ -8,73 +8,93 @@
namespace ui {
+void UpdateDeviceList() { NOTIMPLEMENTED(); }
+
base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
- ui::Event* event = static_cast<ui::Event*>(native_event);
+ const ui::Event* event = static_cast<const ui::Event*>(native_event);
return event->time_stamp();
}
int EventFlagsFromNative(const base::NativeEvent& native_event) {
- ui::Event* event = static_cast<ui::Event*>(native_event);
+ const ui::Event* event = static_cast<const ui::Event*>(native_event);
return event->flags();
}
EventType EventTypeFromNative(const base::NativeEvent& native_event) {
- ui::Event* event = static_cast<ui::Event*>(native_event);
+ const ui::Event* event = static_cast<const ui::Event*>(native_event);
return event->type();
}
+gfx::Point EventSystemLocationFromNative(
+ const base::NativeEvent& native_event) {
+ const ui::LocatedEvent* e =
+ static_cast<const ui::LocatedEvent*>(native_event);
+ DCHECK(e->IsMouseEvent() || e->IsTouchEvent() || e->IsGestureEvent() ||
+ e->IsScrollEvent());
+ return e->location();
+}
+
gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
- ui::LocatedEvent* event = static_cast<ui::LocatedEvent*>(native_event);
- DCHECK(event->IsMouseEvent() || event->IsTouchEvent() ||
- event->IsGestureEvent() || event->IsScrollEvent());
- return event->location();
+ return EventSystemLocationFromNative(native_event);
}
int GetChangedMouseButtonFlagsFromNative(
const base::NativeEvent& native_event) {
- ui::MouseEvent* event = static_cast<ui::MouseEvent*>(native_event);
+ const ui::MouseEvent* event =
+ static_cast<const ui::MouseEvent*>(native_event);
DCHECK(event->IsMouseEvent());
return event->changed_button_flags();
}
KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
- ui::KeyEvent* event = static_cast<ui::KeyEvent*>(native_event);
+ const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
DCHECK(event->IsKeyEvent());
return event->key_code();
}
+bool IsMouseEvent(const base::NativeEvent& native_event) {
+ const ui::Event* e = static_cast<const ui::Event*>(native_event);
+ return e->IsMouseEvent();
+}
+
gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
- ui::MouseWheelEvent* event = static_cast<ui::MouseWheelEvent*>(native_event);
+ const ui::MouseWheelEvent* event =
+ static_cast<const ui::MouseWheelEvent*>(native_event);
DCHECK(event->type() == ET_MOUSEWHEEL);
return event->offset();
}
int GetTouchId(const base::NativeEvent& native_event) {
- ui::TouchEvent* event = static_cast<ui::TouchEvent*>(native_event);
+ const ui::TouchEvent* event =
+ static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
return event->touch_id();
}
float GetTouchRadiusX(const base::NativeEvent& native_event) {
- ui::TouchEvent* event = static_cast<ui::TouchEvent*>(native_event);
+ const ui::TouchEvent* event =
+ static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
return event->radius_x();
}
float GetTouchRadiusY(const base::NativeEvent& native_event) {
- ui::TouchEvent* event = static_cast<ui::TouchEvent*>(native_event);
+ const ui::TouchEvent* event =
+ static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
return event->radius_y();
}
float GetTouchAngle(const base::NativeEvent& native_event) {
- ui::TouchEvent* event = static_cast<ui::TouchEvent*>(native_event);
+ const ui::TouchEvent* event =
+ static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
return event->rotation_angle();
}
float GetTouchForce(const base::NativeEvent& native_event) {
- ui::TouchEvent* event = static_cast<ui::TouchEvent*>(native_event);
+ const ui::TouchEvent* event =
+ static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
return event->force();
}
@@ -99,4 +119,36 @@ bool GetFlingData(const base::NativeEvent& native_event,
return false;
}
+bool GetGestureTimes(const base::NativeEvent& native_event,
+ double* start_time,
+ double* end_time) {
+ *start_time = 0;
+ *end_time = 0;
+ return false;
+}
+
+void SetNaturalScroll(bool /* enabled */) { NOTIMPLEMENTED(); }
+
+bool IsNaturalScrollEnabled() { return false; }
+
+bool IsTouchpadEvent(const base::NativeEvent& event) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool IsNoopEvent(const base::NativeEvent& event) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+base::NativeEvent CreateNoopEvent() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+int GetModifiersFromKeyState() {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
} // namespace ui
diff --git a/ui/base/ozone/key_event_converter_ozone.cc b/ui/base/ozone/key_event_converter_ozone.cc
new file mode 100644
index 0000000..f4ff3db
--- /dev/null
+++ b/ui/base/ozone/key_event_converter_ozone.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 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/ozone/key_event_converter_ozone.h"
+
+#include <linux/input.h>
+
+#include "ui/base/events/event.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+namespace {
+
+ui::KeyboardCode KeyboardCodeFromButton(int code) {
+ switch (code) {
+ case KEY_VOLUMEDOWN:
+ return ui::VKEY_VOLUME_DOWN;
+
+ case KEY_VOLUMEUP:
+ return ui::VKEY_VOLUME_UP;
+
+ case KEY_POWER:
+ return ui::VKEY_POWER;
+ }
+
+ LOG(ERROR) << "Unknown key code: " << code;
+ return static_cast<ui::KeyboardCode>(0);
+}
+
+} // namespace
+
+namespace ui {
+
+// TODO(rjkroege): Stop leaking file descriptor.
+KeyEventConverterOzone::KeyEventConverterOzone() {}
+KeyEventConverterOzone::~KeyEventConverterOzone() {}
+
+void KeyEventConverterOzone::OnFileCanReadWithoutBlocking(int fd) {
+ input_event inputs[4];
+ ssize_t read_size = read(fd, inputs, sizeof(inputs));
+ if (read_size <= 0)
+ return;
+
+ CHECK_EQ(read_size % sizeof(*inputs), 0u);
+ for (unsigned i = 0; i < read_size / sizeof(*inputs); ++i) {
+ const input_event& input = inputs[i];
+ if (input.type == EV_KEY) {
+ scoped_ptr<KeyEvent> key(
+ new KeyEvent(input.value == 1 ? ET_KEY_PRESSED : ET_KEY_RELEASED,
+ KeyboardCodeFromButton(input.code),
+ 0,
+ true));
+ DispatchEvent(key.PassAs<ui::Event>());
+ } else if (input.type == EV_SYN) {
+ // TODO(sadrul): Handle this case appropriately.
+ }
+ }
+}
+
+void KeyEventConverterOzone::OnFileCanWriteWithoutBlocking(int fd) {
+ NOTREACHED();
+}
+
+} // namespace ui
diff --git a/ui/base/ozone/key_event_converter_ozone.h b/ui/base/ozone/key_event_converter_ozone.h
new file mode 100644
index 0000000..29ea26a
--- /dev/null
+++ b/ui/base/ozone/key_event_converter_ozone.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2013 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_OZONE_KEY_EVENT_CONVERTER_OZONE_H_
+#define UI_BASE_OZONE_KEY_EVENT_CONVERTER_OZONE_H_
+
+#include "ui/base/ozone/event_converter_ozone.h"
+
+namespace ui {
+
+class KeyEventConverterOzone : public EventConverterOzone {
+ public:
+ KeyEventConverterOzone();
+ virtual ~KeyEventConverterOzone();
+
+ private:
+ // Overidden from base::MessagePumpLibevent::Watcher.
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyEventConverterOzone);
+};
+
+} // namspace ui
+
+#endif // UI_BASE_OZONE_KEY_EVENT_CONVERTER_OZONE_H_
diff --git a/ui/base/ozone/surface_factory_ozone.h b/ui/base/ozone/surface_factory_ozone.h
index c9c3351..bd22d35 100644
--- a/ui/base/ozone/surface_factory_ozone.h
+++ b/ui/base/ozone/surface_factory_ozone.h
@@ -5,7 +5,8 @@
#ifndef UI_BASE_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
#define UI_BASE_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
-#include "ui/gfx/native_widget_types.h"
+#include "ui/base/ui_export.h"
+#include "ui/gfx/native_widget_types.h"
namespace gfx {
class VSyncProvider;
@@ -19,14 +20,14 @@ class SurfaceFactoryOzone {
virtual ~SurfaceFactoryOzone();
// Returns the instance
- static SurfaceFactoryOzone* GetInstance();
+ UI_EXPORT static SurfaceFactoryOzone* GetInstance();
// Returns a display spec as in |CreateDisplayFromSpec| for the default
// native surface.
virtual const char* DefaultDisplaySpec();
// Sets the implementation delegate.
- static void SetInstance(SurfaceFactoryOzone* impl);
+ UI_EXPORT static void SetInstance(SurfaceFactoryOzone* impl);
// TODO(rjkroege): Add a status code if necessary.
// Configures the display hardware. Must be called from within the GPU
diff --git a/ui/base/ozone/touch_event_converter_ozone.cc b/ui/base/ozone/touch_event_converter_ozone.cc
new file mode 100644
index 0000000..0784fb4
--- /dev/null
+++ b/ui/base/ozone/touch_event_converter_ozone.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2013 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/ozone/touch_event_converter_ozone.h"
+
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <cmath>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/message_pump_ozone.h"
+#include "ui/base/events/event.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/ozone/surface_factory_ozone.h"
+
+namespace {
+
+// Number is determined empirically.
+// TODO(rjkroege): Configure this per device.
+const float kFingerWidth = 25.f;
+
+} // namespace
+
+namespace ui {
+
+TouchEventConverterOzone::TouchEventConverterOzone(int fd, int id)
+ : pressure_min_(0),
+ pressure_max_(0),
+ x_scale_(1.),
+ y_scale_(1.),
+ current_slot_(0),
+ fd_(fd),
+ id_(id) {
+ Init();
+}
+
+TouchEventConverterOzone::~TouchEventConverterOzone() {
+ if (close(fd_) < 0)
+ DLOG(WARNING) << "failed close on /dev/input/event" << id_;
+}
+
+void TouchEventConverterOzone::Init() {
+ input_absinfo abs = {};
+ if (ioctl(fd_, EVIOCGABS(ABS_MT_SLOT), &abs) != -1) {
+ CHECK_GE(abs.maximum, abs.minimum);
+ CHECK_GE(abs.minimum, 0);
+ } else {
+ DLOG(WARNING) << "failed ioctl EVIOCGABS ABS_MT_SLOT event" << id_;
+ }
+ if (ioctl(fd_, EVIOCGABS(ABS_MT_PRESSURE), &abs) != -1) {
+ pressure_min_ = abs.minimum;
+ pressure_max_ = abs.maximum;
+ } else {
+ DLOG(WARNING) << "failed ioctl EVIOCGABS ABS_MT_PRESSURE event" << id_;
+ }
+ int x_min = 0, x_max = 0;
+ if (ioctl(fd_, EVIOCGABS(ABS_MT_POSITION_X), &abs) != -1) {
+ x_min = abs.minimum;
+ x_max = abs.maximum;
+ } else {
+ LOG(WARNING) << "failed ioctl EVIOCGABS ABS_X event" << id_;
+ }
+ int y_min = 0, y_max = 0;
+ if (ioctl(fd_, EVIOCGABS(ABS_MT_POSITION_Y), &abs) != -1) {
+ y_min = abs.minimum;
+ y_max = abs.maximum;
+ } else {
+ LOG(WARNING) << "failed ioctl EVIOCGABS ABS_Y event" << id_;
+ }
+ if (x_max && y_max && SurfaceFactoryOzone::GetInstance()) {
+ const char* display =
+ SurfaceFactoryOzone::GetInstance()->DefaultDisplaySpec();
+ int screen_width, screen_height;
+ int sc = sscanf(display, "%dx%d", &screen_width, &screen_height);
+ if (sc == 2) {
+ x_scale_ = (double)screen_width / (x_max - x_min);
+ y_scale_ = (double)screen_height / (y_max - y_min);
+ LOG(INFO) << "touch input x_scale=" << x_scale_
+ << " y_scale=" << y_scale_;
+ } else {
+ LOG(WARNING) << "malformed display spec from "
+ << "SurfaceFactoryOzone::DefaultDisplaySpec";
+ }
+ }
+}
+
+void TouchEventConverterOzone::OnFileCanWriteWithoutBlocking(int /* fd */) {
+ // Read-only file-descriptors.
+ NOTREACHED();
+}
+
+void TouchEventConverterOzone::OnFileCanReadWithoutBlocking(int fd) {
+ input_event inputs[MAX_FINGERS * 6 + 1];
+ ssize_t read_size = read(fd, inputs, sizeof(inputs));
+ if (read_size <= 0)
+ return;
+
+ for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
+ const input_event& input = inputs[i];
+ if (input.type == EV_ABS) {
+ switch (input.code) {
+ case ABS_MT_TOUCH_MAJOR:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].major_ = input.value;
+ break;
+ case ABS_X:
+ case ABS_MT_POSITION_X:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].x_ = roundf(input.value * x_scale_);
+ break;
+ case ABS_Y:
+ case ABS_MT_POSITION_Y:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].y_ = roundf(input.value * y_scale_);
+ break;
+ case ABS_MT_TRACKING_ID:
+ altered_slots_.set(current_slot_);
+ if (input.value < 0) {
+ events_[current_slot_].type_ = ET_TOUCH_RELEASED;
+ } else {
+ events_[current_slot_].finger_ = input.value;
+ events_[current_slot_].type_ = ET_TOUCH_PRESSED;
+ }
+ break;
+ case ABS_MT_PRESSURE:
+ case ABS_PRESSURE:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].pressure_ = input.value - pressure_min_;
+ events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
+ break;
+ case ABS_MT_SLOT:
+ current_slot_ = input.value;
+ altered_slots_.set(current_slot_);
+ break;
+ default:
+ NOTREACHED();
+ }
+ } else if (input.type == EV_SYN) {
+ switch (input.code) {
+ case SYN_REPORT:
+ for (int j = 0; j < MAX_FINGERS; j++) {
+ if (altered_slots_[j]) {
+ // TODO(rjkroege): Support elliptical finger regions.
+ scoped_ptr<TouchEvent> tev(new TouchEvent(
+ events_[j].type_,
+ gfx::Point(events_[j].x_, events_[j].y_),
+ /* flags */ 0,
+ /* touch_id */ j,
+ base::TimeDelta::FromMicroseconds(
+ input.time.tv_sec * 1000000 + input.time.tv_usec),
+ events_[j].pressure_ * kFingerWidth,
+ events_[j].pressure_ * kFingerWidth,
+ /* angle */ 0.,
+ events_[j].pressure_));
+ events_[j].type_ = ET_TOUCH_MOVED;
+ DispatchEvent(tev.PassAs<ui::Event>());
+ }
+ }
+ altered_slots_.reset();
+ break;
+ case SYN_MT_REPORT:
+ case SYN_CONFIG:
+ case SYN_DROPPED:
+ NOTREACHED() << "SYN_MT events not supported.";
+ break;
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+}
+
+} // namespace ui
diff --git a/ui/base/ozone/touch_event_converter_ozone.h b/ui/base/ozone/touch_event_converter_ozone.h
new file mode 100644
index 0000000..f246b5c
--- /dev/null
+++ b/ui/base/ozone/touch_event_converter_ozone.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2013 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_OZONE_TOUCH_EVENT_CONVERTER_OZONE_H_
+#define UI_BASE_OZONE_TOUCH_EVENT_CONVERTER_OZONE_H_
+
+#include <bitset>
+
+#include "base/compiler_specific.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/ozone/event_converter_ozone.h"
+#include "ui/base/ui_export.h"
+
+namespace ui {
+
+class TouchEvent;
+
+class UI_EXPORT TouchEventConverterOzone : public EventConverterOzone {
+ public:
+ enum {
+ MAX_FINGERS = 11
+ };
+ TouchEventConverterOzone(int fd, int id);
+ virtual ~TouchEventConverterOzone();
+
+ private:
+ friend class MockTouchEventConverterOzone;
+
+ // Unsafe part of initialization.
+ void Init();
+
+ // Overidden from base::MessagePumpLibevent::Watcher.
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ // Pressure values.
+ int pressure_min_;
+ int pressure_max_; // Used to normalize pressure values.
+
+ // Touch scaling.
+ float x_scale_;
+ float y_scale_;
+
+ // Touch point currently being updated from the /dev/input/event* stream.
+ int current_slot_;
+
+ // File descriptor for the /dev/input/event* instance.
+ int fd_;
+
+ // Number corresponding to * in the source evdev device: /dev/input/event*
+ int id_;
+
+ // Bit field tracking which in-progress touch points have been modified
+ // without a syn event.
+ std::bitset<MAX_FINGERS> altered_slots_;
+
+ struct InProgressEvents {
+ int x_;
+ int y_;
+ int id_; // Device reported "unique" touch point id; -1 means not active
+ int finger_; // "Finger" id starting from 0; -1 means not active
+
+ EventType type_;
+ int major_;
+ float pressure_;
+ };
+
+ // In-progress touch points.
+ InProgressEvents events_[MAX_FINGERS];
+
+ DISALLOW_COPY_AND_ASSIGN(TouchEventConverterOzone);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_OZONE_TOUCH_EVENT_CONVERTER_OZONE_H_
diff --git a/ui/base/ozone/touch_event_converter_ozone_unittest.cc b/ui/base/ozone/touch_event_converter_ozone_unittest.cc
new file mode 100644
index 0000000..88194df
--- /dev/null
+++ b/ui/base/ozone/touch_event_converter_ozone_unittest.cc
@@ -0,0 +1,397 @@
+// Copyright (c) 2013 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 <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/events/event.h"
+#include "ui/base/ozone/touch_event_converter_ozone.h"
+
+
+namespace {
+
+static int SetNonBlocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+} // namespace
+
+namespace ui {
+
+class MockTouchEventConverterOzone : public TouchEventConverterOzone,
+ public base::MessageLoop::Dispatcher {
+ public:
+ MockTouchEventConverterOzone(int a, int b);
+ virtual ~MockTouchEventConverterOzone() {};
+
+ void ConfigureReadMock(struct input_event* queue,
+ long read_this_many,
+ long queue_index);
+
+ unsigned size() { return dispatched_events_.size(); }
+ TouchEvent* event(unsigned index) { return dispatched_events_[index]; }
+
+ // Actually dispatch the event reader code.
+ void ReadNow() {
+ OnFileCanReadWithoutBlocking(read_pipe_);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ private:
+ int read_pipe_;
+ int write_pipe_;
+
+ ScopedVector<TouchEvent> dispatched_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockTouchEventConverterOzone);
+};
+
+MockTouchEventConverterOzone::MockTouchEventConverterOzone(int a, int b)
+ : TouchEventConverterOzone(a, b) {
+ pressure_min_ = 30;
+ pressure_max_ = 60;
+
+ int fds[2];
+
+ DCHECK(pipe(fds) >= 0) << "pipe() failed, errno: " << errno;
+ DCHECK(SetNonBlocking(fds[0]) == 0)
+ << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ DCHECK(SetNonBlocking(fds[1]) == 0)
+ << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ read_pipe_ = fds[0];
+ write_pipe_ = fds[1];
+}
+
+bool MockTouchEventConverterOzone::Dispatch(const base::NativeEvent& event) {
+ ui::TouchEvent* ev = new ui::TouchEvent(event);
+ dispatched_events_.push_back(ev);
+ return true;
+}
+
+void MockTouchEventConverterOzone::ConfigureReadMock(struct input_event* queue,
+ long read_this_many,
+ long queue_index) {
+ int nwrite = HANDLE_EINTR(write(write_pipe_,
+ queue + queue_index,
+ sizeof(struct input_event) * read_this_many));
+ DCHECK(nwrite ==
+ static_cast<int>(sizeof(struct input_event) * read_this_many))
+ << "write() failed, errno: " << errno;
+}
+
+} // namespace ui
+
+// Test fixture.
+class TouchEventConverterOzoneTest : public testing::Test {
+ public:
+ TouchEventConverterOzoneTest() {}
+
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ loop_ = new base::MessageLoop(base::MessageLoop::TYPE_UI);
+ device_ = new ui::MockTouchEventConverterOzone(-1, 2);
+ base::MessagePumpOzone::Current()->AddDispatcherForRootWindow(device_);
+ }
+ virtual void TearDown() OVERRIDE {
+ delete device_;
+ delete loop_;
+ }
+
+ ui::MockTouchEventConverterOzone* device() { return device_; }
+
+ private:
+ base::MessageLoop* loop_;
+ ui::MockTouchEventConverterOzone* device_;
+ DISALLOW_COPY_AND_ASSIGN(TouchEventConverterOzoneTest);
+};
+
+// TODO(rjkroege): Test for valid handling of time stamps.
+TEST_F(TouchEventConverterOzoneTest, TouchDown) {
+ ui::MockTouchEventConverterOzone* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ dev->ConfigureReadMock(mock_kernel_queue, 1, 0);
+ dev->ReadNow();
+ EXPECT_EQ(0u, dev->size());
+
+ dev->ConfigureReadMock(mock_kernel_queue, 2, 1);
+ dev->ReadNow();
+ EXPECT_EQ(0u, dev->size());
+
+ dev->ConfigureReadMock(mock_kernel_queue, 3, 3);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ ui::TouchEvent* event = dev->event(0);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_PRESSED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(51, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(.5f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+}
+
+TEST_F(TouchEventConverterOzoneTest, NoEvents) {
+ ui::MockTouchEventConverterOzone* dev = device();
+ dev->ConfigureReadMock(NULL, 0, 0);
+ EXPECT_EQ(0u, dev->size());
+}
+
+TEST_F(TouchEventConverterOzoneTest, TouchMove) {
+ ui::MockTouchEventConverterOzone* dev = device();
+
+ struct input_event mock_kernel_queue_press[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ struct input_event mock_kernel_queue_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 50},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 43}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ struct input_event mock_kernel_queue_move2[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 42}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Setup and discard a press.
+ dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ dev->ConfigureReadMock(mock_kernel_queue_move1, 4, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+ ui::TouchEvent* event = dev->event(1);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(43, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(2.f / 3.f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+
+ dev->ConfigureReadMock(mock_kernel_queue_move2, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(3u, dev->size());
+ event = dev->event(2);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(42, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(2.f / 3.f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+}
+
+TEST_F(TouchEventConverterOzoneTest, TouchRelease) {
+ ui::MockTouchEventConverterOzone* dev = device();
+
+ struct input_event mock_kernel_queue_press[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ struct input_event mock_kernel_queue_release[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Setup and discard a press.
+ dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+ ui::TouchEvent* event = dev->event(0);
+ EXPECT_FALSE(event == NULL);
+
+ dev->ConfigureReadMock(mock_kernel_queue_release, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+ event = dev->event(1);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_RELEASED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(51, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(.5f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+}
+
+TEST_F(TouchEventConverterOzoneTest, TwoFingerGesture) {
+ ui::MockTouchEventConverterOzone* dev = device();
+
+ ui::TouchEvent* ev0;
+ ui::TouchEvent* ev1;
+
+ struct input_event mock_kernel_queue_press0[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ // Setup and discard a press.
+ dev->ConfigureReadMock(mock_kernel_queue_press0, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ struct input_event mock_kernel_queue_move0[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ // Setup and discard a move.
+ dev->ConfigureReadMock(mock_kernel_queue_move0, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+
+ struct input_event mock_kernel_queue_move0press1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ {{0, 0}, EV_ABS, ABS_MT_SLOT, 1}, {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 686},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 101},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 102}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ // Move on 0, press on 1.
+ dev->ConfigureReadMock(mock_kernel_queue_move0press1, 9, 0);
+ dev->ReadNow();
+ EXPECT_EQ(4u, dev->size());
+ ev0 = dev->event(2);
+ ev1 = dev->event(3);
+
+ // Move
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
+ EXPECT_EQ(40, ev0->x());
+ EXPECT_EQ(51, ev0->y());
+ EXPECT_EQ(0, ev0->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev0->force());
+ EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
+
+ // Press
+ EXPECT_EQ(ui::ET_TOUCH_PRESSED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(101, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+
+ // Stationary 0, Moves 1.
+ struct input_event mock_kernel_queue_stationary0_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_stationary0_move1, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(5u, dev->size());
+ ev1 = dev->event(4);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(40, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+
+ // Move 0, stationary 1.
+ struct input_event mock_kernel_queue_move0_stationary1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_SLOT, 0}, {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 39},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_move0_stationary1, 3, 0);
+ dev->ReadNow();
+ EXPECT_EQ(6u, dev->size());
+ ev0 = dev->event(5);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
+ EXPECT_EQ(39, ev0->x());
+ EXPECT_EQ(51, ev0->y());
+ EXPECT_EQ(0, ev0->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev0->force());
+ EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
+
+ // Release 0, move 1.
+ struct input_event mock_kernel_queue_release0_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_ABS, ABS_MT_SLOT, 1},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 38}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_release0_move1, 4, 0);
+ dev->ReadNow();
+ EXPECT_EQ(8u, dev->size());
+ ev0 = dev->event(6);
+ ev1 = dev->event(7);
+
+ EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev0->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
+ EXPECT_EQ(39, ev0->x());
+ EXPECT_EQ(51, ev0->y());
+ EXPECT_EQ(0, ev0->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev0->force());
+ EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(38, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+
+ // Release 1.
+ struct input_event mock_kernel_queue_release1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_release1, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(9u, dev->size());
+ ev1 = dev->event(8);
+
+ EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(38, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+}
diff --git a/ui/gl/gl_implementation_ozone.cc b/ui/gl/gl_implementation_ozone.cc
index b3bdfc9..481a309 100644
--- a/ui/gl/gl_implementation_ozone.cc
+++ b/ui/gl/gl_implementation_ozone.cc
@@ -96,4 +96,14 @@ void ClearGLBindings() {
UnloadGLNativeLibraries();
}
+bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
+ switch (GetGLImplementation()) {
+ case kGLImplementationEGLGLES2:
+ return GetGLWindowSystemBindingInfoEGL(info);
+ default:
+ return false;
+ }
+ return false;
+}
+
} // namespace gfx
diff --git a/ui/ui.gyp b/ui/ui.gyp
index 960bf2a..b62489a 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -279,8 +279,17 @@
'base/models/tree_node_iterator.h',
'base/models/tree_node_model.h',
'base/ozone/events_ozone.cc',
+ 'base/ozone/event_factory_ozone.cc',
+ 'base/ozone/event_factory_ozone.h',
+ 'base/ozone/event_converter_ozone.cc',
+ 'base/ozone/event_converter_ozone.h',
+ 'base/ozone/events_ozone.cc',
+ 'base/ozone/key_event_converter_ozone.cc',
+ 'base/ozone/key_event_converter_ozone.h',
'base/ozone/surface_factory_ozone.cc',
'base/ozone/surface_factory_ozone.h',
+ 'base/ozone/touch_event_converter_ozone.cc',
+ 'base/ozone/touch_event_converter_ozone.h',
'base/range/range.cc',
'base/range/range.h',
'base/range/range_mac.mm',
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
index 30a16dc..2d1e78c 100644
--- a/ui/ui_unittests.gypi
+++ b/ui/ui_unittests.gypi
@@ -152,6 +152,7 @@
'base/models/list_model_unittest.cc',
'base/models/list_selection_model_unittest.cc',
'base/models/tree_node_model_unittest.cc',
+ 'base/ozone/touch_event_converter_ozone_unittest.cc',
'base/test/data/resource.h',
'base/text/bytes_formatting_unittest.cc',
'base/text/utf16_indexing_unittest.cc',