Index: ui/events/ozone/evdev/event_factory_evdev.cc |
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9d79b14b0483ff6eb4ab0c7342b72dd4d323d126 |
--- /dev/null |
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc |
@@ -0,0 +1,393 @@ |
+// 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/event_factory_evdev.h" |
+ |
+#include "base/bind.h" |
+#include "base/task_runner.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/input_device.h" |
+#include "ui/events/event_utils.h" |
+#include "ui/events/ozone/device/device_event.h" |
+#include "ui/events/ozone/device/device_manager.h" |
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h" |
+#include "ui/events/ozone/evdev/input_controller_evdev.h" |
+#include "ui/events/ozone/evdev/input_device_factory_evdev.h" |
+#include "ui/events/ozone/evdev/input_device_factory_evdev_proxy.h" |
+#include "ui/events/ozone/evdev/input_injector_evdev.h" |
+#include "ui/events/ozone/evdev/touch_evdev_types.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+// Thread safe dispatcher proxy for EventFactoryEvdev. |
+// |
+// This is used on the device I/O thread for dispatching to UI. |
+class ProxyDeviceEventDispatcher : public DeviceEventDispatcherEvdev { |
+ public: |
+ ProxyDeviceEventDispatcher( |
+ scoped_refptr<base::SingleThreadTaskRunner> ui_thread_runner, |
+ base::WeakPtr<EventFactoryEvdev> event_factory_evdev) |
+ : ui_thread_runner_(ui_thread_runner), |
+ event_factory_evdev_(event_factory_evdev) {} |
+ ~ProxyDeviceEventDispatcher() override {} |
+ |
+ // DeviceEventDispatcher: |
+ void DispatchKeyEvent(const KeyEventParams& params) override { |
+ ui_thread_runner_->PostTask(FROM_HERE, |
+ base::Bind(&EventFactoryEvdev::DispatchKeyEvent, |
+ event_factory_evdev_, params)); |
+ } |
+ |
+ void DispatchMouseMoveEvent(const MouseMoveEventParams& params) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseMoveEvent, |
+ event_factory_evdev_, params)); |
+ } |
+ |
+ void DispatchMouseButtonEvent(const MouseButtonEventParams& params) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseButtonEvent, |
+ event_factory_evdev_, params)); |
+ } |
+ |
+ void DispatchMouseWheelEvent(const MouseWheelEventParams& params) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseWheelEvent, |
+ event_factory_evdev_, params)); |
+ } |
+ |
+ void DispatchScrollEvent(const ScrollEventParams& params) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchScrollEvent, |
+ event_factory_evdev_, params)); |
+ } |
+ |
+ void DispatchTouchEvent(const TouchEventParams& params) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchTouchEvent, |
+ event_factory_evdev_, params)); |
+ } |
+ |
+ void DispatchKeyboardDevicesUpdated( |
+ const std::vector<KeyboardDevice>& devices) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&EventFactoryEvdev::DispatchKeyboardDevicesUpdated, |
+ event_factory_evdev_, devices)); |
+ } |
+ void DispatchTouchscreenDevicesUpdated( |
+ const std::vector<TouchscreenDevice>& devices) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&EventFactoryEvdev::DispatchTouchscreenDevicesUpdated, |
+ event_factory_evdev_, devices)); |
+ } |
+ void DispatchMouseDevicesUpdated( |
+ const std::vector<InputDevice>& devices) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseDevicesUpdated, |
+ event_factory_evdev_, devices)); |
+ } |
+ void DispatchTouchpadDevicesUpdated( |
+ const std::vector<InputDevice>& devices) override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&EventFactoryEvdev::DispatchTouchpadDevicesUpdated, |
+ event_factory_evdev_, devices)); |
+ } |
+ void DispatchDeviceListsComplete() override { |
+ ui_thread_runner_->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchDeviceListsComplete, |
+ event_factory_evdev_)); |
+ } |
+ |
+ private: |
+ scoped_refptr<base::SingleThreadTaskRunner> ui_thread_runner_; |
+ base::WeakPtr<EventFactoryEvdev> event_factory_evdev_; |
+}; |
+ |
+} // namespace |
+ |
+EventFactoryEvdev::EventFactoryEvdev(CursorDelegateEvdev* cursor, |
+ DeviceManager* device_manager, |
+ KeyboardLayoutEngine* keyboard_layout) |
+ : device_manager_(device_manager), |
+ keyboard_(&modifiers_, |
+ keyboard_layout, |
+ base::Bind(&EventFactoryEvdev::DispatchUiEvent, |
+ base::Unretained(this))), |
+ cursor_(cursor), |
+ input_controller_(&keyboard_, &button_map_), |
+ touch_id_generator_(0), |
+ weak_ptr_factory_(this) { |
+ DCHECK(device_manager_); |
+} |
+ |
+EventFactoryEvdev::~EventFactoryEvdev() { |
+} |
+ |
+void EventFactoryEvdev::Init() { |
+ DCHECK(!initialized_); |
+ |
+ StartThread(); |
+ |
+ initialized_ = true; |
+} |
+ |
+scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() { |
+ // Use forwarding dispatcher for the injector rather than dispatching |
+ // directly. We cannot assume it is safe to (re-)enter ui::Event dispatch |
+ // synchronously from the injection point. |
+ scoped_ptr<DeviceEventDispatcherEvdev> proxy_dispatcher( |
+ new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(), |
+ weak_ptr_factory_.GetWeakPtr())); |
+ return make_scoped_ptr( |
+ new InputInjectorEvdev(proxy_dispatcher.Pass(), cursor_)); |
+} |
+ |
+void EventFactoryEvdev::DispatchKeyEvent(const KeyEventParams& params) { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchKeyEvent", "device", |
+ params.device_id); |
+ keyboard_.OnKeyChange(params.code, params.down, params.suppress_auto_repeat, |
+ params.timestamp, params.device_id); |
+} |
+ |
+void EventFactoryEvdev::DispatchMouseMoveEvent( |
+ const MouseMoveEventParams& params) { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchMouseMoveEvent", "device", |
+ params.device_id); |
+ MouseEvent event(ui::ET_MOUSE_MOVED, params.location, params.location, |
+ params.timestamp, modifiers_.GetModifierFlags(), |
+ /* changed_button_flags */ 0); |
+ event.set_source_device_id(params.device_id); |
+ DispatchUiEvent(&event); |
+} |
+ |
+void EventFactoryEvdev::DispatchMouseButtonEvent( |
+ const MouseButtonEventParams& params) { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchMouseButtonEvent", "device", |
+ params.device_id); |
+ |
+ // Mouse buttons can be remapped, touchpad taps & clicks cannot. |
+ unsigned int button = params.button; |
+ if (params.allow_remap) |
+ button = button_map_.GetMappedButton(button); |
+ |
+ int modifier = EVDEV_MODIFIER_NONE; |
+ switch (button) { |
+ case BTN_LEFT: |
+ modifier = EVDEV_MODIFIER_LEFT_MOUSE_BUTTON; |
+ break; |
+ case BTN_RIGHT: |
+ modifier = EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON; |
+ break; |
+ case BTN_MIDDLE: |
+ modifier = EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON; |
+ break; |
+ case BTN_BACK: |
+ modifier = EVDEV_MODIFIER_BACK_MOUSE_BUTTON; |
+ break; |
+ case BTN_FORWARD: |
+ modifier = EVDEV_MODIFIER_FORWARD_MOUSE_BUTTON; |
+ break; |
+ default: |
+ return; |
+ } |
+ |
+ int flag = modifiers_.GetEventFlagFromModifier(modifier); |
+ bool was_down = modifiers_.GetModifierFlags() & flag; |
+ modifiers_.UpdateModifier(modifier, params.down); |
+ bool down = modifiers_.GetModifierFlags() & flag; |
+ |
+ // Suppress nested clicks. EventModifiersEvdev counts presses, we only |
+ // dispatch an event on 0-1 (first press) and 1-0 (last release) transitions. |
+ if (down == was_down) |
+ return; |
+ |
+ MouseEvent event(params.down ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED, |
+ params.location, params.location, params.timestamp, |
+ modifiers_.GetModifierFlags() | flag, |
+ /* changed_button_flags */ flag); |
+ event.set_source_device_id(params.device_id); |
+ DispatchUiEvent(&event); |
+} |
+ |
+void EventFactoryEvdev::DispatchMouseWheelEvent( |
+ const MouseWheelEventParams& params) { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchMouseWheelEvent", "device", |
+ params.device_id); |
+ MouseWheelEvent event(params.delta, params.location, params.location, |
+ params.timestamp, modifiers_.GetModifierFlags(), |
+ 0 /* changed_button_flags */); |
+ event.set_source_device_id(params.device_id); |
+ DispatchUiEvent(&event); |
+} |
+ |
+void EventFactoryEvdev::DispatchScrollEvent(const ScrollEventParams& params) { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchScrollEvent", "device", |
+ params.device_id); |
+ ScrollEvent event(params.type, params.location, params.timestamp, |
+ modifiers_.GetModifierFlags(), params.delta.x(), |
+ params.delta.y(), params.ordinal_delta.x(), |
+ params.ordinal_delta.y(), params.finger_count); |
+ event.set_source_device_id(params.device_id); |
+ DispatchUiEvent(&event); |
+} |
+ |
+void EventFactoryEvdev::DispatchTouchEvent(const TouchEventParams& params) { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchTouchEvent", "device", |
+ params.device_id); |
+ |
+ float x = params.location.x(); |
+ float y = params.location.y(); |
+ double radius_x = params.radii.x(); |
+ double radius_y = params.radii.y(); |
+ |
+ // Transform the event to align touches to the image based on display mode. |
+ DeviceDataManager::GetInstance()->ApplyTouchTransformer(params.device_id, &x, |
+ &y); |
+ DeviceDataManager::GetInstance()->ApplyTouchRadiusScale(params.device_id, |
+ &radius_x); |
+ DeviceDataManager::GetInstance()->ApplyTouchRadiusScale(params.device_id, |
+ &radius_y); |
+ |
+ // params.slot is guaranteed to be < kNumTouchEvdevSlots. |
+ int touch_id = touch_id_generator_.GetGeneratedID( |
+ params.device_id * kNumTouchEvdevSlots + params.slot); |
+ TouchEvent touch_event(params.type, gfx::PointF(x, y), |
+ modifiers_.GetModifierFlags(), touch_id, |
+ params.timestamp, radius_x, radius_y, |
+ /* angle */ 0.f, params.pressure); |
+ touch_event.set_source_device_id(params.device_id); |
+ DispatchUiEvent(&touch_event); |
+ |
+ if (params.type == ET_TOUCH_RELEASED || params.type == ET_TOUCH_CANCELLED) { |
+ touch_id_generator_.ReleaseGeneratedID(touch_event.touch_id()); |
+ } |
+} |
+ |
+void EventFactoryEvdev::DispatchUiEvent(Event* event) { |
+ // DispatchEvent takes PlatformEvent which is void*. This function |
+ // wraps it with the real type. |
+ DispatchEvent(event); |
+} |
+ |
+void EventFactoryEvdev::DispatchKeyboardDevicesUpdated( |
+ const std::vector<KeyboardDevice>& devices) { |
+ TRACE_EVENT0("evdev", "EventFactoryEvdev::DispatchKeyboardDevicesUpdated"); |
+ DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance(); |
+ observer->OnKeyboardDevicesUpdated(devices); |
+} |
+ |
+void EventFactoryEvdev::DispatchTouchscreenDevicesUpdated( |
+ const std::vector<TouchscreenDevice>& devices) { |
+ TRACE_EVENT0("evdev", "EventFactoryEvdev::DispatchTouchscreenDevicesUpdated"); |
+ DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance(); |
+ observer->OnTouchscreenDevicesUpdated(devices); |
+} |
+ |
+void EventFactoryEvdev::DispatchMouseDevicesUpdated( |
+ const std::vector<InputDevice>& devices) { |
+ TRACE_EVENT0("evdev", "EventFactoryEvdev::DispatchMouseDevicesUpdated"); |
+ |
+ // There's no list of mice in DeviceDataManager. |
+ input_controller_.set_has_mouse(devices.size() != 0); |
+ DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance(); |
+ observer->OnMouseDevicesUpdated(devices); |
+} |
+ |
+void EventFactoryEvdev::DispatchTouchpadDevicesUpdated( |
+ const std::vector<InputDevice>& devices) { |
+ TRACE_EVENT0("evdev", "EventFactoryEvdev::DispatchTouchpadDevicesUpdated"); |
+ |
+ // There's no list of touchpads in DeviceDataManager. |
+ input_controller_.set_has_touchpad(devices.size() != 0); |
+ DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance(); |
+ observer->OnTouchpadDevicesUpdated(devices); |
+} |
+ |
+void EventFactoryEvdev::DispatchDeviceListsComplete() { |
+ TRACE_EVENT0("evdev", "EventFactoryEvdev::DispatchDeviceListsComplete"); |
+ DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance(); |
+ observer->OnDeviceListsComplete(); |
+} |
+ |
+void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) { |
+ if (event.device_type() != DeviceEvent::INPUT) |
+ return; |
+ |
+ switch (event.action_type()) { |
+ case DeviceEvent::ADD: |
+ case DeviceEvent::CHANGE: { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::OnDeviceAdded", "path", |
+ event.path().value()); |
+ input_device_factory_proxy_->AddInputDevice(NextDeviceId(), event.path()); |
+ break; |
+ } |
+ case DeviceEvent::REMOVE: { |
+ TRACE_EVENT1("evdev", "EventFactoryEvdev::OnDeviceRemoved", "path", |
+ event.path().value()); |
+ input_device_factory_proxy_->RemoveInputDevice(event.path()); |
+ break; |
+ } |
+ } |
+} |
+ |
+void EventFactoryEvdev::OnDispatcherListChanged() { |
+ if (!initialized_) |
+ Init(); |
+} |
+ |
+void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget, |
+ const gfx::PointF& location) { |
+ if (!cursor_) |
+ return; |
+ |
+ cursor_->MoveCursorTo(widget, location); |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseMoveEvent, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ MouseMoveEventParams(-1 /* device_id */, |
+ cursor_->GetLocation(), |
+ EventTimeForNow()))); |
+} |
+ |
+int EventFactoryEvdev::NextDeviceId() { |
+ return ++last_device_id_; |
+} |
+ |
+void EventFactoryEvdev::StartThread() { |
+ // Set up device factory. |
+ scoped_ptr<DeviceEventDispatcherEvdev> proxy_dispatcher( |
+ new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(), |
+ weak_ptr_factory_.GetWeakPtr())); |
+ thread_.Start(proxy_dispatcher.Pass(), cursor_, |
+ base::Bind(&EventFactoryEvdev::OnThreadStarted, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void EventFactoryEvdev::OnThreadStarted( |
+ scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory) { |
+ TRACE_EVENT0("evdev", "EventFactoryEvdev::OnThreadStarted"); |
+ input_device_factory_proxy_ = input_device_factory.Pass(); |
+ |
+ // Hook up device configuration. |
+ input_controller_.SetInputDeviceFactory(input_device_factory_proxy_.get()); |
+ |
+ // Scan & monitor devices. |
+ device_manager_->AddObserver(this); |
+ device_manager_->ScanDevices(this); |
+ |
+ // Notify device thread that initial scan is done. |
+ input_device_factory_proxy_->OnStartupScanComplete(); |
+} |
+ |
+} // namespace ui |