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

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

Issue 1287103004: Sync ui/events to chromium @ https://codereview.chromium.org/1210203002 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: rebased Created 5 years, 4 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 2015 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/input_device_factory_evdev.h"
6
7 #include <fcntl.h>
8 #include <linux/input.h>
9
10 #include "base/stl_util.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/threading/worker_pool.h"
13 #include "base/time/time.h"
14 #include "base/trace_event/trace_event.h"
15 #include "ui/events/devices/device_data_manager.h"
16 #include "ui/events/devices/device_util_linux.h"
17 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
18 #include "ui/events/ozone/evdev/event_converter_evdev_impl.h"
19 #include "ui/events/ozone/evdev/event_device_info.h"
20 #include "ui/events/ozone/evdev/tablet_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_feedback.h"
26 #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cr os.h"
27 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
28 #endif
29
30 #ifndef EVIOCSCLOCKID
31 #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
32 #endif
33
34 namespace ui {
35
36 namespace {
37
38 typedef base::Callback<void(scoped_ptr<EventConverterEvdev>)>
39 OpenInputDeviceReplyCallback;
40
41 struct OpenInputDeviceParams {
42 // Unique identifier for the new device.
43 int id;
44
45 // Device path to open.
46 base::FilePath path;
47
48 // Dispatcher for events. Call on UI thread only.
49 DeviceEventDispatcherEvdev* dispatcher;
50
51 // State shared between devices. Must not be dereferenced on worker thread.
52 CursorDelegateEvdev* cursor;
53 #if defined(USE_EVDEV_GESTURES)
54 GesturePropertyProvider* gesture_property_provider;
55 #endif
56 };
57
58 #if defined(USE_EVDEV_GESTURES)
59 void SetGestureIntProperty(GesturePropertyProvider* provider,
60 int id,
61 const std::string& name,
62 int value) {
63 GesturesProp* property = provider->GetProperty(id, name);
64 if (property) {
65 std::vector<int> values(1, value);
66 property->SetIntValue(values);
67 }
68 }
69
70 void SetGestureBoolProperty(GesturePropertyProvider* provider,
71 int id,
72 const std::string& name,
73 bool value) {
74 GesturesProp* property = provider->GetProperty(id, name);
75 if (property) {
76 std::vector<bool> values(1, value);
77 property->SetBoolValue(values);
78 }
79 }
80
81 #endif
82
83 scoped_ptr<EventConverterEvdev> CreateConverter(
84 const OpenInputDeviceParams& params,
85 int fd,
86 InputDeviceType type,
87 const EventDeviceInfo& devinfo) {
88 #if defined(USE_EVDEV_GESTURES)
89 // Touchpad or mouse: use gestures library.
90 // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent
91 if (devinfo.HasTouchpad() || devinfo.HasMouse()) {
92 scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp =
93 make_scoped_ptr(new GestureInterpreterLibevdevCros(
94 params.id, params.cursor, params.gesture_property_provider,
95 params.dispatcher));
96 return make_scoped_ptr(new EventReaderLibevdevCros(
97 fd, params.path, params.id, type, devinfo, gesture_interp.Pass()));
98 }
99 #endif
100
101 // Touchscreen: use TouchEventConverterEvdev.
102 if (devinfo.HasTouchscreen()) {
103 scoped_ptr<TouchEventConverterEvdev> converter(new TouchEventConverterEvdev(
104 fd, params.path, params.id, type, devinfo, params.dispatcher));
105 converter->Initialize(devinfo);
106 return converter.Pass();
107 }
108
109 // Graphics tablet
110 if (devinfo.HasTablet())
111 return make_scoped_ptr<EventConverterEvdev>(new TabletEventConverterEvdev(
112 fd, params.path, params.id, type, params.cursor, devinfo,
113 params.dispatcher));
114
115 // Everything else: use EventConverterEvdevImpl.
116 return make_scoped_ptr<EventConverterEvdevImpl>(
117 new EventConverterEvdevImpl(fd, params.path, params.id, type, devinfo,
118 params.cursor, params.dispatcher));
119 }
120
121 // Open an input device. Opening may put the calling thread to sleep, and
122 // therefore should be run on a thread where latency is not critical. We
123 // run it on a thread from the worker pool.
124 //
125 // This takes a TaskRunner and runs the reply on that thread, so that we
126 // can hop threads if necessary (back to the UI thread).
127 void OpenInputDevice(scoped_ptr<OpenInputDeviceParams> params,
128 scoped_refptr<base::TaskRunner> reply_runner,
129 const OpenInputDeviceReplyCallback& reply_callback) {
130 const base::FilePath& path = params->path;
131 scoped_ptr<EventConverterEvdev> converter;
132
133 TRACE_EVENT1("evdev", "OpenInputDevice", "path", path.value());
134
135 int fd = open(path.value().c_str(), O_RDWR | O_NONBLOCK);
136 if (fd < 0) {
137 PLOG(ERROR) << "Cannot open '" << path.value();
138 reply_runner->PostTask(
139 FROM_HERE, base::Bind(reply_callback, base::Passed(&converter)));
140 return;
141 }
142
143 // Use monotonic timestamps for events. The touch code in particular
144 // expects event timestamps to correlate to the monotonic clock
145 // (base::TimeTicks).
146 unsigned int clk = CLOCK_MONOTONIC;
147 if (ioctl(fd, EVIOCSCLOCKID, &clk))
148 PLOG(ERROR) << "failed to set CLOCK_MONOTONIC";
149
150 EventDeviceInfo devinfo;
151 if (!devinfo.Initialize(fd)) {
152 LOG(ERROR) << "failed to get device information for " << path.value();
153 close(fd);
154 reply_runner->PostTask(
155 FROM_HERE, base::Bind(reply_callback, base::Passed(&converter)));
156 return;
157 }
158
159 InputDeviceType type = GetInputDeviceTypeFromPath(path);
160
161 converter = CreateConverter(*params, fd, type, devinfo);
162
163 // Reply with the constructed converter.
164 reply_runner->PostTask(FROM_HERE,
165 base::Bind(reply_callback, base::Passed(&converter)));
166 }
167
168 // Close an input device. Closing may put the calling thread to sleep, and
169 // therefore should be run on a thread where latency is not critical. We
170 // run it on the FILE thread.
171 void CloseInputDevice(const base::FilePath& path,
172 scoped_ptr<EventConverterEvdev> converter) {
173 TRACE_EVENT1("evdev", "CloseInputDevice", "path", path.value());
174 converter.reset();
175 }
176
177 } // namespace
178
179 InputDeviceFactoryEvdev::InputDeviceFactoryEvdev(
180 scoped_ptr<DeviceEventDispatcherEvdev> dispatcher,
181 CursorDelegateEvdev* cursor)
182 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
183 cursor_(cursor),
184 #if defined(USE_EVDEV_GESTURES)
185 gesture_property_provider_(new GesturePropertyProvider),
186 #endif
187 dispatcher_(dispatcher.Pass()),
188 weak_ptr_factory_(this) {
189 }
190
191 InputDeviceFactoryEvdev::~InputDeviceFactoryEvdev() {
192 STLDeleteValues(&converters_);
193 }
194
195 void InputDeviceFactoryEvdev::AddInputDevice(int id,
196 const base::FilePath& path) {
197 scoped_ptr<OpenInputDeviceParams> params(new OpenInputDeviceParams);
198 params->id = id;
199 params->path = path;
200 params->cursor = cursor_;
201 params->dispatcher = dispatcher_.get();
202
203 #if defined(USE_EVDEV_GESTURES)
204 params->gesture_property_provider = gesture_property_provider_.get();
205 #endif
206
207 OpenInputDeviceReplyCallback reply_callback =
208 base::Bind(&InputDeviceFactoryEvdev::AttachInputDevice,
209 weak_ptr_factory_.GetWeakPtr());
210
211 ++pending_device_changes_;
212
213 // Dispatch task to open from the worker pool, since open may block.
214 base::WorkerPool::PostTask(FROM_HERE,
215 base::Bind(&OpenInputDevice, base::Passed(&params),
216 task_runner_, reply_callback),
217 false /* task_is_slow */);
218 }
219
220 void InputDeviceFactoryEvdev::RemoveInputDevice(const base::FilePath& path) {
221 DetachInputDevice(path);
222 }
223
224 void InputDeviceFactoryEvdev::OnStartupScanComplete() {
225 startup_devices_enumerated_ = true;
226 NotifyDevicesUpdated();
227 }
228
229 void InputDeviceFactoryEvdev::AttachInputDevice(
230 scoped_ptr<EventConverterEvdev> converter) {
231 if (converter.get()) {
232 const base::FilePath& path = converter->path();
233
234 TRACE_EVENT1("evdev", "AttachInputDevice", "path", path.value());
235 DCHECK(task_runner_->RunsTasksOnCurrentThread());
236
237 // If we have an existing device, detach it. We don't want two
238 // devices with the same name open at the same time.
239 if (converters_[path])
240 DetachInputDevice(path);
241
242 // Add initialized device to map.
243 converters_[path] = converter.release();
244 converters_[path]->Start();
245 UpdateDirtyFlags(converters_[path]);
246
247 // Sync settings to new device.
248 ApplyInputDeviceSettings();
249 ApplyCapsLockLed();
250 }
251
252 --pending_device_changes_;
253 NotifyDevicesUpdated();
254 }
255
256 void InputDeviceFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
257 TRACE_EVENT1("evdev", "DetachInputDevice", "path", path.value());
258 DCHECK(task_runner_->RunsTasksOnCurrentThread());
259
260 // Remove device from map.
261 scoped_ptr<EventConverterEvdev> converter(converters_[path]);
262 converters_.erase(path);
263
264 if (converter) {
265 // Disable the device (to release keys/buttons/etc).
266 converter->SetEnabled(false);
267
268 // Cancel libevent notifications from this converter. This part must be
269 // on UI since the polling happens on UI.
270 converter->Stop();
271
272 UpdateDirtyFlags(converter.get());
273 NotifyDevicesUpdated();
274
275 // Dispatch task to close from the worker pool, since close may block.
276 base::WorkerPool::PostTask(
277 FROM_HERE,
278 base::Bind(&CloseInputDevice, path, base::Passed(&converter)), true);
279 }
280 }
281
282 void InputDeviceFactoryEvdev::SetCapsLockLed(bool enabled) {
283 caps_lock_led_enabled_ = enabled;
284 ApplyCapsLockLed();
285 }
286
287 void InputDeviceFactoryEvdev::UpdateInputDeviceSettings(
288 const InputDeviceSettingsEvdev& settings) {
289 input_device_settings_ = settings;
290 ApplyInputDeviceSettings();
291 }
292
293 void InputDeviceFactoryEvdev::GetTouchDeviceStatus(
294 const GetTouchDeviceStatusReply& reply) {
295 scoped_ptr<std::string> status(new std::string);
296 #if defined(USE_EVDEV_GESTURES)
297 DumpTouchDeviceStatus(gesture_property_provider_.get(), status.get());
298 #endif
299 reply.Run(status.Pass());
300 }
301
302 void InputDeviceFactoryEvdev::GetTouchEventLog(
303 const base::FilePath& out_dir,
304 const GetTouchEventLogReply& reply) {
305 scoped_ptr<std::vector<base::FilePath>> log_paths(
306 new std::vector<base::FilePath>);
307 #if defined(USE_EVDEV_GESTURES)
308 DumpTouchEventLog(gesture_property_provider_.get(), out_dir, log_paths.Pass(),
309 reply);
310 #else
311 reply.Run(log_paths.Pass());
312 #endif
313 }
314
315 base::WeakPtr<InputDeviceFactoryEvdev> InputDeviceFactoryEvdev::GetWeakPtr() {
316 return weak_ptr_factory_.GetWeakPtr();
317 }
318
319 void InputDeviceFactoryEvdev::ApplyInputDeviceSettings() {
320 TRACE_EVENT0("evdev", "ApplyInputDeviceSettings");
321
322 SetIntPropertyForOneType(DT_TOUCHPAD, "Pointer Sensitivity",
323 input_device_settings_.touchpad_sensitivity);
324 SetIntPropertyForOneType(DT_TOUCHPAD, "Scroll Sensitivity",
325 input_device_settings_.touchpad_sensitivity);
326
327 SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Enable",
328 input_device_settings_.tap_to_click_enabled);
329 SetBoolPropertyForOneType(DT_TOUCHPAD, "T5R2 Three Finger Click Enable",
330 input_device_settings_.three_finger_click_enabled);
331 SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Drag Enable",
332 input_device_settings_.tap_dragging_enabled);
333
334 SetBoolPropertyForOneType(DT_MULTITOUCH, "Australian Scrolling",
335 input_device_settings_.natural_scroll_enabled);
336
337 SetIntPropertyForOneType(DT_MOUSE, "Pointer Sensitivity",
338 input_device_settings_.mouse_sensitivity);
339 SetIntPropertyForOneType(DT_MOUSE, "Scroll Sensitivity",
340 input_device_settings_.mouse_sensitivity);
341
342 SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Paused",
343 input_device_settings_.tap_to_click_paused);
344
345 for (const auto& it : converters_) {
346 EventConverterEvdev* converter = it.second;
347 converter->SetEnabled(IsDeviceEnabled(converter));
348
349 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
350 converter->HasKeyboard()) {
351 converter->SetKeyFilter(
352 input_device_settings_.enable_internal_keyboard_filter,
353 input_device_settings_.internal_keyboard_allowed_keys);
354 }
355 }
356 }
357
358 void InputDeviceFactoryEvdev::ApplyCapsLockLed() {
359 for (const auto& it : converters_) {
360 EventConverterEvdev* converter = it.second;
361 converter->SetCapsLockLed(caps_lock_led_enabled_);
362 }
363 }
364
365 bool InputDeviceFactoryEvdev::IsDeviceEnabled(
366 const EventConverterEvdev* converter) {
367 if (!input_device_settings_.enable_internal_touchpad &&
368 converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
369 converter->HasTouchpad())
370 return false;
371
372 return input_device_settings_.enable_devices;
373 }
374
375 void InputDeviceFactoryEvdev::UpdateDirtyFlags(
376 const EventConverterEvdev* converter) {
377 if (converter->HasTouchscreen())
378 touchscreen_list_dirty_ = true;
379
380 if (converter->HasKeyboard())
381 keyboard_list_dirty_ = true;
382
383 if (converter->HasMouse())
384 mouse_list_dirty_ = true;
385
386 if (converter->HasTouchpad())
387 touchpad_list_dirty_ = true;
388 }
389
390 void InputDeviceFactoryEvdev::NotifyDevicesUpdated() {
391 if (!startup_devices_enumerated_ || pending_device_changes_)
392 return; // No update until full scan done and no pending operations.
393 if (touchscreen_list_dirty_)
394 NotifyTouchscreensUpdated();
395 if (keyboard_list_dirty_)
396 NotifyKeyboardsUpdated();
397 if (mouse_list_dirty_)
398 NotifyMouseDevicesUpdated();
399 if (touchpad_list_dirty_)
400 NotifyTouchpadDevicesUpdated();
401 if (!startup_devices_opened_) {
402 dispatcher_->DispatchDeviceListsComplete();
403 startup_devices_opened_ = true;
404 }
405 touchscreen_list_dirty_ = false;
406 keyboard_list_dirty_ = false;
407 mouse_list_dirty_ = false;
408 touchpad_list_dirty_ = false;
409 }
410
411 void InputDeviceFactoryEvdev::NotifyTouchscreensUpdated() {
412 std::vector<TouchscreenDevice> touchscreens;
413 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
414 if (it->second->HasTouchscreen()) {
415 touchscreens.push_back(TouchscreenDevice(it->second->input_device(),
416 it->second->GetTouchscreenSize(), it->second->GetTouchPoints()));
417 }
418 }
419
420 dispatcher_->DispatchTouchscreenDevicesUpdated(touchscreens);
421 }
422
423 void InputDeviceFactoryEvdev::NotifyKeyboardsUpdated() {
424 std::vector<KeyboardDevice> keyboards;
425 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
426 if (it->second->HasKeyboard()) {
427 keyboards.push_back(KeyboardDevice(it->second->input_device()));
428 }
429 }
430
431 dispatcher_->DispatchKeyboardDevicesUpdated(keyboards);
432 }
433
434 void InputDeviceFactoryEvdev::NotifyMouseDevicesUpdated() {
435 std::vector<InputDevice> mice;
436 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
437 if (it->second->HasMouse()) {
438 mice.push_back(it->second->input_device());
439 }
440 }
441
442 dispatcher_->DispatchMouseDevicesUpdated(mice);
443 }
444
445 void InputDeviceFactoryEvdev::NotifyTouchpadDevicesUpdated() {
446 std::vector<InputDevice> touchpads;
447 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
448 if (it->second->HasTouchpad()) {
449 touchpads.push_back(it->second->input_device());
450 }
451 }
452
453 dispatcher_->DispatchTouchpadDevicesUpdated(touchpads);
454 }
455
456 void InputDeviceFactoryEvdev::SetIntPropertyForOneType(
457 const EventDeviceType type,
458 const std::string& name,
459 int value) {
460 #if defined(USE_EVDEV_GESTURES)
461 std::vector<int> ids;
462 gesture_property_provider_->GetDeviceIdsByType(type, &ids);
463 for (size_t i = 0; i < ids.size(); ++i) {
464 SetGestureIntProperty(gesture_property_provider_.get(), ids[i], name,
465 value);
466 }
467 #endif
468 // In the future, we may add property setting codes for other non-gesture
469 // devices. One example would be keyboard settings.
470 // TODO(sheckylin): See http://crbug.com/398518 for example.
471 }
472
473 void InputDeviceFactoryEvdev::SetBoolPropertyForOneType(
474 const EventDeviceType type,
475 const std::string& name,
476 bool value) {
477 #if defined(USE_EVDEV_GESTURES)
478 std::vector<int> ids;
479 gesture_property_provider_->GetDeviceIdsByType(type, &ids);
480 for (size_t i = 0; i < ids.size(); ++i) {
481 SetGestureBoolProperty(gesture_property_provider_.get(), ids[i], name,
482 value);
483 }
484 #endif
485 }
486
487 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/ozone/evdev/input_device_factory_evdev.h ('k') | ui/events/ozone/evdev/input_device_factory_evdev_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698