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