Index: ui/events/ozone/evdev/tablet_event_converter_evdev.cc |
diff --git a/ui/events/ozone/evdev/tablet_event_converter_evdev.cc b/ui/events/ozone/evdev/tablet_event_converter_evdev.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8949309efdde3bbf64f3ddb66a6bc707949ca9b9 |
--- /dev/null |
+++ b/ui/events/ozone/evdev/tablet_event_converter_evdev.cc |
@@ -0,0 +1,181 @@ |
+// Copyright 2014 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/ozone/evdev/tablet_event_converter_evdev.h" |
+ |
+#include <errno.h> |
+#include <linux/input.h> |
+ |
+#include "base/message_loop/message_loop.h" |
+#include "base/trace_event/trace_event.h" |
+#include "ui/events/event.h" |
+#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h" |
+ |
+namespace ui { |
+ |
+TabletEventConverterEvdev::TabletEventConverterEvdev( |
+ int fd, |
+ base::FilePath path, |
+ int id, |
+ InputDeviceType type, |
+ CursorDelegateEvdev* cursor, |
+ const EventDeviceInfo& info, |
+ DeviceEventDispatcherEvdev* dispatcher) |
+ : EventConverterEvdev(fd, |
+ path, |
+ id, |
+ type, |
+ info.name(), |
+ info.vendor_id(), |
+ info.product_id()), |
+ cursor_(cursor), |
+ dispatcher_(dispatcher) { |
+ x_abs_min_ = info.GetAbsMinimum(ABS_X); |
+ x_abs_range_ = info.GetAbsMaximum(ABS_X) - x_abs_min_ + 1; |
+ y_abs_min_ = info.GetAbsMinimum(ABS_Y); |
+ y_abs_range_ = info.GetAbsMaximum(ABS_Y) - y_abs_min_ + 1; |
+} |
+ |
+TabletEventConverterEvdev::~TabletEventConverterEvdev() { |
+} |
+ |
+void TabletEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { |
+ TRACE_EVENT1("evdev", |
+ "TabletEventConverterEvdev::OnFileCanReadWithoutBlocking", "fd", |
+ fd); |
+ |
+ input_event inputs[4]; |
+ ssize_t read_size = read(fd, inputs, sizeof(inputs)); |
+ if (read_size < 0) { |
+ if (errno == EINTR || errno == EAGAIN) |
+ return; |
+ if (errno != ENODEV) |
+ PLOG(ERROR) << "error reading device " << path_.value(); |
+ Stop(); |
+ return; |
+ } |
+ |
+ if (!enabled_) |
+ return; |
+ |
+ DCHECK_EQ(read_size % sizeof(*inputs), 0u); |
+ ProcessEvents(inputs, read_size / sizeof(*inputs)); |
+} |
+ |
+void TabletEventConverterEvdev::ProcessEvents(const input_event* inputs, |
+ int count) { |
+ for (int i = 0; i < count; ++i) { |
+ const input_event& input = inputs[i]; |
+ switch (input.type) { |
+ case EV_KEY: |
+ ConvertKeyEvent(input); |
+ break; |
+ case EV_ABS: |
+ ConvertAbsEvent(input); |
+ break; |
+ case EV_SYN: |
+ FlushEvents(input); |
+ break; |
+ } |
+ } |
+} |
+ |
+void TabletEventConverterEvdev::ConvertKeyEvent(const input_event& input) { |
+ // Only handle other events if we have a stylus in proximity |
+ if (input.code >= BTN_TOOL_PEN && input.code <= BTN_TOOL_LENS) { |
+ if (input.value == 1) |
+ stylus_ = input.code; |
+ else if (input.value == 0) |
+ stylus_ = 0; |
+ else |
+ LOG(WARNING) << "Unexpected value: " << input.value |
+ << " for code: " << input.code; |
+ } |
+ |
+ if (input.code >= BTN_TOUCH && input.code <= BTN_STYLUS2) { |
+ DispatchMouseButton(input); |
+ return; |
+ } |
+} |
+ |
+void TabletEventConverterEvdev::ConvertAbsEvent(const input_event& input) { |
+ if (!cursor_) |
+ return; |
+ |
+ switch (input.code) { |
+ case ABS_X: |
+ x_abs_location_ = input.value; |
+ abs_value_dirty_ = true; |
+ break; |
+ case ABS_Y: |
+ y_abs_location_ = input.value; |
+ abs_value_dirty_ = true; |
+ break; |
+ } |
+} |
+ |
+void TabletEventConverterEvdev::UpdateCursor() { |
+ gfx::Rect confined_bounds = cursor_->GetCursorConfinedBounds(); |
+ |
+ int x = |
+ ((x_abs_location_ - x_abs_min_) * confined_bounds.width()) / x_abs_range_; |
+ int y = ((y_abs_location_ - y_abs_min_) * confined_bounds.height()) / |
+ y_abs_range_; |
+ |
+ x += confined_bounds.x(); |
+ y += confined_bounds.y(); |
+ |
+ cursor_->MoveCursorTo(gfx::PointF(x, y)); |
+} |
+ |
+void TabletEventConverterEvdev::DispatchMouseButton(const input_event& input) { |
+ if (!cursor_) |
+ return; |
+ |
+ unsigned int button; |
+ // These are the same as X11 behaviour |
+ if (input.code == BTN_TOUCH) |
+ button = BTN_LEFT; |
+ else if (input.code == BTN_STYLUS2) |
+ button = BTN_RIGHT; |
+ else if (input.code == BTN_STYLUS) |
+ button = BTN_MIDDLE; |
+ else |
+ return; |
+ |
+ if (abs_value_dirty_) { |
+ UpdateCursor(); |
+ abs_value_dirty_ = false; |
+ } |
+ |
+ bool down = input.value; |
+ |
+ dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams( |
+ input_device_.id, cursor_->GetLocation(), button, down, |
+ false /* allow_remap */, TimeDeltaFromInputEvent(input))); |
+} |
+ |
+void TabletEventConverterEvdev::FlushEvents(const input_event& input) { |
+ if (!cursor_) |
+ return; |
+ |
+ // Prevent propagation of invalid data on stylus lift off |
+ if (stylus_ == 0) { |
+ abs_value_dirty_ = false; |
+ return; |
+ } |
+ |
+ if (!abs_value_dirty_) |
+ return; |
+ |
+ UpdateCursor(); |
+ |
+ dispatcher_->DispatchMouseMoveEvent( |
+ MouseMoveEventParams(input_device_.id, cursor_->GetLocation(), |
+ TimeDeltaFromInputEvent(input))); |
+ |
+ abs_value_dirty_ = false; |
+} |
+ |
+} // namespace ui |