Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(744)

Unified Diff: ui/events/ozone/evdev/input_device_factory_evdev.cc

Issue 1287103004: Sync ui/events to chromium @ https://codereview.chromium.org/1210203002 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: rebased Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/events/ozone/evdev/input_device_factory_evdev.cc
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fda9f3d40c0df38e1d3345f652c01137f0249496
--- /dev/null
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -0,0 +1,487 @@
+// 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/ozone/evdev/input_device_factory_evdev.h"
+
+#include <fcntl.h>
+#include <linux/input.h>
+
+#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/device_util_linux.h"
+#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
+#include "ui/events/ozone/evdev/event_converter_evdev_impl.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/tablet_event_converter_evdev.h"
+#include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
+
+#if defined(USE_EVDEV_GESTURES)
+#include "ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_feedback.h"
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h"
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
+#endif
+
+#ifndef EVIOCSCLOCKID
+#define EVIOCSCLOCKID _IOW('E', 0xa0, int)
+#endif
+
+namespace ui {
+
+namespace {
+
+typedef base::Callback<void(scoped_ptr<EventConverterEvdev>)>
+ OpenInputDeviceReplyCallback;
+
+struct OpenInputDeviceParams {
+ // Unique identifier for the new device.
+ int id;
+
+ // Device path to open.
+ base::FilePath path;
+
+ // Dispatcher for events. Call on UI thread only.
+ DeviceEventDispatcherEvdev* dispatcher;
+
+ // State shared between devices. Must not be dereferenced on worker thread.
+ CursorDelegateEvdev* cursor;
+#if defined(USE_EVDEV_GESTURES)
+ GesturePropertyProvider* gesture_property_provider;
+#endif
+};
+
+#if defined(USE_EVDEV_GESTURES)
+void SetGestureIntProperty(GesturePropertyProvider* provider,
+ int id,
+ const std::string& name,
+ int value) {
+ GesturesProp* property = provider->GetProperty(id, name);
+ if (property) {
+ std::vector<int> values(1, value);
+ property->SetIntValue(values);
+ }
+}
+
+void SetGestureBoolProperty(GesturePropertyProvider* provider,
+ int id,
+ const std::string& name,
+ bool value) {
+ GesturesProp* property = provider->GetProperty(id, name);
+ if (property) {
+ std::vector<bool> values(1, value);
+ property->SetBoolValue(values);
+ }
+}
+
+#endif
+
+scoped_ptr<EventConverterEvdev> CreateConverter(
+ const OpenInputDeviceParams& params,
+ int fd,
+ InputDeviceType type,
+ const EventDeviceInfo& devinfo) {
+#if defined(USE_EVDEV_GESTURES)
+ // Touchpad or mouse: use gestures library.
+ // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent
+ if (devinfo.HasTouchpad() || devinfo.HasMouse()) {
+ scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp =
+ make_scoped_ptr(new GestureInterpreterLibevdevCros(
+ params.id, params.cursor, params.gesture_property_provider,
+ params.dispatcher));
+ return make_scoped_ptr(new EventReaderLibevdevCros(
+ fd, params.path, params.id, type, devinfo, gesture_interp.Pass()));
+ }
+#endif
+
+ // Touchscreen: use TouchEventConverterEvdev.
+ if (devinfo.HasTouchscreen()) {
+ scoped_ptr<TouchEventConverterEvdev> converter(new TouchEventConverterEvdev(
+ fd, params.path, params.id, type, devinfo, params.dispatcher));
+ converter->Initialize(devinfo);
+ return converter.Pass();
+ }
+
+ // Graphics tablet
+ if (devinfo.HasTablet())
+ return make_scoped_ptr<EventConverterEvdev>(new TabletEventConverterEvdev(
+ fd, params.path, params.id, type, params.cursor, devinfo,
+ params.dispatcher));
+
+ // Everything else: use EventConverterEvdevImpl.
+ return make_scoped_ptr<EventConverterEvdevImpl>(
+ new EventConverterEvdevImpl(fd, params.path, params.id, type, devinfo,
+ params.cursor, params.dispatcher));
+}
+
+// Open an input device. Opening may put the calling thread to sleep, and
+// therefore should be run on a thread where latency is not critical. We
+// run it on a thread from the worker pool.
+//
+// This takes a TaskRunner and runs the reply on that thread, so that we
+// can hop threads if necessary (back to the UI thread).
+void OpenInputDevice(scoped_ptr<OpenInputDeviceParams> params,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const OpenInputDeviceReplyCallback& reply_callback) {
+ const base::FilePath& path = params->path;
+ scoped_ptr<EventConverterEvdev> converter;
+
+ TRACE_EVENT1("evdev", "OpenInputDevice", "path", path.value());
+
+ int fd = open(path.value().c_str(), O_RDWR | O_NONBLOCK);
+ if (fd < 0) {
+ PLOG(ERROR) << "Cannot open '" << path.value();
+ reply_runner->PostTask(
+ FROM_HERE, base::Bind(reply_callback, base::Passed(&converter)));
+ return;
+ }
+
+ // Use monotonic timestamps for events. The touch code in particular
+ // expects event timestamps to correlate to the monotonic clock
+ // (base::TimeTicks).
+ unsigned int clk = CLOCK_MONOTONIC;
+ if (ioctl(fd, EVIOCSCLOCKID, &clk))
+ PLOG(ERROR) << "failed to set CLOCK_MONOTONIC";
+
+ EventDeviceInfo devinfo;
+ if (!devinfo.Initialize(fd)) {
+ LOG(ERROR) << "failed to get device information for " << path.value();
+ close(fd);
+ reply_runner->PostTask(
+ FROM_HERE, base::Bind(reply_callback, base::Passed(&converter)));
+ return;
+ }
+
+ InputDeviceType type = GetInputDeviceTypeFromPath(path);
+
+ converter = CreateConverter(*params, fd, type, devinfo);
+
+ // Reply with the constructed converter.
+ reply_runner->PostTask(FROM_HERE,
+ base::Bind(reply_callback, base::Passed(&converter)));
+}
+
+// Close an input device. Closing may put the calling thread to sleep, and
+// therefore should be run on a thread where latency is not critical. We
+// run it on the FILE thread.
+void CloseInputDevice(const base::FilePath& path,
+ scoped_ptr<EventConverterEvdev> converter) {
+ TRACE_EVENT1("evdev", "CloseInputDevice", "path", path.value());
+ converter.reset();
+}
+
+} // namespace
+
+InputDeviceFactoryEvdev::InputDeviceFactoryEvdev(
+ scoped_ptr<DeviceEventDispatcherEvdev> dispatcher,
+ CursorDelegateEvdev* cursor)
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ cursor_(cursor),
+#if defined(USE_EVDEV_GESTURES)
+ gesture_property_provider_(new GesturePropertyProvider),
+#endif
+ dispatcher_(dispatcher.Pass()),
+ weak_ptr_factory_(this) {
+}
+
+InputDeviceFactoryEvdev::~InputDeviceFactoryEvdev() {
+ STLDeleteValues(&converters_);
+}
+
+void InputDeviceFactoryEvdev::AddInputDevice(int id,
+ const base::FilePath& path) {
+ scoped_ptr<OpenInputDeviceParams> params(new OpenInputDeviceParams);
+ params->id = id;
+ params->path = path;
+ params->cursor = cursor_;
+ params->dispatcher = dispatcher_.get();
+
+#if defined(USE_EVDEV_GESTURES)
+ params->gesture_property_provider = gesture_property_provider_.get();
+#endif
+
+ OpenInputDeviceReplyCallback reply_callback =
+ base::Bind(&InputDeviceFactoryEvdev::AttachInputDevice,
+ weak_ptr_factory_.GetWeakPtr());
+
+ ++pending_device_changes_;
+
+ // Dispatch task to open from the worker pool, since open may block.
+ base::WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&OpenInputDevice, base::Passed(&params),
+ task_runner_, reply_callback),
+ false /* task_is_slow */);
+}
+
+void InputDeviceFactoryEvdev::RemoveInputDevice(const base::FilePath& path) {
+ DetachInputDevice(path);
+}
+
+void InputDeviceFactoryEvdev::OnStartupScanComplete() {
+ startup_devices_enumerated_ = true;
+ NotifyDevicesUpdated();
+}
+
+void InputDeviceFactoryEvdev::AttachInputDevice(
+ scoped_ptr<EventConverterEvdev> converter) {
+ if (converter.get()) {
+ const base::FilePath& path = converter->path();
+
+ TRACE_EVENT1("evdev", "AttachInputDevice", "path", path.value());
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ // If we have an existing device, detach it. We don't want two
+ // devices with the same name open at the same time.
+ if (converters_[path])
+ DetachInputDevice(path);
+
+ // Add initialized device to map.
+ converters_[path] = converter.release();
+ converters_[path]->Start();
+ UpdateDirtyFlags(converters_[path]);
+
+ // Sync settings to new device.
+ ApplyInputDeviceSettings();
+ ApplyCapsLockLed();
+ }
+
+ --pending_device_changes_;
+ NotifyDevicesUpdated();
+}
+
+void InputDeviceFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
+ TRACE_EVENT1("evdev", "DetachInputDevice", "path", path.value());
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ // Remove device from map.
+ scoped_ptr<EventConverterEvdev> converter(converters_[path]);
+ converters_.erase(path);
+
+ if (converter) {
+ // Disable the device (to release keys/buttons/etc).
+ converter->SetEnabled(false);
+
+ // Cancel libevent notifications from this converter. This part must be
+ // on UI since the polling happens on UI.
+ converter->Stop();
+
+ UpdateDirtyFlags(converter.get());
+ NotifyDevicesUpdated();
+
+ // Dispatch task to close from the worker pool, since close may block.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&CloseInputDevice, path, base::Passed(&converter)), true);
+ }
+}
+
+void InputDeviceFactoryEvdev::SetCapsLockLed(bool enabled) {
+ caps_lock_led_enabled_ = enabled;
+ ApplyCapsLockLed();
+}
+
+void InputDeviceFactoryEvdev::UpdateInputDeviceSettings(
+ const InputDeviceSettingsEvdev& settings) {
+ input_device_settings_ = settings;
+ ApplyInputDeviceSettings();
+}
+
+void InputDeviceFactoryEvdev::GetTouchDeviceStatus(
+ const GetTouchDeviceStatusReply& reply) {
+ scoped_ptr<std::string> status(new std::string);
+#if defined(USE_EVDEV_GESTURES)
+ DumpTouchDeviceStatus(gesture_property_provider_.get(), status.get());
+#endif
+ reply.Run(status.Pass());
+}
+
+void InputDeviceFactoryEvdev::GetTouchEventLog(
+ const base::FilePath& out_dir,
+ const GetTouchEventLogReply& reply) {
+ scoped_ptr<std::vector<base::FilePath>> log_paths(
+ new std::vector<base::FilePath>);
+#if defined(USE_EVDEV_GESTURES)
+ DumpTouchEventLog(gesture_property_provider_.get(), out_dir, log_paths.Pass(),
+ reply);
+#else
+ reply.Run(log_paths.Pass());
+#endif
+}
+
+base::WeakPtr<InputDeviceFactoryEvdev> InputDeviceFactoryEvdev::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void InputDeviceFactoryEvdev::ApplyInputDeviceSettings() {
+ TRACE_EVENT0("evdev", "ApplyInputDeviceSettings");
+
+ SetIntPropertyForOneType(DT_TOUCHPAD, "Pointer Sensitivity",
+ input_device_settings_.touchpad_sensitivity);
+ SetIntPropertyForOneType(DT_TOUCHPAD, "Scroll Sensitivity",
+ input_device_settings_.touchpad_sensitivity);
+
+ SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Enable",
+ input_device_settings_.tap_to_click_enabled);
+ SetBoolPropertyForOneType(DT_TOUCHPAD, "T5R2 Three Finger Click Enable",
+ input_device_settings_.three_finger_click_enabled);
+ SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Drag Enable",
+ input_device_settings_.tap_dragging_enabled);
+
+ SetBoolPropertyForOneType(DT_MULTITOUCH, "Australian Scrolling",
+ input_device_settings_.natural_scroll_enabled);
+
+ SetIntPropertyForOneType(DT_MOUSE, "Pointer Sensitivity",
+ input_device_settings_.mouse_sensitivity);
+ SetIntPropertyForOneType(DT_MOUSE, "Scroll Sensitivity",
+ input_device_settings_.mouse_sensitivity);
+
+ SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Paused",
+ input_device_settings_.tap_to_click_paused);
+
+ for (const auto& it : converters_) {
+ EventConverterEvdev* converter = it.second;
+ converter->SetEnabled(IsDeviceEnabled(converter));
+
+ if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
+ converter->HasKeyboard()) {
+ converter->SetKeyFilter(
+ input_device_settings_.enable_internal_keyboard_filter,
+ input_device_settings_.internal_keyboard_allowed_keys);
+ }
+ }
+}
+
+void InputDeviceFactoryEvdev::ApplyCapsLockLed() {
+ for (const auto& it : converters_) {
+ EventConverterEvdev* converter = it.second;
+ converter->SetCapsLockLed(caps_lock_led_enabled_);
+ }
+}
+
+bool InputDeviceFactoryEvdev::IsDeviceEnabled(
+ const EventConverterEvdev* converter) {
+ if (!input_device_settings_.enable_internal_touchpad &&
+ converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
+ converter->HasTouchpad())
+ return false;
+
+ return input_device_settings_.enable_devices;
+}
+
+void InputDeviceFactoryEvdev::UpdateDirtyFlags(
+ const EventConverterEvdev* converter) {
+ if (converter->HasTouchscreen())
+ touchscreen_list_dirty_ = true;
+
+ if (converter->HasKeyboard())
+ keyboard_list_dirty_ = true;
+
+ if (converter->HasMouse())
+ mouse_list_dirty_ = true;
+
+ if (converter->HasTouchpad())
+ touchpad_list_dirty_ = true;
+}
+
+void InputDeviceFactoryEvdev::NotifyDevicesUpdated() {
+ if (!startup_devices_enumerated_ || pending_device_changes_)
+ return; // No update until full scan done and no pending operations.
+ if (touchscreen_list_dirty_)
+ NotifyTouchscreensUpdated();
+ if (keyboard_list_dirty_)
+ NotifyKeyboardsUpdated();
+ if (mouse_list_dirty_)
+ NotifyMouseDevicesUpdated();
+ if (touchpad_list_dirty_)
+ NotifyTouchpadDevicesUpdated();
+ if (!startup_devices_opened_) {
+ dispatcher_->DispatchDeviceListsComplete();
+ startup_devices_opened_ = true;
+ }
+ touchscreen_list_dirty_ = false;
+ keyboard_list_dirty_ = false;
+ mouse_list_dirty_ = false;
+ touchpad_list_dirty_ = false;
+}
+
+void InputDeviceFactoryEvdev::NotifyTouchscreensUpdated() {
+ std::vector<TouchscreenDevice> touchscreens;
+ for (auto it = converters_.begin(); it != converters_.end(); ++it) {
+ if (it->second->HasTouchscreen()) {
+ touchscreens.push_back(TouchscreenDevice(it->second->input_device(),
+ it->second->GetTouchscreenSize(), it->second->GetTouchPoints()));
+ }
+ }
+
+ dispatcher_->DispatchTouchscreenDevicesUpdated(touchscreens);
+}
+
+void InputDeviceFactoryEvdev::NotifyKeyboardsUpdated() {
+ std::vector<KeyboardDevice> keyboards;
+ for (auto it = converters_.begin(); it != converters_.end(); ++it) {
+ if (it->second->HasKeyboard()) {
+ keyboards.push_back(KeyboardDevice(it->second->input_device()));
+ }
+ }
+
+ dispatcher_->DispatchKeyboardDevicesUpdated(keyboards);
+}
+
+void InputDeviceFactoryEvdev::NotifyMouseDevicesUpdated() {
+ std::vector<InputDevice> mice;
+ for (auto it = converters_.begin(); it != converters_.end(); ++it) {
+ if (it->second->HasMouse()) {
+ mice.push_back(it->second->input_device());
+ }
+ }
+
+ dispatcher_->DispatchMouseDevicesUpdated(mice);
+}
+
+void InputDeviceFactoryEvdev::NotifyTouchpadDevicesUpdated() {
+ std::vector<InputDevice> touchpads;
+ for (auto it = converters_.begin(); it != converters_.end(); ++it) {
+ if (it->second->HasTouchpad()) {
+ touchpads.push_back(it->second->input_device());
+ }
+ }
+
+ dispatcher_->DispatchTouchpadDevicesUpdated(touchpads);
+}
+
+void InputDeviceFactoryEvdev::SetIntPropertyForOneType(
+ const EventDeviceType type,
+ const std::string& name,
+ int value) {
+#if defined(USE_EVDEV_GESTURES)
+ std::vector<int> ids;
+ gesture_property_provider_->GetDeviceIdsByType(type, &ids);
+ for (size_t i = 0; i < ids.size(); ++i) {
+ SetGestureIntProperty(gesture_property_provider_.get(), ids[i], name,
+ value);
+ }
+#endif
+ // In the future, we may add property setting codes for other non-gesture
+ // devices. One example would be keyboard settings.
+ // TODO(sheckylin): See http://crbug.com/398518 for example.
+}
+
+void InputDeviceFactoryEvdev::SetBoolPropertyForOneType(
+ const EventDeviceType type,
+ const std::string& name,
+ bool value) {
+#if defined(USE_EVDEV_GESTURES)
+ std::vector<int> ids;
+ gesture_property_provider_->GetDeviceIdsByType(type, &ids);
+ for (size_t i = 0; i < ids.size(); ++i) {
+ SetGestureBoolProperty(gesture_property_provider_.get(), ids[i], name,
+ value);
+ }
+#endif
+}
+
+} // namespace ui
« no previous file with comments | « ui/events/ozone/evdev/input_device_factory_evdev.h ('k') | ui/events/ozone/evdev/input_device_factory_evdev_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698