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

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

Issue 863353003: [PATCH 6/11] ozone: evdev: Factor device I/O out of EventFactoryOzone (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix compile with USE_EVDEV_GESTURES Created 5 years, 10 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
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>
8 #include <linux/input.h>
9
10 #include "base/bind.h" 7 #include "base/bind.h"
11 #include "base/stl_util.h" 8 #include "base/debug/trace_event.h"
12 #include "base/task_runner.h" 9 #include "base/task_runner.h"
13 #include "base/thread_task_runner_handle.h" 10 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/worker_pool.h" 11 #include "base/threading/worker_pool.h"
15 #include "base/time/time.h" 12 #include "base/time/time.h"
16 #include "base/trace_event/trace_event.h"
17 #include "ui/events/devices/device_data_manager.h" 13 #include "ui/events/devices/device_data_manager.h"
18 #include "ui/events/devices/device_util_linux.h"
19 #include "ui/events/devices/input_device.h" 14 #include "ui/events/devices/input_device.h"
20 #include "ui/events/ozone/device/device_event.h" 15 #include "ui/events/ozone/device/device_event.h"
21 #include "ui/events/ozone/device/device_manager.h" 16 #include "ui/events/ozone/device/device_manager.h"
22 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" 17 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
23 #include "ui/events/ozone/evdev/event_converter_evdev_impl.h" 18 #include "ui/events/ozone/evdev/input_controller_evdev.h"
19 #include "ui/events/ozone/evdev/input_device_factory_evdev.h"
24 #include "ui/events/ozone/evdev/input_injector_evdev.h" 20 #include "ui/events/ozone/evdev/input_injector_evdev.h"
25 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h"
26 #include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
27 21
28 #if defined(USE_EVDEV_GESTURES) 22 #if defined(USE_EVDEV_GESTURES)
29 #include "ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
30 #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cr os.h"
31 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h" 23 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
32 #endif 24 #endif
33 25
34 #ifndef EVIOCSCLOCKID
35 #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
36 #endif
37
38 namespace ui { 26 namespace ui {
39 27
40 namespace {
41
42 typedef base::Callback<void(scoped_ptr<EventConverterEvdev>)>
43 OpenInputDeviceReplyCallback;
44
45 struct OpenInputDeviceParams {
46 // Unique identifier for the new device.
47 int id;
48
49 // Device path to open.
50 base::FilePath path;
51
52 // Dispatcher for events. Call on UI thread only.
53 DeviceEventDispatcherEvdev* dispatcher;
54
55 // State shared between devices. Must not be dereferenced on worker thread.
56 CursorDelegateEvdev* cursor;
57 #if defined(USE_EVDEV_GESTURES)
58 GesturePropertyProvider* gesture_property_provider;
59 #endif
60 };
61
62 #if defined(USE_EVDEV_GESTURES)
63 bool UseGesturesLibraryForDevice(const EventDeviceInfo& devinfo) {
64 if (devinfo.HasTouchpad())
65 return true;
66
67 if (devinfo.HasRelXY())
68 return true; // mouse
69
70 return false;
71 }
72 #endif
73
74 scoped_ptr<EventConverterEvdev> CreateConverter(
75 const OpenInputDeviceParams& params,
76 int fd,
77 InputDeviceType type,
78 const EventDeviceInfo& devinfo) {
79 #if defined(USE_EVDEV_GESTURES)
80 // Touchpad or mouse: use gestures library.
81 // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent
82 if (UseGesturesLibraryForDevice(devinfo)) {
83 scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp =
84 make_scoped_ptr(new GestureInterpreterLibevdevCros(
85 params.id, params.cursor, params.gesture_property_provider,
86 params.dispatcher));
87 return make_scoped_ptr(new EventReaderLibevdevCros(
88 fd, params.path, params.id, type, devinfo, gesture_interp.Pass()));
89 }
90 #endif
91
92 // Touchscreen: use TouchEventConverterEvdev.
93 if (devinfo.HasMTAbsXY()) {
94 scoped_ptr<TouchEventConverterEvdev> converter(new TouchEventConverterEvdev(
95 fd, params.path, params.id, type, params.dispatcher));
96 converter->Initialize(devinfo);
97 return converter.Pass();
98 }
99
100 // Graphics tablet
101 if (devinfo.HasAbsXY())
102 return make_scoped_ptr<EventConverterEvdev>(new TabletEventConverterEvdev(
103 fd, params.path, params.id, type, params.cursor, devinfo,
104 params.dispatcher));
105
106 // Everything else: use EventConverterEvdevImpl.
107 return make_scoped_ptr<EventConverterEvdevImpl>(
108 new EventConverterEvdevImpl(fd, params.path, params.id, type, devinfo,
109 params.cursor, params.dispatcher));
110 }
111
112 // Open an input device. Opening may put the calling thread to sleep, and
113 // therefore should be run on a thread where latency is not critical. We
114 // run it on a thread from the worker pool.
115 //
116 // This takes a TaskRunner and runs the reply on that thread, so that we
117 // can hop threads if necessary (back to the UI thread).
118 void OpenInputDevice(scoped_ptr<OpenInputDeviceParams> params,
119 scoped_refptr<base::TaskRunner> reply_runner,
120 const OpenInputDeviceReplyCallback& reply_callback) {
121 const base::FilePath& path = params->path;
122
123 TRACE_EVENT1("ozone", "OpenInputDevice", "path", path.value());
124
125 int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK);
126 if (fd < 0) {
127 PLOG(ERROR) << "Cannot open '" << path.value();
128 return;
129 }
130
131 // Use monotonic timestamps for events. The touch code in particular
132 // expects event timestamps to correlate to the monotonic clock
133 // (base::TimeTicks).
134 unsigned int clk = CLOCK_MONOTONIC;
135 if (ioctl(fd, EVIOCSCLOCKID, &clk))
136 PLOG(ERROR) << "failed to set CLOCK_MONOTONIC";
137
138 EventDeviceInfo devinfo;
139 if (!devinfo.Initialize(fd)) {
140 LOG(ERROR) << "failed to get device information for " << path.value();
141 close(fd);
142 return;
143 }
144
145 InputDeviceType type = GetInputDeviceTypeFromPath(path);
146
147 scoped_ptr<EventConverterEvdev> converter =
148 CreateConverter(*params, fd, type, devinfo);
149
150 // Reply with the constructed converter.
151 reply_runner->PostTask(FROM_HERE,
152 base::Bind(reply_callback, base::Passed(&converter)));
153 }
154
155 // Close an input device. Closing may put the calling thread to sleep, and
156 // therefore should be run on a thread where latency is not critical. We
157 // run it on the FILE thread.
158 void CloseInputDevice(const base::FilePath& path,
159 scoped_ptr<EventConverterEvdev> converter) {
160 TRACE_EVENT1("ozone", "CloseInputDevice", "path", path.value());
161 converter.reset();
162 }
163
164 } // namespace
165
166 EventFactoryEvdev::EventFactoryEvdev(CursorDelegateEvdev* cursor, 28 EventFactoryEvdev::EventFactoryEvdev(CursorDelegateEvdev* cursor,
167 DeviceManager* device_manager, 29 DeviceManager* device_manager,
168 KeyboardLayoutEngine* keyboard_layout) 30 KeyboardLayoutEngine* keyboard_layout)
169 : last_device_id_(0), 31 : last_device_id_(0),
170 device_manager_(device_manager), 32 device_manager_(device_manager),
171 dispatch_callback_( 33 dispatch_callback_(
172 base::Bind(&EventFactoryEvdev::PostUiEvent, base::Unretained(this))), 34 base::Bind(&EventFactoryEvdev::PostUiEvent, base::Unretained(this))),
173 keyboard_(&modifiers_, keyboard_layout, dispatch_callback_), 35 keyboard_(&modifiers_, keyboard_layout, dispatch_callback_),
174 cursor_(cursor), 36 cursor_(cursor),
175 #if defined(USE_EVDEV_GESTURES) 37 #if defined(USE_EVDEV_GESTURES)
176 gesture_property_provider_(new GesturePropertyProvider), 38 gesture_property_provider_(new GesturePropertyProvider),
177 #endif 39 #endif
178 input_controller_(this, 40 input_controller_(&keyboard_,
179 &keyboard_,
180 &button_map_ 41 &button_map_
181 #if defined(USE_EVDEV_GESTURES) 42 #if defined(USE_EVDEV_GESTURES)
182 , 43 ,
183 gesture_property_provider_.get() 44 gesture_property_provider_.get()
184 #endif 45 #endif
185 ), 46 ),
186 initialized_(false), 47 initialized_(false),
187 weak_ptr_factory_(this) { 48 weak_ptr_factory_(this) {
188 DCHECK(device_manager_); 49 DCHECK(device_manager_);
189 } 50 }
190 51
191 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); } 52 EventFactoryEvdev::~EventFactoryEvdev() {
53 }
192 54
193 void EventFactoryEvdev::Init() { 55 void EventFactoryEvdev::Init() {
194 DCHECK(!initialized_); 56 DCHECK(!initialized_);
195 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 57
58 // Set up device factory.
59 input_device_factory_.reset(
60 new InputDeviceFactoryEvdev(this, base::ThreadTaskRunnerHandle::Get(),
61 #if defined(USE_EVDEV_GESTURES)
62 gesture_property_provider_.get(),
63 #endif
64 cursor_));
65 // TODO(spang): This settings interface is really broken. crbug.com/450899
66 input_controller_.SetInputDeviceFactory(input_device_factory_.get());
196 67
197 // Scan & monitor devices. 68 // Scan & monitor devices.
198 device_manager_->AddObserver(this); 69 device_manager_->AddObserver(this);
199 device_manager_->ScanDevices(this); 70 device_manager_->ScanDevices(this);
200 71
201 initialized_ = true; 72 initialized_ = true;
202 } 73 }
203 74
204 scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() { 75 scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() {
205 return make_scoped_ptr(new InputInjectorEvdev( 76 return make_scoped_ptr(new InputInjectorEvdev(
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 FROM_HERE, 169 FROM_HERE,
299 base::Bind(&EventFactoryEvdev::DispatchUiEventTask, 170 base::Bind(&EventFactoryEvdev::DispatchUiEventTask,
300 weak_ptr_factory_.GetWeakPtr(), 171 weak_ptr_factory_.GetWeakPtr(),
301 base::Passed(&event))); 172 base::Passed(&event)));
302 } 173 }
303 174
304 void EventFactoryEvdev::DispatchUiEventTask(scoped_ptr<Event> event) { 175 void EventFactoryEvdev::DispatchUiEventTask(scoped_ptr<Event> event) {
305 DispatchEvent(event.get()); 176 DispatchEvent(event.get());
306 } 177 }
307 178
308 void EventFactoryEvdev::AttachInputDevice(
309 scoped_ptr<EventConverterEvdev> converter) {
310 const base::FilePath& path = converter->path();
311
312 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value());
313 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
314
315 // If we have an existing device, detach it. We don't want two
316 // devices with the same name open at the same time.
317 if (converters_[path])
318 DetachInputDevice(path);
319
320 // Add initialized device to map.
321 converters_[path] = converter.release();
322 converters_[path]->Start();
323
324 NotifyDeviceChange(*converters_[path]);
325 }
326
327 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) { 179 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) {
328 if (event.device_type() != DeviceEvent::INPUT) 180 if (event.device_type() != DeviceEvent::INPUT)
329 return; 181 return;
330 182
331 switch (event.action_type()) { 183 switch (event.action_type()) {
332 case DeviceEvent::ADD: 184 case DeviceEvent::ADD:
333 case DeviceEvent::CHANGE: { 185 case DeviceEvent::CHANGE: {
334 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value()); 186 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value());
335 187 input_device_factory_->AddInputDevice(NextDeviceId(), event.path());
336 scoped_ptr<OpenInputDeviceParams> params(new OpenInputDeviceParams); 188 break;
337 params->id = NextDeviceId();
338 params->path = event.path();
339 params->cursor = cursor_;
340 params->dispatcher = this;
341
342 #if defined(USE_EVDEV_GESTURES)
343 params->gesture_property_provider = gesture_property_provider_.get();
344 #endif
345
346 OpenInputDeviceReplyCallback reply_callback =
347 base::Bind(&EventFactoryEvdev::AttachInputDevice,
348 weak_ptr_factory_.GetWeakPtr());
349
350 // Dispatch task to open from the worker pool, since open may block.
351 base::WorkerPool::PostTask(FROM_HERE,
352 base::Bind(&OpenInputDevice,
353 base::Passed(&params),
354 ui_task_runner_,
355 reply_callback),
356 true /* task_is_slow */);
357 } 189 }
358 break;
359 case DeviceEvent::REMOVE: { 190 case DeviceEvent::REMOVE: {
360 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value()); 191 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value());
361 DetachInputDevice(event.path()); 192 input_device_factory_->RemoveInputDevice(event.path());
193 break;
362 } 194 }
363 break;
364 } 195 }
365 } 196 }
366 197
367 void EventFactoryEvdev::OnDispatcherListChanged() { 198 void EventFactoryEvdev::OnDispatcherListChanged() {
368 if (!initialized_) 199 if (!initialized_)
369 Init(); 200 Init();
370 } 201 }
371 202
372 void EventFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
373 TRACE_EVENT1("ozone", "DetachInputDevice", "path", path.value());
374 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
375
376 // Remove device from map.
377 scoped_ptr<EventConverterEvdev> converter(converters_[path]);
378 converters_.erase(path);
379
380 if (converter) {
381 // Cancel libevent notifications from this converter. This part must be
382 // on UI since the polling happens on UI.
383 converter->Stop();
384
385 NotifyDeviceChange(*converter);
386
387 // Dispatch task to close from the worker pool, since close may block.
388 base::WorkerPool::PostTask(
389 FROM_HERE,
390 base::Bind(&CloseInputDevice, path, base::Passed(&converter)),
391 true);
392 }
393 }
394
395 void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget, 203 void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget,
396 const gfx::PointF& location) { 204 const gfx::PointF& location) {
397 if (cursor_) { 205 if (cursor_) {
398 cursor_->MoveCursorTo(widget, location); 206 cursor_->MoveCursorTo(widget, location);
399 PostUiEvent(make_scoped_ptr(new MouseEvent(ET_MOUSE_MOVED, 207 PostUiEvent(make_scoped_ptr(new MouseEvent(ET_MOUSE_MOVED,
400 cursor_->GetLocation(), 208 cursor_->GetLocation(),
401 cursor_->GetLocation(), 209 cursor_->GetLocation(),
402 modifiers_.GetModifierFlags(), 210 modifiers_.GetModifierFlags(),
403 /* changed_button_flags */ 0))); 211 /* changed_button_flags */ 0)));
404 } 212 }
405 } 213 }
406 214
407 void EventFactoryEvdev::DisableInternalTouchpad() {
408 for (const auto& it : converters_) {
409 EventConverterEvdev* converter = it.second;
410 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
411 converter->HasTouchpad()) {
412 DCHECK(!converter->HasKeyboard());
413 converter->set_ignore_events(true);
414 }
415 }
416 }
417
418 void EventFactoryEvdev::EnableInternalTouchpad() {
419 for (const auto& it : converters_) {
420 EventConverterEvdev* converter = it.second;
421 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
422 converter->HasTouchpad()) {
423 DCHECK(!converter->HasKeyboard());
424 converter->set_ignore_events(false);
425 }
426 }
427 }
428
429 void EventFactoryEvdev::DisableInternalKeyboardExceptKeys(
430 scoped_ptr<std::set<DomCode>> excepted_keys) {
431 for (const auto& it : converters_) {
432 EventConverterEvdev* converter = it.second;
433 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
434 converter->HasKeyboard()) {
435 converter->SetAllowedKeys(excepted_keys.Pass());
436 }
437 }
438 }
439
440 void EventFactoryEvdev::EnableInternalKeyboard() {
441 for (const auto& it : converters_) {
442 EventConverterEvdev* converter = it.second;
443 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
444 converter->HasKeyboard()) {
445 converter->AllowAllKeys();
446 }
447 }
448 }
449
450 void EventFactoryEvdev::NotifyDeviceChange(
451 const EventConverterEvdev& converter) {
452 if (converter.HasTouchscreen())
453 NotifyTouchscreensUpdated();
454
455 if (converter.HasKeyboard())
456 NotifyKeyboardsUpdated();
457 }
458
459 void EventFactoryEvdev::NotifyTouchscreensUpdated() {
460 DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
461 std::vector<TouchscreenDevice> touchscreens;
462 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
463 if (it->second->HasTouchscreen()) {
464 // TODO(spang): Extract the number of touch-points supported by the
465 // device.
466 const int touch_points = 11;
467 touchscreens.push_back(TouchscreenDevice(
468 it->second->id(), it->second->type(), std::string() /* Device name */,
469 it->second->GetTouchscreenSize(), touch_points));
470 }
471 }
472
473 observer->OnTouchscreenDevicesUpdated(touchscreens);
474 }
475
476 void EventFactoryEvdev::NotifyKeyboardsUpdated() {
477 DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
478 std::vector<KeyboardDevice> keyboards;
479 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
480 if (it->second->HasKeyboard()) {
481 keyboards.push_back(KeyboardDevice(it->second->id(), it->second->type(),
482 std::string() /* Device name */));
483 }
484 }
485
486 observer->OnKeyboardDevicesUpdated(keyboards);
487 }
488
489 int EventFactoryEvdev::NextDeviceId() { 215 int EventFactoryEvdev::NextDeviceId() {
490 return ++last_device_id_; 216 return ++last_device_id_;
491 } 217 }
492 218
493 bool EventFactoryEvdev::GetDeviceIdsByType(const EventDeviceType type,
494 std::vector<int>* device_ids) {
495 if (device_ids)
496 device_ids->clear();
497 std::vector<int> ids;
498
499 #if defined(USE_EVDEV_GESTURES)
500 // Ask GesturePropertyProvider for matching devices.
501 gesture_property_provider_->GetDeviceIdsByType(type, &ids);
502 #endif
503 // In the future we can add other device matching logics here.
504
505 if (device_ids)
506 device_ids->assign(ids.begin(), ids.end());
507 return !ids.empty();
508 }
509
510 } // namespace ui 219 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/ozone/evdev/event_factory_evdev.h ('k') | ui/events/ozone/evdev/input_controller_evdev.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698