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 #include <stddef.h>
10
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/files/scoped_file.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "base/time/time.h"
18 #include "base/trace_event/trace_event.h"
19 #include "ui/events/devices/device_data_manager.h"
20 #include "ui/events/devices/device_util_linux.h"
21 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
22 #include "ui/events/ozone/evdev/event_converter_evdev_impl.h"
23 #include "ui/events/ozone/evdev/event_device_info.h"
24 #include "ui/events/ozone/evdev/gamepad_event_converter_evdev.h"
25 #include "ui/events/ozone/evdev/stylus_button_event_converter_evdev.h"
26 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h"
27 #include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
28 #include "ui/events/ozone/gamepad/gamepad_provider_ozone.h"
29
30 #if defined(USE_EVDEV_GESTURES)
31 #include "ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
32 #include "ui/events/ozone/evdev/libgestures_glue/gesture_feedback.h"
33 #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h"
34 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
35 #endif
36
37 #ifndef EVIOCSCLOCKID
38 #define EVIOCSCLOCKID _IOW('E', 0xa0, int)
39 #endif
40
41 namespace ui {
42
43 namespace {
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.
53 DeviceEventDispatcherEvdev* dispatcher;
54
55 // State shared between devices.
56 CursorDelegateEvdev* cursor;
57 #if defined(USE_EVDEV_GESTURES)
58 GesturePropertyProvider* gesture_property_provider;
59 #endif
60 SharedPalmDetectionFilterState* shared_palm_state;
61 };
62
63 #if defined(USE_EVDEV_GESTURES)
SetGestureIntProperty(GesturePropertyProvider * provider,int id,const std::string & name,int value)64 void SetGestureIntProperty(GesturePropertyProvider* provider,
65 int id,
66 const std::string& name,
67 int value) {
68 GesturesProp* property = provider->GetProperty(id, name);
69 if (property) {
70 std::vector<int> values(1, value);
71 property->SetIntValue(values);
72 }
73 }
74
SetGestureBoolProperty(GesturePropertyProvider * provider,int id,const std::string & name,bool value)75 void SetGestureBoolProperty(GesturePropertyProvider* provider,
76 int id,
77 const std::string& name,
78 bool value) {
79 GesturesProp* property = provider->GetProperty(id, name);
80 if (property) {
81 std::vector<bool> values(1, value);
82 property->SetBoolValue(values);
83 }
84 }
85
86 #endif
87
CreateConverter(const OpenInputDeviceParams & params,base::ScopedFD fd,const EventDeviceInfo & devinfo)88 std::unique_ptr<EventConverterEvdev> CreateConverter(
89 const OpenInputDeviceParams& params,
90 base::ScopedFD fd,
91 const EventDeviceInfo& devinfo) {
92 #if defined(USE_EVDEV_GESTURES)
93 // Touchpad or mouse: use gestures library.
94 // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent
95 if (devinfo.HasTouchpad() || devinfo.HasMouse()) {
96 std::unique_ptr<GestureInterpreterLibevdevCros> gesture_interp =
97 std::make_unique<GestureInterpreterLibevdevCros>(
98 params.id, params.cursor, params.gesture_property_provider,
99 params.dispatcher);
100 return std::make_unique<EventReaderLibevdevCros>(std::move(fd), params.path,
101 params.id, devinfo,
102 std::move(gesture_interp));
103 }
104 #endif
105
106 // Touchscreen: use TouchEventConverterEvdev.
107 if (devinfo.HasTouchscreen()) {
108 std::unique_ptr<TouchEventConverterEvdev> converter(
109 new TouchEventConverterEvdev(std::move(fd), params.path, params.id,
110 devinfo, params.shared_palm_state,
111 params.dispatcher));
112 converter->Initialize(devinfo);
113 return std::move(converter);
114 }
115
116 // Graphics tablet
117 if (devinfo.HasTablet()) {
118 return base::WrapUnique<EventConverterEvdev>(new TabletEventConverterEvdev(
119 std::move(fd), params.path, params.id, params.cursor, devinfo,
120 params.dispatcher));
121 }
122
123 if (devinfo.HasGamepad()) {
124 return base::WrapUnique<EventConverterEvdev>(new GamepadEventConverterEvdev(
125 std::move(fd), params.path, params.id, devinfo, params.dispatcher));
126 }
127
128 if (devinfo.IsStylusButtonDevice()) {
129 return base::WrapUnique<EventConverterEvdev>(
130 new StylusButtonEventConverterEvdev(
131 std::move(fd), params.path, params.id, devinfo, params.dispatcher));
132 }
133
134 // Everything else: use EventConverterEvdevImpl.
135 return base::WrapUnique<EventConverterEvdevImpl>(
136 new EventConverterEvdevImpl(std::move(fd), params.path, params.id,
137 devinfo, params.cursor, params.dispatcher));
138 }
139
140 // Open an input device and construct an EventConverterEvdev.
OpenInputDevice(const OpenInputDeviceParams & params)141 std::unique_ptr<EventConverterEvdev> OpenInputDevice(
142 const OpenInputDeviceParams& params) {
143 const base::FilePath& path = params.path;
144 TRACE_EVENT1("evdev", "OpenInputDevice", "path", path.value());
145
146 base::ScopedFD fd(open(path.value().c_str(), O_RDWR | O_NONBLOCK));
147 if (fd.get() < 0) {
148 PLOG(ERROR) << "Cannot open " << path.value();
149 return nullptr;
150 }
151
152 // Use monotonic timestamps for events. The touch code in particular
153 // expects event timestamps to correlate to the monotonic clock
154 // (base::TimeTicks).
155 unsigned int clk = CLOCK_MONOTONIC;
156 if (ioctl(fd.get(), EVIOCSCLOCKID, &clk))
157 PLOG(ERROR) << "failed to set CLOCK_MONOTONIC";
158
159 EventDeviceInfo devinfo;
160 if (!devinfo.Initialize(fd.get(), path)) {
161 LOG(ERROR) << "Failed to get device information for " << path.value();
162 return nullptr;
163 }
164
165 return CreateConverter(params, std::move(fd), devinfo);
166 }
167
IsUncategorizedDevice(const EventConverterEvdev & converter)168 bool IsUncategorizedDevice(const EventConverterEvdev& converter) {
169 return !converter.HasTouchscreen() && !converter.HasKeyboard() &&
170 !converter.HasMouse() && !converter.HasTouchpad() &&
171 !converter.HasGamepad();
172 }
173
174 } // namespace
175
InputDeviceFactoryEvdev(std::unique_ptr<DeviceEventDispatcherEvdev> dispatcher,CursorDelegateEvdev * cursor)176 InputDeviceFactoryEvdev::InputDeviceFactoryEvdev(
177 std::unique_ptr<DeviceEventDispatcherEvdev> dispatcher,
178 CursorDelegateEvdev* cursor)
179 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
180 cursor_(cursor),
181 shared_palm_state_(new SharedPalmDetectionFilterState),
182 #if defined(USE_EVDEV_GESTURES)
183 gesture_property_provider_(new GesturePropertyProvider),
184 #endif
185 dispatcher_(std::move(dispatcher)) {
186 }
187
~InputDeviceFactoryEvdev()188 InputDeviceFactoryEvdev::~InputDeviceFactoryEvdev() {
189 }
190
AddInputDevice(int id,const base::FilePath & path)191 void InputDeviceFactoryEvdev::AddInputDevice(int id,
192 const base::FilePath& path) {
193 OpenInputDeviceParams params;
194 params.id = id;
195 params.path = path;
196 params.cursor = cursor_;
197 params.dispatcher = dispatcher_.get();
198 params.shared_palm_state = shared_palm_state_.get();
199
200 #if defined(USE_EVDEV_GESTURES)
201 params.gesture_property_provider = gesture_property_provider_.get();
202 #endif
203
204 std::unique_ptr<EventConverterEvdev> converter = OpenInputDevice(params);
205
206 base::ThreadTaskRunnerHandle::Get()->PostTask(
207 FROM_HERE,
208 base::BindOnce(&InputDeviceFactoryEvdev::AttachInputDevice,
209 weak_ptr_factory_.GetWeakPtr(), std::move(converter)));
210
211 ++pending_device_changes_;
212 }
213
RemoveInputDevice(const base::FilePath & path)214 void InputDeviceFactoryEvdev::RemoveInputDevice(const base::FilePath& path) {
215 DetachInputDevice(path);
216 }
217
OnStartupScanComplete()218 void InputDeviceFactoryEvdev::OnStartupScanComplete() {
219 startup_devices_enumerated_ = true;
220 NotifyDevicesUpdated();
221 }
222
AttachInputDevice(std::unique_ptr<EventConverterEvdev> converter)223 void InputDeviceFactoryEvdev::AttachInputDevice(
224 std::unique_ptr<EventConverterEvdev> converter) {
225 if (converter.get()) {
226 const base::FilePath& path = converter->path();
227
228 TRACE_EVENT1("evdev", "AttachInputDevice", "path", path.value());
229 DCHECK(task_runner_->RunsTasksInCurrentSequence());
230
231 // If we have an existing device, detach it. We don't want two
232 // devices with the same name open at the same time.
233 if (converters_[path])
234 DetachInputDevice(path);
235
236 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
237 converter->HasPen()) {
238 converter->SetPalmSuppressionCallback(
239 base::BindRepeating(&InputDeviceFactoryEvdev::EnablePalmSuppression,
240 base::Unretained(this)));
241 }
242
243 // Add initialized device to map.
244 converters_[path] = std::move(converter);
245 converters_[path]->Start();
246 UpdateDirtyFlags(converters_[path].get());
247
248 // Sync settings to new device.
249 ApplyInputDeviceSettings();
250 ApplyCapsLockLed();
251 }
252
253 --pending_device_changes_;
254 NotifyDevicesUpdated();
255 }
256
DetachInputDevice(const base::FilePath & path)257 void InputDeviceFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
258 TRACE_EVENT1("evdev", "DetachInputDevice", "path", path.value());
259 DCHECK(task_runner_->RunsTasksInCurrentSequence());
260
261 // Remove device from map.
262 std::unique_ptr<EventConverterEvdev> converter = std::move(converters_[path]);
263 converters_.erase(path);
264
265 if (converter) {
266 // Disable the device (to release keys/buttons/etc).
267 converter->SetEnabled(false);
268
269 // Cancel libevent notifications from this converter.
270 converter->Stop();
271
272 UpdateDirtyFlags(converter.get());
273 NotifyDevicesUpdated();
274 }
275 }
276
SetCapsLockLed(bool enabled)277 void InputDeviceFactoryEvdev::SetCapsLockLed(bool enabled) {
278 caps_lock_led_enabled_ = enabled;
279 ApplyCapsLockLed();
280 }
281
UpdateInputDeviceSettings(const InputDeviceSettingsEvdev & settings)282 void InputDeviceFactoryEvdev::UpdateInputDeviceSettings(
283 const InputDeviceSettingsEvdev& settings) {
284 input_device_settings_ = settings;
285 ApplyInputDeviceSettings();
286 }
287
GetTouchDeviceStatus(InputController::GetTouchDeviceStatusReply reply)288 void InputDeviceFactoryEvdev::GetTouchDeviceStatus(
289 InputController::GetTouchDeviceStatusReply reply) {
290 std::string status;
291 #if defined(USE_EVDEV_GESTURES)
292 DumpTouchDeviceStatus(gesture_property_provider_.get(), &status);
293 #endif
294 std::move(reply).Run(status);
295 }
296
GetTouchEventLog(const base::FilePath & out_dir,InputController::GetTouchEventLogReply reply)297 void InputDeviceFactoryEvdev::GetTouchEventLog(
298 const base::FilePath& out_dir,
299 InputController::GetTouchEventLogReply reply) {
300 #if defined(USE_EVDEV_GESTURES)
301 DumpTouchEventLog(converters_, gesture_property_provider_.get(), out_dir,
302 std::move(reply));
303 #else
304 std::move(reply).Run(std::vector<base::FilePath>());
305 #endif
306 }
307
GetGesturePropertiesService(mojo::PendingReceiver<ozone::mojom::GesturePropertiesService> receiver)308 void InputDeviceFactoryEvdev::GetGesturePropertiesService(
309 mojo::PendingReceiver<ozone::mojom::GesturePropertiesService> receiver) {
310 #if defined(USE_EVDEV_GESTURES)
311 gesture_properties_service_ = std::make_unique<GesturePropertiesService>(
312 gesture_property_provider_.get(), std::move(receiver));
313 #endif
314 }
315
GetWeakPtr()316 base::WeakPtr<InputDeviceFactoryEvdev> InputDeviceFactoryEvdev::GetWeakPtr() {
317 return weak_ptr_factory_.GetWeakPtr();
318 }
319
ApplyInputDeviceSettings()320 void InputDeviceFactoryEvdev::ApplyInputDeviceSettings() {
321 TRACE_EVENT0("evdev", "ApplyInputDeviceSettings");
322
323 SetIntPropertyForOneType(DT_TOUCHPAD, "Pointer Sensitivity",
324 input_device_settings_.touchpad_sensitivity);
325 SetIntPropertyForOneType(DT_TOUCHPAD, "Scroll Sensitivity",
326 input_device_settings_.touchpad_scroll_sensitivity);
327 SetBoolPropertyForOneType(
328 DT_TOUCHPAD, "Pointer Acceleration",
329 input_device_settings_.touchpad_acceleration_enabled);
330 SetBoolPropertyForOneType(
331 DT_TOUCHPAD, "Scroll Acceleration",
332 input_device_settings_.touchpad_scroll_acceleration_enabled);
333
334 SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Enable",
335 input_device_settings_.tap_to_click_enabled);
336 SetBoolPropertyForOneType(DT_TOUCHPAD, "T5R2 Three Finger Click Enable",
337 input_device_settings_.three_finger_click_enabled);
338 SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Drag Enable",
339 input_device_settings_.tap_dragging_enabled);
340
341 SetBoolPropertyForOneType(DT_MULTITOUCH, "Australian Scrolling",
342 input_device_settings_.natural_scroll_enabled);
343
344 SetIntPropertyForOneType(DT_MOUSE, "Pointer Sensitivity",
345 input_device_settings_.mouse_sensitivity);
346 SetIntPropertyForOneType(DT_MOUSE, "Mouse Scroll Sensitivity",
347 input_device_settings_.mouse_scroll_sensitivity);
348 SetBoolPropertyForOneType(DT_MOUSE, "Pointer Acceleration",
349 input_device_settings_.mouse_acceleration_enabled);
350 SetBoolPropertyForOneType(
351 DT_MOUSE, "Mouse Scroll Acceleration",
352 input_device_settings_.mouse_scroll_acceleration_enabled);
353 SetBoolPropertyForOneType(
354 DT_MOUSE, "Mouse Reverse Scrolling",
355 input_device_settings_.mouse_reverse_scroll_enabled);
356
357 SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Paused",
358 input_device_settings_.tap_to_click_paused);
359
360 for (const auto& it : converters_) {
361 EventConverterEvdev* converter = it.second.get();
362
363 bool should_be_enabled = IsDeviceEnabled(converter);
364 bool was_enabled = converter->IsEnabled();
365 if (should_be_enabled != was_enabled) {
366 converter->SetEnabled(should_be_enabled);
367
368 // The device was activated/deactivated we need to notify so
369 // Interactions MQs can be updated.
370 UpdateDirtyFlags(converter);
371 }
372
373 if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
374 converter->HasKeyboard()) {
375 converter->SetKeyFilter(
376 input_device_settings_.enable_internal_keyboard_filter,
377 input_device_settings_.internal_keyboard_allowed_keys);
378 }
379
380 converter->SetTouchEventLoggingEnabled(
381 input_device_settings_.touch_event_logging_enabled);
382 }
383
384 NotifyDevicesUpdated();
385 }
386
ApplyCapsLockLed()387 void InputDeviceFactoryEvdev::ApplyCapsLockLed() {
388 for (const auto& it : converters_) {
389 EventConverterEvdev* converter = it.second.get();
390 converter->SetCapsLockLed(caps_lock_led_enabled_);
391 }
392 }
393
IsDeviceEnabled(const EventConverterEvdev * converter)394 bool InputDeviceFactoryEvdev::IsDeviceEnabled(
395 const EventConverterEvdev* converter) {
396 if (!input_device_settings_.enable_internal_touchpad &&
397 converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
398 converter->HasTouchpad())
399 return false;
400
401 if (!input_device_settings_.enable_touch_screens &&
402 converter->HasTouchscreen())
403 return false;
404
405 if (palm_suppression_enabled_ &&
406 converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
407 converter->HasTouchscreen() && !converter->HasPen())
408 return false;
409
410 return input_device_settings_.enable_devices;
411 }
412
UpdateDirtyFlags(const EventConverterEvdev * converter)413 void InputDeviceFactoryEvdev::UpdateDirtyFlags(
414 const EventConverterEvdev* converter) {
415 if (converter->HasTouchscreen())
416 touchscreen_list_dirty_ = true;
417
418 if (converter->HasKeyboard())
419 keyboard_list_dirty_ = true;
420
421 if (converter->HasMouse())
422 mouse_list_dirty_ = true;
423
424 if (converter->HasTouchpad())
425 touchpad_list_dirty_ = true;
426
427 if (converter->HasGamepad())
428 gamepad_list_dirty_ = true;
429
430 if (IsUncategorizedDevice(*converter))
431 uncategorized_list_dirty_ = true;
432 }
433
NotifyDevicesUpdated()434 void InputDeviceFactoryEvdev::NotifyDevicesUpdated() {
435 if (!startup_devices_enumerated_ || pending_device_changes_)
436 return; // No update until full scan done and no pending operations.
437 if (touchscreen_list_dirty_)
438 NotifyTouchscreensUpdated();
439 if (keyboard_list_dirty_)
440 NotifyKeyboardsUpdated();
441 if (mouse_list_dirty_)
442 NotifyMouseDevicesUpdated();
443 if (touchpad_list_dirty_)
444 NotifyTouchpadDevicesUpdated();
445 if (gamepad_list_dirty_)
446 NotifyGamepadDevicesUpdated();
447 if (uncategorized_list_dirty_)
448 NotifyUncategorizedDevicesUpdated();
449 if (!startup_devices_opened_) {
450 dispatcher_->DispatchDeviceListsComplete();
451 startup_devices_opened_ = true;
452 }
453 touchscreen_list_dirty_ = false;
454 keyboard_list_dirty_ = false;
455 mouse_list_dirty_ = false;
456 touchpad_list_dirty_ = false;
457 gamepad_list_dirty_ = false;
458 uncategorized_list_dirty_ = false;
459 }
460
NotifyTouchscreensUpdated()461 void InputDeviceFactoryEvdev::NotifyTouchscreensUpdated() {
462 std::vector<TouchscreenDevice> touchscreens;
463 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
464 if (it->second->HasTouchscreen()) {
465 touchscreens.emplace_back(
466 it->second->input_device(), it->second->GetTouchscreenSize(),
467 it->second->GetTouchPoints(), it->second->HasPen());
468 }
469 }
470
471 dispatcher_->DispatchTouchscreenDevicesUpdated(touchscreens);
472 }
473
NotifyKeyboardsUpdated()474 void InputDeviceFactoryEvdev::NotifyKeyboardsUpdated() {
475 std::vector<InputDevice> keyboards;
476 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
477 if (it->second->HasKeyboard()) {
478 keyboards.push_back(InputDevice(it->second->input_device()));
479 }
480 }
481
482 dispatcher_->DispatchKeyboardDevicesUpdated(keyboards);
483 }
484
NotifyMouseDevicesUpdated()485 void InputDeviceFactoryEvdev::NotifyMouseDevicesUpdated() {
486 std::vector<InputDevice> mice;
487 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
488 if (it->second->HasMouse()) {
489 mice.push_back(it->second->input_device());
490 }
491 }
492
493 dispatcher_->DispatchMouseDevicesUpdated(mice);
494 }
495
NotifyTouchpadDevicesUpdated()496 void InputDeviceFactoryEvdev::NotifyTouchpadDevicesUpdated() {
497 std::vector<InputDevice> touchpads;
498 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
499 if (it->second->HasTouchpad()) {
500 touchpads.push_back(it->second->input_device());
501 }
502 }
503
504 dispatcher_->DispatchTouchpadDevicesUpdated(touchpads);
505 }
506
NotifyGamepadDevicesUpdated()507 void InputDeviceFactoryEvdev::NotifyGamepadDevicesUpdated() {
508 std::vector<GamepadDevice> gamepads;
509 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
510 if (it->second->HasGamepad()) {
511 gamepads.emplace_back(it->second->input_device(),
512 it->second->GetGamepadAxes());
513 }
514 }
515
516 dispatcher_->DispatchGamepadDevicesUpdated(gamepads);
517 }
518
NotifyUncategorizedDevicesUpdated()519 void InputDeviceFactoryEvdev::NotifyUncategorizedDevicesUpdated() {
520 std::vector<InputDevice> uncategorized_devices;
521 for (auto it = converters_.begin(); it != converters_.end(); ++it) {
522 if (IsUncategorizedDevice(*(it->second)))
523 uncategorized_devices.push_back(it->second->input_device());
524 }
525
526 dispatcher_->DispatchUncategorizedDevicesUpdated(uncategorized_devices);
527 }
528
SetIntPropertyForOneType(const EventDeviceType type,const std::string & name,int value)529 void InputDeviceFactoryEvdev::SetIntPropertyForOneType(
530 const EventDeviceType type,
531 const std::string& name,
532 int value) {
533 #if defined(USE_EVDEV_GESTURES)
534 std::vector<int> ids;
535 gesture_property_provider_->GetDeviceIdsByType(type, &ids);
536 for (size_t i = 0; i < ids.size(); ++i) {
537 SetGestureIntProperty(gesture_property_provider_.get(), ids[i], name,
538 value);
539 }
540 #endif
541 // In the future, we may add property setting codes for other non-gesture
542 // devices. One example would be keyboard settings.
543 // TODO(sheckylin): See http://crbug.com/398518 for example.
544 }
545
SetBoolPropertyForOneType(const EventDeviceType type,const std::string & name,bool value)546 void InputDeviceFactoryEvdev::SetBoolPropertyForOneType(
547 const EventDeviceType type,
548 const std::string& name,
549 bool value) {
550 #if defined(USE_EVDEV_GESTURES)
551 std::vector<int> ids;
552 gesture_property_provider_->GetDeviceIdsByType(type, &ids);
553 for (size_t i = 0; i < ids.size(); ++i) {
554 SetGestureBoolProperty(gesture_property_provider_.get(), ids[i], name,
555 value);
556 }
557 #endif
558 }
559
EnablePalmSuppression(bool enabled)560 void InputDeviceFactoryEvdev::EnablePalmSuppression(bool enabled) {
561 if (enabled == palm_suppression_enabled_)
562 return;
563 palm_suppression_enabled_ = enabled;
564
565 // This function can be called while disabling pen devices, so don't disable
566 // inline here.
567 base::ThreadTaskRunnerHandle::Get()->PostTask(
568 FROM_HERE, base::BindOnce(&InputDeviceFactoryEvdev::EnableDevices,
569 weak_ptr_factory_.GetWeakPtr()));
570 }
571
EnableDevices()572 void InputDeviceFactoryEvdev::EnableDevices() {
573 // TODO(spang): Fix the UI to not dismiss menus when we use
574 // ApplyInputDeviceSettings() instead of this function.
575 for (const auto& it : converters_)
576 it.second->SetEnabled(IsDeviceEnabled(it.second.get()));
577 }
578
579 } // namespace ui
580