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

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: updates for events_unittests 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
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/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
12 #include "base/stl_util.h"
13 #include "base/task_runner.h" 9 #include "base/task_runner.h"
14 #include "base/thread_task_runner_handle.h" 10 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/worker_pool.h" 11 #include "base/threading/worker_pool.h"
16 #include "base/time/time.h"
17 #include "ui/events/devices/device_data_manager.h" 12 #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" 13 #include "ui/events/devices/input_device.h"
20 #include "ui/events/ozone/device/device_event.h" 14 #include "ui/events/ozone/device/device_event.h"
21 #include "ui/events/ozone/device/device_manager.h" 15 #include "ui/events/ozone/device/device_manager.h"
22 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" 16 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
23 #include "ui/events/ozone/evdev/event_converter_evdev_impl.h" 17 #include "ui/events/ozone/evdev/input_controller_evdev.h"
18 #include "ui/events/ozone/evdev/input_device_factory_evdev.h"
24 #include "ui/events/ozone/evdev/input_injector_evdev.h" 19 #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 20
28 #if defined(USE_EVDEV_GESTURES) 21 #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" 22 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
32 #endif 23 #endif
33 24
34 #ifndef EVIOCSCLOCKID
35 #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
36 #endif
37
38 namespace ui { 25 namespace ui {
39 26
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, 27 EventFactoryEvdev::EventFactoryEvdev(CursorDelegateEvdev* cursor,
167 DeviceManager* device_manager, 28 DeviceManager* device_manager,
168 KeyboardLayoutEngine* keyboard_layout) 29 KeyboardLayoutEngine* keyboard_layout)
169 : last_device_id_(0), 30 : last_device_id_(0),
170 device_manager_(device_manager), 31 device_manager_(device_manager),
171 dispatch_callback_( 32 dispatch_callback_(
172 base::Bind(&EventFactoryEvdev::PostUiEvent, base::Unretained(this))), 33 base::Bind(&EventFactoryEvdev::PostUiEvent, base::Unretained(this))),
173 keyboard_(&modifiers_, keyboard_layout, dispatch_callback_), 34 keyboard_(&modifiers_, keyboard_layout, dispatch_callback_),
174 cursor_(cursor), 35 cursor_(cursor),
175 #if defined(USE_EVDEV_GESTURES) 36 #if defined(USE_EVDEV_GESTURES)
176 gesture_property_provider_(new GesturePropertyProvider), 37 gesture_property_provider_(new GesturePropertyProvider),
177 #endif 38 #endif
178 input_controller_(this, 39 input_controller_(&keyboard_,
179 &keyboard_,
180 &button_map_ 40 &button_map_
181 #if defined(USE_EVDEV_GESTURES) 41 #if defined(USE_EVDEV_GESTURES)
182 , 42 ,
183 gesture_property_provider_.get() 43 gesture_property_provider_.get()
184 #endif 44 #endif
185 ), 45 ),
186 initialized_(false), 46 initialized_(false),
187 weak_ptr_factory_(this) { 47 weak_ptr_factory_(this) {
188 DCHECK(device_manager_); 48 DCHECK(device_manager_);
189 } 49 }
190 50
191 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); } 51 EventFactoryEvdev::~EventFactoryEvdev() {
52 }
192 53
193 void EventFactoryEvdev::Init() { 54 void EventFactoryEvdev::Init() {
194 DCHECK(!initialized_); 55 DCHECK(!initialized_);
195 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 56
57 // Set up device factory.
58 input_device_factory_.reset(
59 new InputDeviceFactoryEvdev(this, base::ThreadTaskRunnerHandle::Get(),
60 #if defined(USE_EVDEV_GESTURES)
61 gesture_property_provider_.get(),
62 #endif
63 cursor_));
64 // TODO(spang): This settings interface is really broken. crbug.com/450899
65 input_controller_.SetInputDeviceFactory(input_device_factory_.get());
196 66
197 // Scan & monitor devices. 67 // Scan & monitor devices.
198 device_manager_->AddObserver(this); 68 device_manager_->AddObserver(this);
199 device_manager_->ScanDevices(this); 69 device_manager_->ScanDevices(this);
200 70
201 initialized_ = true; 71 initialized_ = true;
202 } 72 }
203 73
204 scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() { 74 scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() {
205 return make_scoped_ptr(new InputInjectorEvdev( 75 return make_scoped_ptr(new InputInjectorEvdev(
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 FROM_HERE, 173 FROM_HERE,
304 base::Bind(&EventFactoryEvdev::DispatchUiEventTask, 174 base::Bind(&EventFactoryEvdev::DispatchUiEventTask,
305 weak_ptr_factory_.GetWeakPtr(), 175 weak_ptr_factory_.GetWeakPtr(),
306 base::Passed(&event))); 176 base::Passed(&event)));
307 } 177 }
308 178
309 void EventFactoryEvdev::DispatchUiEventTask(scoped_ptr<Event> event) { 179 void EventFactoryEvdev::DispatchUiEventTask(scoped_ptr<Event> event) {
310 DispatchEvent(event.get()); 180 DispatchEvent(event.get());
311 } 181 }
312 182
313 void EventFactoryEvdev::AttachInputDevice(
314 scoped_ptr<EventConverterEvdev> converter) {
315 const base::FilePath& path = converter->path();
316
317 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value());
318 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
319
320 // If we have an existing device, detach it. We don't want two
321 // devices with the same name open at the same time.
322 if (converters_[path])
323 DetachInputDevice(path);
324
325 // Add initialized device to map.
326 converters_[path] = converter.release();
327 converters_[path]->Start();
328
329 NotifyDeviceChange(*converters_[path]);
330 }
331
332 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) { 183 void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) {
333 if (event.device_type() != DeviceEvent::INPUT) 184 if (event.device_type() != DeviceEvent::INPUT)
334 return; 185 return;
335 186
336 switch (event.action_type()) { 187 switch (event.action_type()) {
337 case DeviceEvent::ADD: 188 case DeviceEvent::ADD:
338 case DeviceEvent::CHANGE: { 189 case DeviceEvent::CHANGE: {
339 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value()); 190 TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value());
340 191 input_device_factory_->AddInputDevice(NextDeviceId(), event.path());
341 scoped_ptr<OpenInputDeviceParams> params(new OpenInputDeviceParams); 192 break;
342 params->id = NextDeviceId();
343 params->path = event.path();
344 params->cursor = cursor_;
345 params->dispatcher = this;
346
347 #if defined(USE_EVDEV_GESTURES)
348 params->gesture_property_provider = gesture_property_provider_.get();
349 #endif
350
351 OpenInputDeviceReplyCallback reply_callback =
352 base::Bind(&EventFactoryEvdev::AttachInputDevice,
353 weak_ptr_factory_.GetWeakPtr());
354
355 // Dispatch task to open from the worker pool, since open may block.
356 base::WorkerPool::PostTask(FROM_HERE,
357 base::Bind(&OpenInputDevice,
358 base::Passed(&params),
359 ui_task_runner_,
360 reply_callback),
361 true /* task_is_slow */);
362 } 193 }
363 break;
364 case DeviceEvent::REMOVE: { 194 case DeviceEvent::REMOVE: {
365 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value()); 195 TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value());
366 DetachInputDevice(event.path()); 196 input_device_factory_->RemoveInputDevice(event.path());
197 break;
367 } 198 }
368 break;
369 } 199 }
370 } 200 }
371 201
372 void EventFactoryEvdev::OnDispatcherListChanged() { 202 void EventFactoryEvdev::OnDispatcherListChanged() {
373 if (!initialized_) 203 if (!initialized_)
374 Init(); 204 Init();
375 } 205 }
376 206
377 void EventFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
378 TRACE_EVENT1("ozone", "DetachInputDevice", "path", path.value());
379 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
380
381 // Remove device from map.
382 scoped_ptr<EventConverterEvdev> converter(converters_[path]);
383 converters_.erase(path);
384
385 if (converter) {
386 // Cancel libevent notifications from this converter. This part must be
387 // on UI since the polling happens on UI.
388 converter->Stop();
389
390 NotifyDeviceChange(*converter);
391
392 // Dispatch task to close from the worker pool, since close may block.
393 base::WorkerPool::PostTask(
394 FROM_HERE,
395 base::Bind(&CloseInputDevice, path, base::Passed(&converter)),
396 true);
397 }
398 }
399
400 void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget, 207 void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget,
401 const gfx::PointF& location) { 208 const gfx::PointF& location) {
402 if (cursor_) { 209 if (cursor_) {
403 cursor_->MoveCursorTo(widget, location); 210 cursor_->MoveCursorTo(widget, location);
404 PostUiEvent(make_scoped_ptr(new MouseEvent(ET_MOUSE_MOVED, 211 PostUiEvent(make_scoped_ptr(new MouseEvent(ET_MOUSE_MOVED,
405 cursor_->GetLocation(), 212 cursor_->GetLocation(),
406 cursor_->GetLocation(), 213 cursor_->GetLocation(),
407 modifiers_.GetModifierFlags(), 214 modifiers_.GetModifierFlags(),
408 /* changed_button_flags */ 0))); 215 /* changed_button_flags */ 0)));
409 } 216 }
410 } 217 }
411 218
412 void EventFactoryEvdev::DisableInternalTouchpad() {
413 for (const auto& it : converters_) {
414 EventConverterEvdev* converter = it.second;
415 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
416 converter->HasTouchpad()) {
417 DCHECK(!converter->HasKeyboard());
418 converter->set_ignore_events(true);
419 }
420 }
421 }
422
423 void EventFactoryEvdev::EnableInternalTouchpad() {
424 for (const auto& it : converters_) {
425 EventConverterEvdev* converter = it.second;
426 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
427 converter->HasTouchpad()) {
428 DCHECK(!converter->HasKeyboard());
429 converter->set_ignore_events(false);
430 }
431 }
432 }
433
434 void EventFactoryEvdev::DisableInternalKeyboardExceptKeys(
435 scoped_ptr<std::set<DomCode>> excepted_keys) {
436 for (const auto& it : converters_) {
437 EventConverterEvdev* converter = it.second;
438 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
439 converter->HasKeyboard()) {
440 converter->SetAllowedKeys(excepted_keys.Pass());
441 }
442 }
443 }
444
445 void EventFactoryEvdev::EnableInternalKeyboard() {
446 for (const auto& it : converters_) {
447 EventConverterEvdev* converter = it.second;
448 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
449 converter->HasKeyboard()) {
450 converter->AllowAllKeys();
451 }
452 }
453 }
454
455 void EventFactoryEvdev::NotifyDeviceChange(
456 const EventConverterEvdev& converter) {
457 if (converter.HasTouchscreen())
458 NotifyTouchscreensUpdated();
459
460 if (converter.HasKeyboard())
461 NotifyKeyboardsUpdated();
462 }
463
464 void EventFactoryEvdev::NotifyTouchscreensUpdated() {
465 DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
466 std::vector<TouchscreenDevice> touchscreens;
467 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
468 if (it->second->HasTouchscreen()) {
469 // TODO(spang): Extract the number of touch-points supported by the
470 // device.
471 const int touch_points = 11;
472 touchscreens.push_back(TouchscreenDevice(
473 it->second->id(), it->second->type(), std::string() /* Device name */,
474 it->second->GetTouchscreenSize(), touch_points));
475 }
476 }
477
478 observer->OnTouchscreenDevicesUpdated(touchscreens);
479 }
480
481 void EventFactoryEvdev::NotifyKeyboardsUpdated() {
482 DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
483 std::vector<KeyboardDevice> keyboards;
484 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
485 if (it->second->HasKeyboard()) {
486 keyboards.push_back(KeyboardDevice(it->second->id(), it->second->type(),
487 std::string() /* Device name */));
488 }
489 }
490
491 observer->OnKeyboardDevicesUpdated(keyboards);
492 }
493
494 int EventFactoryEvdev::NextDeviceId() { 219 int EventFactoryEvdev::NextDeviceId() {
495 return ++last_device_id_; 220 return ++last_device_id_;
496 } 221 }
497 222
498 bool EventFactoryEvdev::GetDeviceIdsByType(const EventDeviceType type,
499 std::vector<int>* device_ids) {
500 if (device_ids)
501 device_ids->clear();
502 std::vector<int> ids;
503
504 #if defined(USE_EVDEV_GESTURES)
505 // Ask GesturePropertyProvider for matching devices.
506 gesture_property_provider_->GetDeviceIdsByType(type, &ids);
507 #endif
508 // In the future we can add other device matching logics here.
509
510 if (device_ids)
511 device_ids->assign(ids.begin(), ids.end());
512 return !ids.empty();
513 }
514
515 } // namespace ui 223 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698