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

Side by Side Diff: ui/events/ozone/evdev/event_factory_evdev.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 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 unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "ui/events/ozone/evdev/event_factory_evdev.h"
6
7 #include <fcntl.h>
8 #include <linux/input.h>
9
10 #include "base/debug/trace_event.h"
11 #include "base/stl_util.h"
12 #include "base/task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/worker_pool.h"
15 #include "ui/events/device_data_manager.h"
16 #include "ui/events/ozone/device/device_event.h"
17 #include "ui/events/ozone/device/device_manager.h"
18 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
19 #include "ui/events/ozone/evdev/event_device_info.h"
20 #include "ui/events/ozone/evdev/key_event_converter_evdev.h"
21 #include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
22
23 #if defined(USE_EVDEV_GESTURES)
24 #include "ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
25 #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cr os.h"
26 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
27 #endif
28
29 #ifndef EVIOCSCLOCKID
30 #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
31 #endif
32
33 namespace ui {
34
35 namespace {
36
37 typedef base::Callback<void(scoped_ptr<EventConverterEvdev>)>
38 OpenInputDeviceReplyCallback;
39
40 struct OpenInputDeviceParams {
41 // Unique identifier for the new device.
42 int id;
43
44 // Device path to open.
45 base::FilePath path;
46
47 // Callback for dispatching events. Call on UI thread only.
48 EventDispatchCallback dispatch_callback;
49
50 // State shared between devices. Must not be dereferenced on worker thread.
51 EventModifiersEvdev* modifiers;
52 KeyboardEvdev* keyboard;
53 CursorDelegateEvdev* cursor;
54 #if defined(USE_EVDEV_GESTURES)
55 GesturePropertyProvider* gesture_property_provider;
56 #endif
57 };
58
59 #if defined(USE_EVDEV_GESTURES)
60 bool UseGesturesLibraryForDevice(const EventDeviceInfo& devinfo) {
61 if (devinfo.HasAbsXY() && !devinfo.IsMappedToScreen())
62 return true; // touchpad
63
64 if (devinfo.HasRelXY())
65 return true; // mouse
66
67 return false;
68 }
69 #endif
70
71 scoped_ptr<EventConverterEvdev> CreateConverter(
72 const OpenInputDeviceParams& params,
73 int fd,
74 const EventDeviceInfo& devinfo) {
75 #if defined(USE_EVDEV_GESTURES)
76 // Touchpad or mouse: use gestures library.
77 // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent
78 if (UseGesturesLibraryForDevice(devinfo)) {
79 scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp = make_scoped_ptr(
80 new GestureInterpreterLibevdevCros(params.id,
81 params.modifiers,
82 params.cursor,
83 params.keyboard,
84 params.gesture_property_provider,
85 params.dispatch_callback));
86 return make_scoped_ptr(new EventReaderLibevdevCros(
87 fd, params.path, params.id, gesture_interp.Pass()));
88 }
89 #endif
90
91 // Touchscreen: use TouchEventConverterEvdev.
92 scoped_ptr<EventConverterEvdev> converter;
93 if (devinfo.HasAbsXY())
94 return make_scoped_ptr<EventConverterEvdev>(new TouchEventConverterEvdev(
95 fd, params.path, params.id, devinfo, params.dispatch_callback));
96
97 // Everything else: use KeyEventConverterEvdev.
98 return make_scoped_ptr<EventConverterEvdev>(
99 new KeyEventConverterEvdev(fd, params.path, params.id, params.keyboard));
100 }
101
102 // Open an input device. Opening may put the calling thread to sleep, and
103 // therefore should be run on a thread where latency is not critical. We
104 // run it on a thread from the worker pool.
105 //
106 // This takes a TaskRunner and runs the reply on that thread, so that we
107 // can hop threads if necessary (back to the UI thread).
108 void OpenInputDevice(scoped_ptr<OpenInputDeviceParams> params,
109 scoped_refptr<base::TaskRunner> reply_runner,
110 const OpenInputDeviceReplyCallback& reply_callback) {
111 const base::FilePath& path = params->path;
112
113 TRACE_EVENT1("ozone", "OpenInputDevice", "path", path.value());
114
115 int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK);
116 if (fd < 0) {
117 PLOG(ERROR) << "Cannot open '" << path.value();
118 return;
119 }
120
121 // Use monotonic timestamps for events. The touch code in particular
122 // expects event timestamps to correlate to the monotonic clock
123 // (base::TimeTicks).
124 unsigned int clk = CLOCK_MONOTONIC;
125 if (ioctl(fd, EVIOCSCLOCKID, &clk))
126 PLOG(ERROR) << "failed to set CLOCK_MONOTONIC";
127
128 EventDeviceInfo devinfo;
129 if (!devinfo.Initialize(fd)) {
130 LOG(ERROR) << "failed to get device information for " << path.value();
131 close(fd);
132 return;
133 }
134
135 scoped_ptr<EventConverterEvdev> converter =
136 CreateConverter(*params, fd, devinfo);
137
138 // Reply with the constructed converter.
139 reply_runner->PostTask(FROM_HERE,
140 base::Bind(reply_callback, base::Passed(&converter)));
141 }
142
143 // Close an input device. Closing may put the calling thread to sleep, and
144 // therefore should be run on a thread where latency is not critical. We
145 // run it on the FILE thread.
146 void CloseInputDevice(const base::FilePath& path,
147 scoped_ptr<EventConverterEvdev> converter) {
148 TRACE_EVENT1("ozone", "CloseInputDevice", "path", path.value());
149 converter.reset();
150 }
151
152 } // namespace
153
154 EventFactoryEvdev::EventFactoryEvdev(CursorDelegateEvdev* cursor,
155 DeviceManager* device_manager)
156 : last_device_id_(0),
157 device_manager_(device_manager),
158 dispatch_callback_(
159 base::Bind(&EventFactoryEvdev::PostUiEvent, base::Unretained(this))),
160 keyboard_(&modifiers_, dispatch_callback_),
161 cursor_(cursor),
162 #if defined(USE_EVDEV_GESTURES)
163 gesture_property_provider_(new GesturePropertyProvider),
164 #endif
165 weak_ptr_factory_(this) {
166 DCHECK(device_manager_);
167 }
168
169 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); }
170
171 void EventFactoryEvdev::PostUiEvent(scoped_ptr<Event> event) {
172 base::ThreadTaskRunnerHandle::Get()->PostTask(
173 FROM_HERE,
174 base::Bind(&EventFactoryEvdev::DispatchUiEventTask,
175 weak_ptr_factory_.GetWeakPtr(),
176 base::Passed(&event)));
177 }
178
179 void EventFactoryEvdev::DispatchUiEventTask(scoped_ptr<Event> event) {
180 DispatchEvent(event.get());
181 }
182
183 void EventFactoryEvdev::AttachInputDevice(
184 scoped_ptr<EventConverterEvdev> converter) {
185 const base::FilePath& path = converter->path();
186
187 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value());
188 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
189
190 // If we have an existing device, detach it. We don't want two
191 // devices with the same name open at the same time.
192 if (converters_[path])
193 DetachInputDevice(path);
194
195 // Add initialized device to map.
196 converters_[path] = converter.release();
197 converters_[path]->Start();
198
199 NotifyHotplugEventObserver(*converters_[path]);
200 }
201
202 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) {
203 if (event.device_type() != DeviceEvent::INPUT)
204 return;
205
206 switch (event.action_type()) {
207 case DeviceEvent::ADD:
208 case DeviceEvent::CHANGE: {
209 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value());
210
211 scoped_ptr<OpenInputDeviceParams> params(new OpenInputDeviceParams);
212 params->id = NextDeviceId();
213 params->path = event.path();
214 params->dispatch_callback = dispatch_callback_;
215 params->modifiers = &modifiers_;
216 params->keyboard = &keyboard_;
217 params->cursor = cursor_;
218 #if defined(USE_EVDEV_GESTURES)
219 params->gesture_property_provider = gesture_property_provider_.get();
220 #endif
221
222 OpenInputDeviceReplyCallback reply_callback =
223 base::Bind(&EventFactoryEvdev::AttachInputDevice,
224 weak_ptr_factory_.GetWeakPtr());
225
226 // Dispatch task to open from the worker pool, since open may block.
227 base::WorkerPool::PostTask(FROM_HERE,
228 base::Bind(&OpenInputDevice,
229 base::Passed(&params),
230 ui_task_runner_,
231 reply_callback),
232 true /* task_is_slow */);
233 }
234 break;
235 case DeviceEvent::REMOVE: {
236 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value());
237 DetachInputDevice(event.path());
238 }
239 break;
240 }
241 }
242
243 void EventFactoryEvdev::OnDispatcherListChanged() {
244 if (!ui_task_runner_.get()) {
245 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
246 // Scan & monitor devices.
247 device_manager_->AddObserver(this);
248 device_manager_->ScanDevices(this);
249 }
250 }
251
252 void EventFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
253 TRACE_EVENT1("ozone", "DetachInputDevice", "path", path.value());
254 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
255
256 // Remove device from map.
257 scoped_ptr<EventConverterEvdev> converter(converters_[path]);
258 converters_.erase(path);
259
260 if (converter) {
261 // Cancel libevent notifications from this converter. This part must be
262 // on UI since the polling happens on UI.
263 converter->Stop();
264
265 NotifyHotplugEventObserver(*converter);
266
267 // Dispatch task to close from the worker pool, since close may block.
268 base::WorkerPool::PostTask(
269 FROM_HERE,
270 base::Bind(&CloseInputDevice, path, base::Passed(&converter)),
271 true);
272 }
273 }
274
275 void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget,
276 const gfx::PointF& location) {
277 if (cursor_) {
278 cursor_->MoveCursorTo(widget, location);
279 PostUiEvent(make_scoped_ptr(new MouseEvent(ET_MOUSE_MOVED,
280 cursor_->location(),
281 cursor_->location(),
282 modifiers_.GetModifierFlags(),
283 /* changed_button_flags */ 0)));
284 }
285 }
286
287 void EventFactoryEvdev::NotifyHotplugEventObserver(
288 const EventConverterEvdev& converter) {
289 // For now the only information propagated is related to touchscreens. Ignore
290 // events for everything but touchscreens.
291 if (!converter.HasTouchscreen())
292 return;
293
294 DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
295 std::vector<TouchscreenDevice> touchscreens;
296 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
297 if (it->second->HasTouchscreen()) {
298 touchscreens.push_back(TouchscreenDevice(it->second->id(),
299 it->second->GetTouchscreenSize(),
300 false /* is_internal */));
301 }
302 }
303
304 observer->OnTouchscreenDevicesUpdated(touchscreens);
305 }
306
307 int EventFactoryEvdev::NextDeviceId() {
308 return ++last_device_id_;
309 }
310
311 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/ozone/evdev/event_factory_evdev.h ('k') | ui/events/ozone/evdev/event_modifiers_evdev.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698