| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/events/ozone/evdev/event_factory_evdev.h" | 5 #include "ui/events/ozone/evdev/event_factory_evdev.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <linux/input.h> | 8 #include <linux/input.h> |
| 9 | 9 |
| 10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #endif | 26 #endif |
| 27 | 27 |
| 28 #ifndef EVIOCSCLOCKID | 28 #ifndef EVIOCSCLOCKID |
| 29 #define EVIOCSCLOCKID _IOW('E', 0xa0, int) | 29 #define EVIOCSCLOCKID _IOW('E', 0xa0, int) |
| 30 #endif | 30 #endif |
| 31 | 31 |
| 32 namespace ui { | 32 namespace ui { |
| 33 | 33 |
| 34 namespace { | 34 namespace { |
| 35 | 35 |
| 36 typedef base::Callback<void(scoped_ptr<EventConverterEvdev>)> |
| 37 OpenInputDeviceReplyCallback; |
| 38 |
| 39 struct OpenInputDeviceParams { |
| 40 // Unique identifier for the new device. |
| 41 int id; |
| 42 |
| 43 // Device path to open. |
| 44 base::FilePath path; |
| 45 |
| 46 // Callback for dispatching events. Call on UI thread only. |
| 47 EventDispatchCallback dispatch_callback; |
| 48 |
| 49 // State shared between devices. Must not be dereferenced on worker thread. |
| 50 EventModifiersEvdev* modifiers; |
| 51 CursorDelegateEvdev* cursor; |
| 52 }; |
| 53 |
| 36 #if defined(USE_EVDEV_GESTURES) | 54 #if defined(USE_EVDEV_GESTURES) |
| 37 bool UseGesturesLibraryForDevice(const EventDeviceInfo& devinfo) { | 55 bool UseGesturesLibraryForDevice(const EventDeviceInfo& devinfo) { |
| 38 if (devinfo.HasAbsXY() && !devinfo.IsMappedToScreen()) | 56 if (devinfo.HasAbsXY() && !devinfo.IsMappedToScreen()) |
| 39 return true; // touchpad | 57 return true; // touchpad |
| 40 | 58 |
| 41 if (devinfo.HasRelXY()) | 59 if (devinfo.HasRelXY()) |
| 42 return true; // mouse | 60 return true; // mouse |
| 43 | 61 |
| 44 return false; | 62 return false; |
| 45 } | 63 } |
| 46 #endif | 64 #endif |
| 47 | 65 |
| 48 scoped_ptr<EventConverterEvdev> CreateConverter( | 66 scoped_ptr<EventConverterEvdev> CreateConverter( |
| 67 const OpenInputDeviceParams& params, |
| 49 int fd, | 68 int fd, |
| 50 const base::FilePath& path, | 69 const EventDeviceInfo& devinfo) { |
| 51 int id, | |
| 52 const EventDeviceInfo& devinfo, | |
| 53 const EventDispatchCallback& dispatch, | |
| 54 EventModifiersEvdev* modifiers, | |
| 55 CursorDelegateEvdev* cursor) { | |
| 56 #if defined(USE_EVDEV_GESTURES) | 70 #if defined(USE_EVDEV_GESTURES) |
| 57 // Touchpad or mouse: use gestures library. | 71 // Touchpad or mouse: use gestures library. |
| 58 // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent | 72 // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent |
| 59 if (UseGesturesLibraryForDevice(devinfo)) { | 73 if (UseGesturesLibraryForDevice(devinfo)) { |
| 60 scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp = make_scoped_ptr( | 74 scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp = |
| 61 new GestureInterpreterLibevdevCros(modifiers, cursor, dispatch)); | 75 make_scoped_ptr(new GestureInterpreterLibevdevCros( |
| 76 params.modifiers, params.cursor, params.dispatch_callback)); |
| 62 scoped_ptr<EventReaderLibevdevCros> libevdev_reader = | 77 scoped_ptr<EventReaderLibevdevCros> libevdev_reader = |
| 63 make_scoped_ptr(new EventReaderLibevdevCros( | 78 make_scoped_ptr(new EventReaderLibevdevCros( |
| 64 fd, | 79 fd, |
| 65 path, | 80 params.path, |
| 66 id, | 81 params.id, |
| 67 gesture_interp.PassAs<EventReaderLibevdevCros::Delegate>())); | 82 gesture_interp.PassAs<EventReaderLibevdevCros::Delegate>())); |
| 68 return libevdev_reader.PassAs<EventConverterEvdev>(); | 83 return libevdev_reader.PassAs<EventConverterEvdev>(); |
| 69 } | 84 } |
| 70 #endif | 85 #endif |
| 71 | 86 |
| 72 // Touchscreen: use TouchEventConverterEvdev. | 87 // Touchscreen: use TouchEventConverterEvdev. |
| 73 scoped_ptr<EventConverterEvdev> converter; | 88 scoped_ptr<EventConverterEvdev> converter; |
| 74 if (devinfo.HasAbsXY()) | 89 if (devinfo.HasAbsXY()) |
| 75 return make_scoped_ptr<EventConverterEvdev>( | 90 return make_scoped_ptr<EventConverterEvdev>(new TouchEventConverterEvdev( |
| 76 new TouchEventConverterEvdev(fd, path, id, devinfo, dispatch)); | 91 fd, params.path, params.id, devinfo, params.dispatch_callback)); |
| 77 | 92 |
| 78 // Everything else: use KeyEventConverterEvdev. | 93 // Everything else: use KeyEventConverterEvdev. |
| 79 return make_scoped_ptr<EventConverterEvdev>( | 94 return make_scoped_ptr<EventConverterEvdev>(new KeyEventConverterEvdev( |
| 80 new KeyEventConverterEvdev(fd, path, id, modifiers, dispatch)); | 95 fd, params.path, params.id, params.modifiers, params.dispatch_callback)); |
| 81 } | 96 } |
| 82 | 97 |
| 83 // Open an input device. Opening may put the calling thread to sleep, and | 98 // Open an input device. Opening may put the calling thread to sleep, and |
| 84 // therefore should be run on a thread where latency is not critical. We | 99 // therefore should be run on a thread where latency is not critical. We |
| 85 // run it on a thread from the worker pool. | 100 // run it on a thread from the worker pool. |
| 86 // | 101 // |
| 87 // This takes a TaskRunner and runs the reply on that thread, so that we | 102 // This takes a TaskRunner and runs the reply on that thread, so that we |
| 88 // can hop threads if necessary (back to the UI thread). | 103 // can hop threads if necessary (back to the UI thread). |
| 89 void OpenInputDevice( | 104 void OpenInputDevice(scoped_ptr<OpenInputDeviceParams> params, |
| 90 const base::FilePath& path, | 105 scoped_refptr<base::TaskRunner> reply_runner, |
| 91 EventModifiersEvdev* modifiers, | 106 const OpenInputDeviceReplyCallback& reply_callback) { |
| 92 CursorDelegateEvdev* cursor, | 107 const base::FilePath& path = params->path; |
| 93 int device_id, | 108 |
| 94 scoped_refptr<base::TaskRunner> reply_runner, | |
| 95 const EventDispatchCallback& dispatch, | |
| 96 base::Callback<void(scoped_ptr<EventConverterEvdev>)> reply_callback) { | |
| 97 TRACE_EVENT1("ozone", "OpenInputDevice", "path", path.value()); | 109 TRACE_EVENT1("ozone", "OpenInputDevice", "path", path.value()); |
| 98 | 110 |
| 99 int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK); | 111 int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK); |
| 100 if (fd < 0) { | 112 if (fd < 0) { |
| 101 PLOG(ERROR) << "Cannot open '" << path.value(); | 113 PLOG(ERROR) << "Cannot open '" << path.value(); |
| 102 return; | 114 return; |
| 103 } | 115 } |
| 104 | 116 |
| 105 // Use monotonic timestamps for events. The touch code in particular | 117 // Use monotonic timestamps for events. The touch code in particular |
| 106 // expects event timestamps to correlate to the monotonic clock | 118 // expects event timestamps to correlate to the monotonic clock |
| 107 // (base::TimeTicks). | 119 // (base::TimeTicks). |
| 108 unsigned int clk = CLOCK_MONOTONIC; | 120 unsigned int clk = CLOCK_MONOTONIC; |
| 109 if (ioctl(fd, EVIOCSCLOCKID, &clk)) | 121 if (ioctl(fd, EVIOCSCLOCKID, &clk)) |
| 110 PLOG(ERROR) << "failed to set CLOCK_MONOTONIC"; | 122 PLOG(ERROR) << "failed to set CLOCK_MONOTONIC"; |
| 111 | 123 |
| 112 EventDeviceInfo devinfo; | 124 EventDeviceInfo devinfo; |
| 113 if (!devinfo.Initialize(fd)) { | 125 if (!devinfo.Initialize(fd)) { |
| 114 LOG(ERROR) << "failed to get device information for " << path.value(); | 126 LOG(ERROR) << "failed to get device information for " << path.value(); |
| 115 close(fd); | 127 close(fd); |
| 116 return; | 128 return; |
| 117 } | 129 } |
| 118 | 130 |
| 119 scoped_ptr<EventConverterEvdev> converter = CreateConverter( | 131 scoped_ptr<EventConverterEvdev> converter = |
| 120 fd, path, device_id, devinfo, dispatch, modifiers, cursor); | 132 CreateConverter(*params, fd, devinfo); |
| 121 | 133 |
| 122 // Reply with the constructed converter. | 134 // Reply with the constructed converter. |
| 123 reply_runner->PostTask(FROM_HERE, | 135 reply_runner->PostTask(FROM_HERE, |
| 124 base::Bind(reply_callback, base::Passed(&converter))); | 136 base::Bind(reply_callback, base::Passed(&converter))); |
| 125 } | 137 } |
| 126 | 138 |
| 127 // Close an input device. Closing may put the calling thread to sleep, and | 139 // Close an input device. Closing may put the calling thread to sleep, and |
| 128 // therefore should be run on a thread where latency is not critical. We | 140 // therefore should be run on a thread where latency is not critical. We |
| 129 // run it on the FILE thread. | 141 // run it on the FILE thread. |
| 130 void CloseInputDevice(const base::FilePath& path, | 142 void CloseInputDevice(const base::FilePath& path, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 147 DCHECK(device_manager_); | 159 DCHECK(device_manager_); |
| 148 } | 160 } |
| 149 | 161 |
| 150 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); } | 162 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); } |
| 151 | 163 |
| 152 void EventFactoryEvdev::DispatchUiEvent(Event* event) { | 164 void EventFactoryEvdev::DispatchUiEvent(Event* event) { |
| 153 DispatchEvent(event); | 165 DispatchEvent(event); |
| 154 } | 166 } |
| 155 | 167 |
| 156 void EventFactoryEvdev::AttachInputDevice( | 168 void EventFactoryEvdev::AttachInputDevice( |
| 157 const base::FilePath& path, | |
| 158 scoped_ptr<EventConverterEvdev> converter) { | 169 scoped_ptr<EventConverterEvdev> converter) { |
| 170 const base::FilePath& path = converter->path(); |
| 171 |
| 159 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value()); | 172 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value()); |
| 160 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 173 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 161 | 174 |
| 162 // If we have an existing device, detach it. We don't want two | 175 // If we have an existing device, detach it. We don't want two |
| 163 // devices with the same name open at the same time. | 176 // devices with the same name open at the same time. |
| 164 if (converters_[path]) | 177 if (converters_[path]) |
| 165 DetachInputDevice(path); | 178 DetachInputDevice(path); |
| 166 | 179 |
| 167 // Add initialized device to map. | 180 // Add initialized device to map. |
| 168 converters_[path] = converter.release(); | 181 converters_[path] = converter.release(); |
| 169 converters_[path]->Start(); | 182 converters_[path]->Start(); |
| 170 | 183 |
| 171 NotifyHotplugEventObserver(*converters_[path]); | 184 NotifyHotplugEventObserver(*converters_[path]); |
| 172 } | 185 } |
| 173 | 186 |
| 174 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) { | 187 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) { |
| 175 if (event.device_type() != DeviceEvent::INPUT) | 188 if (event.device_type() != DeviceEvent::INPUT) |
| 176 return; | 189 return; |
| 177 | 190 |
| 178 switch (event.action_type()) { | 191 switch (event.action_type()) { |
| 179 case DeviceEvent::ADD: | 192 case DeviceEvent::ADD: |
| 180 case DeviceEvent::CHANGE: { | 193 case DeviceEvent::CHANGE: { |
| 181 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value()); | 194 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value()); |
| 182 | 195 |
| 196 scoped_ptr<OpenInputDeviceParams> params(new OpenInputDeviceParams); |
| 197 params->id = NextDeviceId(); |
| 198 params->path = event.path(); |
| 199 params->dispatch_callback = dispatch_callback_; |
| 200 params->modifiers = &modifiers_; |
| 201 params->cursor = cursor_; |
| 202 |
| 203 OpenInputDeviceReplyCallback reply_callback = |
| 204 base::Bind(&EventFactoryEvdev::AttachInputDevice, |
| 205 weak_ptr_factory_.GetWeakPtr()); |
| 206 |
| 183 // Dispatch task to open from the worker pool, since open may block. | 207 // Dispatch task to open from the worker pool, since open may block. |
| 184 base::WorkerPool::PostTask( | 208 base::WorkerPool::PostTask(FROM_HERE, |
| 185 FROM_HERE, | 209 base::Bind(&OpenInputDevice, |
| 186 base::Bind(&OpenInputDevice, | 210 base::Passed(¶ms), |
| 187 event.path(), | 211 ui_task_runner_, |
| 188 &modifiers_, | 212 reply_callback), |
| 189 cursor_, | 213 true /* task_is_slow */); |
| 190 NextDeviceId(), | |
| 191 ui_task_runner_, | |
| 192 dispatch_callback_, | |
| 193 base::Bind(&EventFactoryEvdev::AttachInputDevice, | |
| 194 weak_ptr_factory_.GetWeakPtr(), | |
| 195 event.path())), | |
| 196 true); | |
| 197 } | 214 } |
| 198 break; | 215 break; |
| 199 case DeviceEvent::REMOVE: { | 216 case DeviceEvent::REMOVE: { |
| 200 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value()); | 217 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value()); |
| 201 DetachInputDevice(event.path()); | 218 DetachInputDevice(event.path()); |
| 202 } | 219 } |
| 203 break; | 220 break; |
| 204 } | 221 } |
| 205 } | 222 } |
| 206 | 223 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 } | 284 } |
| 268 | 285 |
| 269 observer->OnTouchscreenDevicesUpdated(touchscreens); | 286 observer->OnTouchscreenDevicesUpdated(touchscreens); |
| 270 } | 287 } |
| 271 | 288 |
| 272 int EventFactoryEvdev::NextDeviceId() { | 289 int EventFactoryEvdev::NextDeviceId() { |
| 273 return ++last_device_id_; | 290 return ++last_device_id_; |
| 274 } | 291 } |
| 275 | 292 |
| 276 } // namespace ui | 293 } // namespace ui |
| OLD | NEW |