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
3 // found in the LICENSE file.
5 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
7 #include <gestures/gestures.h>
8 #include <libevdev/libevdev.h>
15 #include "base/containers/hash_tables.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/files/file_util.h"
18 #include "base/logging.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_split.h"
21 #include "base/strings/string_tokenizer.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringize_macros.h"
24 #include "base/strings/stringprintf.h"
25 #include "ui/events/ozone/evdev/libgestures_glue/gesture_feedback.h"
26 #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h"
28 // GesturesProp implementation.
30 // Check the header file for its definition.
31 GesturesProp::GesturesProp(const std::string
& name
,
32 const PropertyType type
,
42 std::vector
<int> GesturesProp::GetIntValue() const {
44 return std::vector
<int>();
47 bool GesturesProp::SetIntValue(const std::vector
<int>& value
) {
52 std::vector
<int16_t> GesturesProp::GetShortValue() const {
54 return std::vector
<int16_t>();
57 bool GesturesProp::SetShortValue(const std::vector
<int16_t>& value
) {
62 std::vector
<bool> GesturesProp::GetBoolValue() const {
64 return std::vector
<bool>();
67 bool GesturesProp::SetBoolValue(const std::vector
<bool>& value
) {
72 std::string
GesturesProp::GetStringValue() const {
77 bool GesturesProp::SetStringValue(const std::string
& value
) {
82 std::vector
<double> GesturesProp::GetDoubleValue() const {
84 return std::vector
<double>();
87 bool GesturesProp::SetDoubleValue(const std::vector
<double>& value
) {
92 void GesturesProp::SetHandlers(GesturesPropGetHandler get
,
93 GesturesPropSetHandler set
,
100 void GesturesProp::OnGet() const {
101 // We don't have the X server now so there is currently nothing to do when
102 // the get handler returns true.
103 // TODO(sheckylin): Re-visit this if we use handlers that modifies the
109 void GesturesProp::OnSet() const {
110 // Call the property set handler if available.
115 const char** GesturesProp::GetStringWritebackPtr() const {
120 bool GesturesProp::IsAllocated() const {
125 // Type-templated GesturesProp.
126 template <typename T
>
127 class TypedGesturesProp
: public GesturesProp
{
129 TypedGesturesProp(const std::string
& name
,
130 const PropertyType type
,
133 : GesturesProp(name
, type
, count
),
135 is_read_only_(false),
136 is_allocated_(false) {
139 ~TypedGesturesProp() override
{
145 bool IsReadOnly() const override
{ return is_read_only_
; }
148 // Functions for setting/getting numerical properties.
150 // These two functions calls the set/get handler and should only be used in
151 // Get*Value/Set*Value functions.
152 template <typename U
>
153 std::vector
<U
> GetNumericalPropertyValue() const {
154 // Nothing should be modified so it is OK to call the get handler first.
156 return this->template GetNumericalValue
<U
>();
159 template <typename U
>
160 bool SetNumericalPropertyValue(const std::vector
<U
>& value
) {
161 // Set the value only if not read-only and the vector size matches.
163 // As per the legacy guideline, all read-only properties (created with NULL)
164 // can't be modified. If we want to change this in the future, re-think
165 // about the different cases here (e.g., should we allow setting an array
166 // value of different size?).
167 if (is_read_only_
|| value
.size() != count())
169 bool ret
= this->template SetNumericalValue(value
);
174 // Initialize a numerical property's value. Note that a (numerical) default
175 // property's value is always stored in double.
176 void InitializeNumericalProperty(const T
* init
,
177 const GesturesProp
* default_property
) {
178 if (IsDefaultPropertyUsable(default_property
)) {
179 DVLOG(2) << "Default property found. Using its value ...";
180 this->template SetNumericalValue(default_property
->GetDoubleValue());
182 // To work with the interface exposed by the gesture lib, we have no
183 // choice but to trust that the init array has sufficient size.
184 std::vector
<T
> temp(init
, init
+ count());
185 this->template SetNumericalValue(temp
);
192 // If the flag is on, it means the GesturesProp is created by passing a NULL
193 // data pointer to the creator functions. We define the property as a
194 // read-only one and that no value change will be allowed for it. Note that
195 // the flag is different from is_allocated in that StringProperty will always
196 // allocate no matter it is created with NULL or not.
200 // Initialize the object.
202 // If no external data pointer is passed, we have to create our own.
204 value_
= new T
[GesturesProp::count()];
205 is_read_only_
= true;
206 is_allocated_
= true;
210 // Low-level functions for setting/getting numerical properties.
211 template <typename U
>
212 std::vector
<U
> GetNumericalValue() const {
213 // We do type-casting because the numerical types may not totally match.
214 // For example, we store bool as GesturesPropBool to be compatible with the
215 // gesture library. Also, all parsed xorg-conf property values are stored
216 // as double because we can't identify their original type lexically.
217 // TODO(sheckylin): Handle value out-of-range (e.g., double to int).
218 std::vector
<U
> result(count());
219 for (size_t i
= 0; i
< count(); ++i
)
220 result
[i
] = static_cast<U
>(value_
[i
]);
224 template <typename U
>
225 bool SetNumericalValue(const std::vector
<U
>& value
) {
226 for (size_t i
= 0; i
< count(); ++i
)
227 value_
[i
] = static_cast<T
>(value
[i
]);
231 // Check if a default property usable for (numerical) initialization.
232 bool IsDefaultPropertyUsable(const GesturesProp
* default_property
) const {
233 // We currently assumed that we won't specify any array property in the
234 // configuration files. The code needs to be updated if the assumption
235 // becomes invalid in the future.
236 return (count() == 1 && default_property
&&
237 default_property
->type() != PropertyType::PT_STRING
);
241 bool IsAllocated() const override
{ return is_allocated_
; }
243 // If the flag is on, it means the memory that the data pointer points to is
244 // allocated here. We will need to free the memory by ourselves when the
245 // GesturesProp is destroyed.
249 class GesturesIntProp
: public TypedGesturesProp
<int> {
251 GesturesIntProp(const std::string
& name
,
255 const GesturesProp
* default_property
)
256 : TypedGesturesProp
<int>(name
, PropertyType::PT_INT
, count
, value
) {
257 InitializeNumericalProperty(init
, default_property
);
259 std::vector
<int> GetIntValue() const override
{
260 return this->template GetNumericalPropertyValue
<int>();
262 bool SetIntValue(const std::vector
<int>& value
) override
{
263 return this->template SetNumericalPropertyValue(value
);
267 class GesturesShortProp
: public TypedGesturesProp
<short> {
269 GesturesShortProp(const std::string
& name
,
273 const GesturesProp
* default_property
)
274 : TypedGesturesProp
<short>(name
, PropertyType::PT_SHORT
, count
, value
) {
275 InitializeNumericalProperty(init
, default_property
);
277 std::vector
<int16_t> GetShortValue() const override
{
278 return this->template GetNumericalPropertyValue
<int16_t>();
280 bool SetShortValue(const std::vector
<int16_t>& value
) override
{
281 return this->template SetNumericalPropertyValue(value
);
285 class GesturesBoolProp
: public TypedGesturesProp
<GesturesPropBool
> {
287 GesturesBoolProp(const std::string
& name
,
289 GesturesPropBool
* value
,
290 const GesturesPropBool
* init
,
291 const GesturesProp
* default_property
)
292 : TypedGesturesProp
<GesturesPropBool
>(name
,
293 PropertyType::PT_BOOL
,
296 InitializeNumericalProperty(init
, default_property
);
298 std::vector
<bool> GetBoolValue() const override
{
299 return this->template GetNumericalPropertyValue
<bool>();
301 bool SetBoolValue(const std::vector
<bool>& value
) override
{
302 return this->template SetNumericalPropertyValue(value
);
306 class GesturesDoubleProp
: public TypedGesturesProp
<double> {
308 GesturesDoubleProp(const std::string
& name
,
312 const GesturesProp
* default_property
)
313 : TypedGesturesProp
<double>(name
, PropertyType::PT_REAL
, count
, value
) {
314 InitializeNumericalProperty(init
, default_property
);
316 std::vector
<double> GetDoubleValue() const override
{
317 return this->template GetNumericalPropertyValue
<double>();
319 bool SetDoubleValue(const std::vector
<double>& value
) override
{
320 return this->template SetNumericalPropertyValue(value
);
324 class GesturesStringProp
: public TypedGesturesProp
<std::string
> {
326 // StringProperty's memory is always allocated on this side instead of
327 // externally in the gesture lib as the original one will be destroyed right
328 // after the constructor call (check the design of StringProperty). To do
329 // this, we call the TypedGesturesProp constructor with NULL pointer so that
330 // it always allocates.
331 GesturesStringProp(const std::string
& name
,
334 const GesturesProp
* default_property
)
335 : TypedGesturesProp
<std::string
>(name
, PropertyType::PT_STRING
, 1, NULL
),
337 InitializeStringProperty(value
, init
, default_property
);
339 std::string
GetStringValue() const override
{
343 bool SetStringValue(const std::string
& value
) override
{
348 // Write back the pointer in case it may change (e.g., string
351 *(write_back_
) = value_
->c_str();
357 // Initialize the object.
358 void InitializeStringProperty(const char** value
,
360 const GesturesProp
* default_property
) {
361 // Initialize the property value similar to the numerical types.
362 if (IsDefaultPropertyUsable(default_property
)) {
363 DVLOG(2) << "Default property found. Using its value ...";
364 *value_
= default_property
->GetStringValue();
369 // If the provided pointer is not NULL, replace its content
370 // (val_ of StringProperty) with the address of our allocated string.
371 // Note that we don't have to do this for the other data types as they will
372 // use the original data pointer if possible and it is unnecessary to do so
373 // if the pointer is NULL.
375 *value
= value_
->c_str();
377 // Set the read-only flag back to false.
378 is_read_only_
= false;
382 // Re-write the function with different criteria as we want string properties
384 bool IsDefaultPropertyUsable(const GesturesProp
* default_property
) const {
385 return (default_property
&&
386 default_property
->type() == PropertyType::PT_STRING
);
389 const char** GetStringWritebackPtr() const override
{ return write_back_
; }
391 // In some cases, we don't directly use the data pointer provided by the
392 // creators due to its limitation and instead use our own types (e.g., in
393 // the case of string). We thus need to store the write back pointer so that
394 // we can update the value in the gesture lib if the property value gets
396 const char** write_back_
;
399 // Anonymous namespace for utility functions and internal constants.
402 // The path that we will look for conf files.
403 const char kConfigurationFilePath
[] = "/etc/gesture";
405 // We support only match types that have already been used. One should change
406 // this if we start using new types in the future. Note that most unsupported
407 // match types are either useless in CrOS or inapplicable to the non-X
409 const char* kSupportedMatchTypes
[] = {"MatchProduct",
414 "MatchIsTouchscreen"};
415 const char* kUnsupportedMatchTypes
[] = {"MatchVendor",
425 // Special keywords for boolean values.
426 const char* kTrue
[] = {"on", "true", "yes"};
427 const char* kFalse
[] = {"off", "false", "no"};
429 // Check if a device falls into one device type category.
430 bool IsDeviceOfType(const ui::GesturePropertyProvider::DevicePtr device
,
431 const ui::EventDeviceType type
,
432 const GesturesProp
* device_mouse_property
,
433 const GesturesProp
* device_touchpad_property
) {
434 // Get the device type info from gesture properties if they are available.
435 // Otherwise, fallback to the libevdev device info.
436 bool is_mouse
= false, is_touchpad
= false;
437 EvdevClass evdev_class
= device
->info
.evdev_class
;
438 if (device_mouse_property
) {
439 is_mouse
= device_mouse_property
->GetBoolValue()[0];
441 is_mouse
= (evdev_class
== EvdevClassMouse
||
442 evdev_class
== EvdevClassMultitouchMouse
);
444 if (device_touchpad_property
) {
445 is_touchpad
= device_touchpad_property
->GetBoolValue()[0];
447 is_touchpad
= (evdev_class
== EvdevClassTouchpad
||
448 evdev_class
== EvdevClassTouchscreen
||
449 evdev_class
== EvdevClassMultitouchMouse
);
453 case ui::DT_KEYBOARD
:
454 return (evdev_class
== EvdevClassKeyboard
);
459 case ui::DT_TOUCHPAD
:
460 return (!is_mouse
) && is_touchpad
;
462 case ui::DT_TOUCHSCREEN
:
463 return (evdev_class
== EvdevClassTouchscreen
);
465 case ui::DT_MULTITOUCH
:
468 case ui::DT_MULTITOUCH_MOUSE
:
469 return is_mouse
&& is_touchpad
;
480 // Trick to get the device path from a file descriptor.
481 std::string
GetDeviceNodePath(
482 const ui::GesturePropertyProvider::DevicePtr device
) {
483 std::string proc_symlink
= "/proc/self/fd/" + base::IntToString(device
->fd
);
485 if (!base::ReadSymbolicLink(base::FilePath(proc_symlink
), &path
))
486 return std::string();
490 // Check if a match criteria is currently implemented. Note that we didn't
491 // implemented all of them as some are inapplicable in the non-X world.
492 bool IsMatchTypeSupported(const std::string
& match_type
) {
493 for (size_t i
= 0; i
< arraysize(kSupportedMatchTypes
); ++i
)
494 if (match_type
== kSupportedMatchTypes
[i
])
496 for (size_t i
= 0; i
< arraysize(kUnsupportedMatchTypes
); ++i
) {
497 if (match_type
== kUnsupportedMatchTypes
[i
]) {
498 LOG(ERROR
) << "Unsupported gestures input class match type: "
506 // Check if a match criteria is a device type one.
507 bool IsMatchDeviceType(const std::string
& match_type
) {
508 return base::StartsWith(match_type
, "MatchIs", base::CompareCase::SENSITIVE
);
511 // Parse a boolean value keyword (e.g., on/off, true/false).
512 int ParseBooleanKeyword(const std::string
& value
) {
513 for (size_t i
= 0; i
< arraysize(kTrue
); ++i
) {
514 if (base::LowerCaseEqualsASCII(value
, kTrue
[i
]))
517 for (size_t i
= 0; i
< arraysize(kFalse
); ++i
) {
518 if (base::LowerCaseEqualsASCII(value
, kFalse
[i
]))
524 // Log the value of an array property.
525 template <typename T
>
526 void LogArrayProperty(std::ostream
& os
, const std::vector
<T
>& value
) {
528 for (size_t i
= 0; i
< value
.size(); ++i
) {
536 // Property type logging function.
537 std::ostream
& operator<<(std::ostream
& out
,
538 const ui::GesturePropertyProvider::PropertyType type
) {
540 #define TYPE_CASE(TYPE) \
541 case (ui::GesturePropertyProvider::TYPE): \
548 TYPE_CASE(PT_STRING
);
558 // A relay function that dumps evdev log to a place that we have access to
559 // (the default directory is inaccessible without X11).
560 void DumpTouchEvdevDebugLog(void* data
) {
561 Event_Dump_Debug_Log_To(data
, ui::kTouchpadEvdevLogPath
);
566 // GesturesProp logging function.
567 std::ostream
& operator<<(std::ostream
& os
, const GesturesProp
& prop
) {
568 const GesturesProp
* property
= &prop
;
570 // Output the property content.
571 os
<< "\"" << property
->name() << "\", " << property
->type() << ", "
572 << property
->count() << ", (" << property
->IsAllocated() << ", "
573 << property
->IsReadOnly() << "), ";
575 // Only the string property has the write back pointer.
576 if (property
->type() == ui::GesturePropertyProvider::PT_STRING
)
577 os
<< property
->GetStringWritebackPtr();
581 // Output the property values.
583 switch (property
->type()) {
584 case ui::GesturePropertyProvider::PT_INT
:
585 LogArrayProperty(os
, property
->GetIntValue());
587 case ui::GesturePropertyProvider::PT_SHORT
:
588 LogArrayProperty(os
, property
->GetShortValue());
590 case ui::GesturePropertyProvider::PT_BOOL
:
591 LogArrayProperty(os
, property
->GetBoolValue());
593 case ui::GesturePropertyProvider::PT_STRING
:
594 os
<< "\"" << property
->GetStringValue() << "\"";
596 case ui::GesturePropertyProvider::PT_REAL
:
597 LogArrayProperty(os
, property
->GetDoubleValue());
600 LOG(ERROR
) << "Unknown gesture property type: " << property
->type();
610 // Mapping table from a property name to its corresponding GesturesProp
612 typedef base::hash_map
<std::string
, GesturesProp
*> PropertiesMap
;
613 typedef base::ScopedPtrHashMap
<std::string
, scoped_ptr
<GesturesProp
>>
616 // Struct holding properties of a device.
618 // Note that we can't define it in GesturePropertyProvider as a nested class
619 // because ScopedPtrHashMap will require us to expose the GestureProp's
620 // destructor so that it can instantiate the object. This is something we
622 struct GestureDevicePropertyData
{
623 GestureDevicePropertyData() {}
625 // Properties owned and being used by the device.
626 ScopedPropertiesMap properties
;
628 // Unowned default properties (owned by the configuration file). Their values
629 // will be applied when a property of the same name is created. These are
630 // usually only a small portion of all properties in use.
631 PropertiesMap default_properties
;
634 // Base class for device match criterias in conf files.
635 // Check the xorg-conf spec for more detailed information.
636 class MatchCriteria
{
638 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr
;
639 explicit MatchCriteria(const std::string
& arg
);
640 virtual ~MatchCriteria() {}
641 virtual bool Match(const DevicePtr device
) = 0;
644 std::vector
<std::string
> args_
;
647 // Match a device based on its evdev name string.
648 class MatchProduct
: public MatchCriteria
{
650 explicit MatchProduct(const std::string
& arg
);
651 ~MatchProduct() override
{}
652 bool Match(const DevicePtr device
) override
;
655 // Math a device based on its device node path.
656 class MatchDevicePath
: public MatchCriteria
{
658 explicit MatchDevicePath(const std::string
& arg
);
659 ~MatchDevicePath() override
{}
660 bool Match(const DevicePtr device
) override
;
663 // Math a USB device based on its USB vid and pid.
664 // Mostly used for external mice and touchpads.
665 class MatchUSBID
: public MatchCriteria
{
667 explicit MatchUSBID(const std::string
& arg
);
668 ~MatchUSBID() override
{}
669 bool Match(const DevicePtr device
) override
;
672 bool IsValidPattern(const std::string
& pattern
);
673 std::vector
<std::string
> vid_patterns_
;
674 std::vector
<std::string
> pid_patterns_
;
677 // Generic base class for device type math criteria.
678 class MatchDeviceType
: public MatchCriteria
{
680 explicit MatchDeviceType(const std::string
& arg
);
681 ~MatchDeviceType() override
{}
688 // Check if a device is a pointer device.
689 class MatchIsPointer
: public MatchDeviceType
{
691 explicit MatchIsPointer(const std::string
& arg
);
692 ~MatchIsPointer() override
{}
693 bool Match(const DevicePtr device
) override
;
696 // Check if a device is a touchpad.
697 class MatchIsTouchpad
: public MatchDeviceType
{
699 explicit MatchIsTouchpad(const std::string
& arg
);
700 ~MatchIsTouchpad() override
{}
701 bool Match(const DevicePtr device
) override
;
704 // Check if a device is a touchscreen.
705 class MatchIsTouchscreen
: public MatchDeviceType
{
707 explicit MatchIsTouchscreen(const std::string
& arg
);
708 ~MatchIsTouchscreen() override
{}
709 bool Match(const DevicePtr device
) override
;
712 // Struct for sections in xorg conf files.
713 struct ConfigurationSection
{
714 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr
;
715 ConfigurationSection() {}
716 bool Match(const DevicePtr device
);
717 std::string identifier
;
718 ScopedVector
<MatchCriteria
> criterias
;
719 ScopedVector
<GesturesProp
> properties
;
722 MatchCriteria::MatchCriteria(const std::string
& arg
) {
723 // TODO(sheckylin): Should we trim all tokens here?
724 args_
= base::SplitString(
725 arg
, "|", base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
727 LOG(ERROR
) << "Empty match pattern found, will evaluate to the default "
728 "value (true): \"" << arg
<< "\"";
732 MatchProduct::MatchProduct(const std::string
& arg
) : MatchCriteria(arg
) {
735 bool MatchProduct::Match(const DevicePtr device
) {
738 std::string
name(device
->info
.name
);
739 for (size_t i
= 0; i
< args_
.size(); ++i
)
740 if (name
.find(args_
[i
]) != std::string::npos
)
745 MatchDevicePath::MatchDevicePath(const std::string
& arg
) : MatchCriteria(arg
) {
748 bool MatchDevicePath::Match(const DevicePtr device
) {
752 // Check if the device path matches any pattern.
753 std::string path
= GetDeviceNodePath(device
);
756 for (size_t i
= 0; i
< args_
.size(); ++i
)
757 if (fnmatch(args_
[i
].c_str(), path
.c_str(), FNM_NOESCAPE
) == 0)
762 MatchUSBID::MatchUSBID(const std::string
& arg
) : MatchCriteria(arg
) {
763 // Check each pattern and split valid ones into vids and pids.
764 for (size_t i
= 0; i
< args_
.size(); ++i
) {
765 if (!IsValidPattern(args_
[i
])) {
766 LOG(ERROR
) << "Invalid USB ID: " << args_
[i
];
769 std::vector
<std::string
> tokens
;
770 base::SplitString(args_
[i
], ':', &tokens
);
771 vid_patterns_
.push_back(base::StringToLowerASCII(tokens
[0]));
772 pid_patterns_
.push_back(base::StringToLowerASCII(tokens
[1]));
774 if (vid_patterns_
.empty()) {
775 LOG(ERROR
) << "No valid USB ID pattern found, will be ignored: \"" << arg
780 bool MatchUSBID::Match(const DevicePtr device
) {
781 if (vid_patterns_
.empty())
783 std::string vid
= base::StringPrintf("%04x", device
->info
.id
.vendor
);
784 std::string pid
= base::StringPrintf("%04x", device
->info
.id
.product
);
785 for (size_t i
= 0; i
< vid_patterns_
.size(); ++i
) {
786 if (fnmatch(vid_patterns_
[i
].c_str(), vid
.c_str(), FNM_NOESCAPE
) == 0 &&
787 fnmatch(pid_patterns_
[i
].c_str(), pid
.c_str(), FNM_NOESCAPE
) == 0) {
794 bool MatchUSBID::IsValidPattern(const std::string
& pattern
) {
795 // Each USB id should be in the lsusb format, i.e., xxxx:xxxx. We choose to do
796 // a lazy check here: if the pattern contains wrong characters not in the hex
797 // number range, it won't be matched anyway.
798 int number_of_colons
= 0;
799 size_t pos_of_colon
= 0;
800 for (size_t i
= 0; i
< pattern
.size(); ++i
)
801 if (pattern
[i
] == ':')
802 ++number_of_colons
, pos_of_colon
= i
;
803 return (number_of_colons
== 1) && (pos_of_colon
!= 0) &&
804 (pos_of_colon
!= pattern
.size() - 1);
807 MatchDeviceType::MatchDeviceType(const std::string
& arg
)
808 : MatchCriteria(arg
), value_(true), is_valid_(false) {
809 // Default value of a match criteria is true.
811 args_
.push_back("on");
813 // We care only about the first argument.
814 int value
= ParseBooleanKeyword(args_
[0]);
821 << "No valid device class boolean keyword found, will be ignored: \""
826 MatchIsPointer::MatchIsPointer(const std::string
& arg
) : MatchDeviceType(arg
) {
829 bool MatchIsPointer::Match(const DevicePtr device
) {
832 return (value_
== (device
->info
.evdev_class
== EvdevClassMouse
||
833 device
->info
.evdev_class
== EvdevClassMultitouchMouse
));
836 MatchIsTouchpad::MatchIsTouchpad(const std::string
& arg
)
837 : MatchDeviceType(arg
) {
840 bool MatchIsTouchpad::Match(const DevicePtr device
) {
843 return (value_
== (device
->info
.evdev_class
== EvdevClassTouchpad
));
846 MatchIsTouchscreen::MatchIsTouchscreen(const std::string
& arg
)
847 : MatchDeviceType(arg
) {
850 bool MatchIsTouchscreen::Match(const DevicePtr device
) {
853 return (value_
== (device
->info
.evdev_class
== EvdevClassTouchscreen
));
856 bool ConfigurationSection::Match(DevicePtr device
) {
857 for (size_t i
= 0; i
< criterias
.size(); ++i
)
858 if (!criterias
[i
]->Match(device
))
863 } // namespace internal
865 GesturePropertyProvider::GesturePropertyProvider() {
866 LoadDeviceConfigurations();
869 GesturePropertyProvider::~GesturePropertyProvider() {
872 bool GesturePropertyProvider::GetDeviceIdsByType(
873 const EventDeviceType type
,
874 std::vector
<DeviceId
>* device_ids
) {
876 DeviceMap::const_iterator it
= device_map_
.begin();
877 for (; it
!= device_map_
.end(); ++it
) {
878 if (IsDeviceIdOfType(it
->first
, type
)) {
881 device_ids
->push_back(it
->first
);
887 bool GesturePropertyProvider::IsDeviceIdOfType(const DeviceId device_id
,
888 const EventDeviceType type
) {
889 DeviceMap::const_iterator it
= device_map_
.find(device_id
);
890 if (it
== device_map_
.end())
892 return IsDeviceOfType(it
->second
, type
,
893 GetProperty(device_id
, "Device Mouse"),
894 GetProperty(device_id
, "Device Touchpad"));
897 GesturesProp
* GesturePropertyProvider::GetProperty(const DeviceId device_id
,
898 const std::string
& name
) {
899 return FindProperty(device_id
, name
);
902 std::vector
<std::string
> GesturePropertyProvider::GetPropertyNamesById(
903 const DeviceId device_id
) {
904 internal::GestureDevicePropertyData
* device_data
=
905 device_data_map_
.get(device_id
);
907 return std::vector
<std::string
>();
909 // Dump all property names of the device.
910 std::vector
<std::string
> names
;
911 for (internal::ScopedPropertiesMap::const_iterator it
=
912 device_data
->properties
.begin();
913 it
!= device_data
->properties
.end(); ++it
)
914 names
.push_back(it
->first
);
918 std::string
GesturePropertyProvider::GetDeviceNameById(
919 const DeviceId device_id
) {
920 DeviceMap::const_iterator it
= device_map_
.find(device_id
);
921 if (it
== device_map_
.end())
922 return std::string();
923 return std::string(it
->second
->info
.name
);
926 void GesturePropertyProvider::RegisterDevice(const DeviceId id
,
927 const DevicePtr device
) {
928 DeviceMap::const_iterator it
= device_map_
.find(id
);
929 if (it
!= device_map_
.end())
932 // Setup data-structures.
933 device_map_
[id
] = device
;
934 device_data_map_
.set(id
,
935 scoped_ptr
<internal::GestureDevicePropertyData
>(
936 new internal::GestureDevicePropertyData
));
938 // Gather default property values for the device from the parsed conf files.
939 SetupDefaultProperties(id
, device
);
943 void GesturePropertyProvider::UnregisterDevice(const DeviceId id
) {
944 DeviceMap::const_iterator it
= device_map_
.find(id
);
945 if (it
== device_map_
.end())
947 device_data_map_
.erase(id
);
948 device_map_
.erase(it
);
951 void GesturePropertyProvider::AddProperty(const DeviceId device_id
,
952 const std::string
& name
,
953 GesturesProp
* property
) {
954 // The look-up should never fail because ideally a property can only be
955 // created with GesturesPropCreate* functions from the gesture lib side.
956 // Therefore, we simply return on failure.
957 internal::GestureDevicePropertyData
* device_data
=
958 device_data_map_
.get(device_id
);
960 device_data
->properties
.set(name
, scoped_ptr
<GesturesProp
>(property
));
963 void GesturePropertyProvider::DeleteProperty(const DeviceId device_id
,
964 const std::string
& name
) {
965 internal::GestureDevicePropertyData
* device_data
=
966 device_data_map_
.get(device_id
);
968 device_data
->properties
.erase(name
);
971 GesturesProp
* GesturePropertyProvider::FindProperty(const DeviceId device_id
,
972 const std::string
& name
) {
973 internal::GestureDevicePropertyData
* device_data
=
974 device_data_map_
.get(device_id
);
977 return device_data
->properties
.get(name
);
980 GesturesProp
* GesturePropertyProvider::GetDefaultProperty(
981 const DeviceId device_id
,
982 const std::string
& name
) {
983 internal::GestureDevicePropertyData
* device_data
=
984 device_data_map_
.get(device_id
);
987 internal::PropertiesMap::const_iterator ib
=
988 device_data
->default_properties
.find(name
);
989 if (ib
== device_data
->default_properties
.end())
994 void GesturePropertyProvider::LoadDeviceConfigurations() {
995 // Enumerate conf files and sort them lexicographically.
996 std::set
<base::FilePath
> files
;
997 base::FileEnumerator
file_enum(base::FilePath(kConfigurationFilePath
),
999 base::FileEnumerator::FILES
,
1001 for (base::FilePath path
= file_enum
.Next(); !path
.empty();
1002 path
= file_enum
.Next()) {
1005 DVLOG(2) << files
.size() << " conf files were found";
1007 // Parse conf files one-by-one.
1008 for (std::set
<base::FilePath
>::iterator file_iter
= files
.begin();
1009 file_iter
!= files
.end();
1011 DVLOG(2) << "Parsing conf file: " << (*file_iter
).value();
1012 std::string content
;
1013 if (!base::ReadFileToString(*file_iter
, &content
)) {
1014 LOG(ERROR
) << "Can't loading gestures conf file: "
1015 << (*file_iter
).value();
1018 ParseXorgConfFile(content
);
1022 void GesturePropertyProvider::ParseXorgConfFile(const std::string
& content
) {
1023 // To simplify the parsing work, we made some assumption about the conf file
1024 // format which doesn't exist in the original xorg-conf spec. Most important
1026 // 1. All keywords and names are now case-sensitive. Also, underscores are not
1028 // 2. Each entry takes up one and exactly one line in the file.
1029 // 3. No negation of the option value even if the option name is prefixed with
1030 // "No" as it may cause problems for option names that does start with "No"
1031 // (e.g., "Non-linearity").
1033 // Break the content into sections, lines and then pieces.
1034 // Sections are delimited by the "EndSection" keyword.
1035 // Lines are delimited by "\n".
1036 // Pieces are delimited by all white-spaces.
1037 std::vector
<std::string
> sections
;
1038 base::SplitStringUsingSubstr(content
, "EndSection", §ions
);
1039 for (size_t i
= 0; i
< sections
.size(); ++i
) {
1040 // Create a new configuration section.
1041 configurations_
.push_back(new internal::ConfigurationSection());
1042 internal::ConfigurationSection
* config
= configurations_
.back();
1044 // Break the section into lines.
1045 base::StringTokenizer
lines(sections
[i
], "\n");
1046 bool is_input_class_section
= true;
1047 bool has_checked_section_type
= false;
1048 while (is_input_class_section
&& lines
.GetNext()) {
1049 // Parse the line w.r.t. the xorg-conf format.
1050 std::string
line(lines
.token());
1052 // Skip empty lines.
1056 // Treat all whitespaces as delimiters.
1057 base::StringTokenizer
pieces(line
, base::kWhitespaceASCII
);
1058 pieces
.set_quote_chars("\"");
1059 bool is_parsing
= false;
1060 bool has_error
= false;
1061 bool next_is_section_type
= false;
1062 bool next_is_option_name
= false;
1063 bool next_is_option_value
= false;
1064 bool next_is_match_criteria
= false;
1065 bool next_is_identifier
= false;
1066 std::string match_type
, option_name
;
1067 while (pieces
.GetNext()) {
1068 std::string
piece(pieces
.token());
1070 // Skip empty pieces.
1074 // See if we are currently parsing an entry or are still looking for
1077 // Stop parsing the current line if the format is wrong.
1078 if (piece
.size() <= 2 || piece
[0] != '\"' ||
1079 piece
[piece
.size() - 1] != '\"') {
1080 LOG(ERROR
) << "Error parsing line: " << lines
.token();
1082 if (next_is_section_type
)
1083 is_input_class_section
= false;
1087 // Parse the arguments. Note that we don't break even if a whitespace
1088 // string is passed. It will just be handled in various ways based on
1091 base::TrimWhitespaceASCII(
1092 piece
.substr(1, piece
.size() - 2), base::TRIM_ALL
, &arg
);
1093 if (next_is_section_type
) {
1094 // We only care about InputClass sections.
1095 if (arg
!= "InputClass") {
1097 is_input_class_section
= false;
1099 DVLOG(2) << "New InputClass section found";
1100 has_checked_section_type
= true;
1103 } else if (next_is_identifier
) {
1104 DVLOG(2) << "Identifier: " << arg
;
1105 config
->identifier
= arg
;
1106 next_is_identifier
= false;
1108 } else if (next_is_option_name
) {
1109 // TODO(sheckylin): Support option "Ignore".
1111 next_is_option_value
= true;
1112 next_is_option_name
= false;
1113 } else if (next_is_option_value
) {
1114 GesturesProp
* property
= CreateDefaultProperty(option_name
, arg
);
1116 config
->properties
.push_back(property
);
1117 next_is_option_value
= false;
1119 } else if (next_is_match_criteria
) {
1120 // Skip all match types that are not supported.
1121 if (IsMatchTypeSupported(match_type
)) {
1122 internal::MatchCriteria
* criteria
=
1123 CreateMatchCriteria(match_type
, arg
);
1125 config
->criterias
.push_back(criteria
);
1127 next_is_match_criteria
= false;
1131 // If the section type hasn't been decided yet, look for it.
1132 // Otherwise, look for valid entries according to the spec.
1133 if (has_checked_section_type
) {
1134 if (piece
== "Driver") {
1135 // "Driver" field is meaningless for non-X11 setup.
1137 } else if (piece
== "Identifier") {
1139 next_is_identifier
= true;
1141 } else if (piece
== "Option") {
1143 next_is_option_name
= true;
1145 } else if (piece
.size() > 5 && piece
.compare(0, 5, "Match") == 0) {
1148 next_is_match_criteria
= true;
1151 } else if (piece
== "Section") {
1153 next_is_section_type
= true;
1157 // If none of the above is found, check if the current piece starts a
1159 if (piece
.empty() || piece
[0] != '#') {
1160 LOG(ERROR
) << "Error parsing line: " << lines
.token();
1167 // The value of a boolean option is skipped (default is true).
1168 if (!has_error
&& (next_is_option_value
|| next_is_match_criteria
)) {
1169 if (next_is_option_value
) {
1170 GesturesProp
* property
= CreateDefaultProperty(option_name
, "on");
1172 config
->properties
.push_back(property
);
1173 } else if (IsMatchTypeSupported(match_type
) &&
1174 IsMatchDeviceType(match_type
)) {
1175 internal::MatchCriteria
* criteria
=
1176 CreateMatchCriteria(match_type
, "on");
1178 config
->criterias
.push_back(criteria
);
1183 // Remove useless config sections.
1184 if (!is_input_class_section
||
1185 (config
->criterias
.empty() && config
->properties
.empty())) {
1186 configurations_
.pop_back();
1191 internal::MatchCriteria
* GesturePropertyProvider::CreateMatchCriteria(
1192 const std::string
& match_type
,
1193 const std::string
& arg
) {
1194 DVLOG(2) << "Creating match criteria: (" << match_type
<< ", " << arg
<< ")";
1195 if (match_type
== "MatchProduct")
1196 return new internal::MatchProduct(arg
);
1197 if (match_type
== "MatchDevicePath")
1198 return new internal::MatchDevicePath(arg
);
1199 if (match_type
== "MatchUSBID")
1200 return new internal::MatchUSBID(arg
);
1201 if (match_type
== "MatchIsPointer")
1202 return new internal::MatchIsPointer(arg
);
1203 if (match_type
== "MatchIsTouchpad")
1204 return new internal::MatchIsTouchpad(arg
);
1205 if (match_type
== "MatchIsTouchscreen")
1206 return new internal::MatchIsTouchscreen(arg
);
1211 GesturesProp
* GesturePropertyProvider::CreateDefaultProperty(
1212 const std::string
& name
,
1213 const std::string
& value
) {
1214 // Our parsing rule:
1215 // 1. No hex or oct number is accepted.
1216 // 2. All numbers will be stored as double.
1217 // 3. Array elements can be separated by both white-spaces or commas.
1218 // 4. A token is treated as numeric either if it is one of the special
1219 // keywords for boolean values (on, true, yes, off, false, no) or if
1220 // base::StringToDouble succeeds.
1221 // 5. The property is treated as numeric if and only if all of its elements
1222 // (if any) are numerics. Otherwise, it will be treated as a string.
1223 // 6. A string property will be trimmed before storing its value.
1224 DVLOG(2) << "Creating default property: (" << name
<< ", " << value
<< ")";
1226 // Parse elements one-by-one.
1227 std::string
delimiters(base::kWhitespaceASCII
);
1228 delimiters
.append(",");
1229 base::StringTokenizer
tokens(value
, delimiters
);
1230 bool is_all_numeric
= true;
1231 std::vector
<double> numbers
;
1232 while (tokens
.GetNext()) {
1233 // Skip empty tokens.
1234 std::string
token(tokens
.token());
1238 // Check if it is a boolean keyword.
1239 int bool_result
= ParseBooleanKeyword(token
);
1241 numbers
.push_back(bool_result
> 0);
1245 // Check if it is a number.
1247 bool success
= base::StringToDouble(token
, &real_result
);
1249 is_all_numeric
= false;
1252 numbers
.push_back(real_result
);
1255 // Create the GesturesProp. Array properties need to contain at least one
1256 // number and may contain numbers only.
1257 GesturesProp
* property
= NULL
;
1258 if (is_all_numeric
&& numbers
.size()) {
1259 property
= new GesturesDoubleProp(
1260 name
, numbers
.size(), NULL
, numbers
.data(), NULL
);
1262 property
= new GesturesStringProp(name
, NULL
, value
.c_str(), NULL
);
1265 DVLOG(2) << "Prop: " << *property
;
1266 // The function will always succeed for now but it may change later if we
1267 // specify some name or args as invalid.
1271 void GesturePropertyProvider::SetupDefaultProperties(const DeviceId device_id
,
1272 const DevicePtr device
) {
1273 DVLOG(2) << "Setting up default properties for (" << device
<< ", "
1274 << device_id
<< ", " << device
->info
.name
<< ")";
1276 // Go through all parsed sections.
1277 internal::PropertiesMap
& property_map
=
1278 device_data_map_
.get(device_id
)->default_properties
;
1279 for (size_t i
= 0; i
< configurations_
.size(); ++i
) {
1280 if (configurations_
[i
]->Match(device
)) {
1281 DVLOG(2) << "Conf section \"" << configurations_
[i
]->identifier
1283 for (size_t j
= 0; j
< configurations_
[i
]->properties
.size(); j
++) {
1284 GesturesProp
* property
= configurations_
[i
]->properties
[j
];
1285 // We can't use insert here because a property may be set for several
1286 // times along the way.
1287 property_map
[property
->name()] = property
;
1293 GesturesProp
* GesturesPropFunctionsWrapper::CreateInt(void* device_data
,
1298 return CreateProperty
<int, GesturesIntProp
>(
1299 device_data
, name
, value
, count
, init
);
1302 GesturesProp
* GesturesPropFunctionsWrapper::CreateShort(void* device_data
,
1306 const short* init
) {
1307 return CreateProperty
<short, GesturesShortProp
>(
1308 device_data
, name
, value
, count
, init
);
1311 GesturesProp
* GesturesPropFunctionsWrapper::CreateBool(
1314 GesturesPropBool
* value
,
1316 const GesturesPropBool
* init
) {
1317 return CreateProperty
<GesturesPropBool
, GesturesBoolProp
>(
1318 device_data
, name
, value
, count
, init
);
1321 GesturesProp
* GesturesPropFunctionsWrapper::CreateReal(void* device_data
,
1325 const double* init
) {
1326 return CreateProperty
<double, GesturesDoubleProp
>(
1327 device_data
, name
, value
, count
, init
);
1330 GesturesProp
* GesturesPropFunctionsWrapper::CreateString(void* device_data
,
1334 GesturesProp
* default_property
= NULL
;
1335 if (!PreCreateProperty(device_data
, name
, &default_property
))
1337 GesturesProp
* property
=
1338 new GesturesStringProp(name
, value
, init
, default_property
);
1340 PostCreateProperty(device_data
, name
, property
);
1344 void GesturesPropFunctionsWrapper::RegisterHandlers(
1346 GesturesProp
* property
,
1348 GesturesPropGetHandler get
,
1349 GesturesPropSetHandler set
) {
1351 if (!device_data
|| !property
)
1354 property
->SetHandlers(get
, set
, handler_data
);
1357 void GesturesPropFunctionsWrapper::Free(void* device_data
,
1358 GesturesProp
* property
) {
1361 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1363 // No need to manually delete the prop pointer as it is implicitly handled
1365 DVLOG(3) << "Freeing Property: \"" << property
->name() << "\"";
1366 provider
->DeleteProperty(GetDeviceId(device_data
), property
->name());
1369 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties(
1371 GestureDeviceProperties
* properties
) {
1374 GesturePropertyProvider::DevicePtr device
= GetDevicePointer(device_data
);
1376 /* Create Device Properties */
1378 // Read Only properties.
1380 device_data
, "Device Node", NULL
, GetDeviceNodePath(device
).c_str());
1381 short vid
= static_cast<short>(device
->info
.id
.vendor
);
1382 CreateShort(device_data
, "Device Vendor ID", NULL
, 1, &vid
);
1383 short pid
= static_cast<short>(device
->info
.id
.product
);
1384 CreateShort(device_data
, "Device Product ID", NULL
, 1, &pid
);
1386 // Useable trackpad area. If not configured in .conf file,
1387 // use x/y valuator min/max as reported by kernel driver.
1388 CreateIntSingle(device_data
,
1390 &properties
->area_left
,
1391 Event_Get_Left(device
));
1392 CreateIntSingle(device_data
,
1393 "Active Area Right",
1394 &properties
->area_right
,
1395 Event_Get_Right(device
));
1396 CreateIntSingle(device_data
,
1398 &properties
->area_top
,
1399 Event_Get_Top(device
));
1400 CreateIntSingle(device_data
,
1401 "Active Area Bottom",
1402 &properties
->area_bottom
,
1403 Event_Get_Bottom(device
));
1405 // Trackpad resolution (pixels/mm). If not configured in .conf file,
1406 // use x/y resolution as reported by kernel driver.
1407 CreateIntSingle(device_data
,
1408 "Vertical Resolution",
1410 Event_Get_Res_Y(device
));
1411 CreateIntSingle(device_data
,
1412 "Horizontal Resolution",
1414 Event_Get_Res_X(device
));
1416 // Trackpad orientation minimum/maximum. If not configured in .conf file,
1417 // use min/max as reported by kernel driver.
1418 CreateIntSingle(device_data
,
1419 "Orientation Minimum",
1420 &properties
->orientation_minimum
,
1421 Event_Get_Orientation_Minimum(device
));
1422 CreateIntSingle(device_data
,
1423 "Orientation Maximum",
1424 &properties
->orientation_maximum
,
1425 Event_Get_Orientation_Maximum(device
));
1427 // Log dump property. Will call Event_Dump_Debug_Log when its value is being
1429 GesturesProp
* dump_debug_log_prop
= CreateBoolSingle(
1430 device_data
, "Dump Debug Log", &properties
->dump_debug_log
, false);
1431 RegisterHandlers(device_data
, dump_debug_log_prop
, device
, NULL
,
1432 DumpTouchEvdevDebugLog
);
1434 // Whether to do the gesture recognition or just passing the multi-touch data
1436 CreateBoolSingle(device_data
,
1437 "Raw Touch Passthrough",
1438 &properties
->raw_passthrough
,
1443 void GesturesPropFunctionsWrapper::UnregisterDevice(void* device_data
) {
1444 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1445 provider
->UnregisterDevice(GetDeviceId(device_data
));
1448 template <typename T
, class PROPTYPE
>
1449 GesturesProp
* GesturesPropFunctionsWrapper::CreateProperty(void* device_data
,
1454 // Create the property. Use the default property value if possible.
1455 GesturesProp
* default_property
= NULL
;
1456 if (!PreCreateProperty(device_data
, name
, &default_property
))
1458 GesturesProp
* property
=
1459 new PROPTYPE(name
, count
, value
, init
, default_property
);
1461 // Start tracking the property in the provider.
1462 PostCreateProperty(device_data
, name
, property
);
1466 bool GesturesPropFunctionsWrapper::PreCreateProperty(
1469 GesturesProp
** default_property
) {
1470 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1471 GesturePropertyProvider::DeviceId device_id
= GetDeviceId(device_data
);
1473 // Register the device in the property provider if not yet.
1474 provider
->RegisterDevice(device_id
, GetDevicePointer(device_data
));
1476 // First, see if the GesturesProp already exists.
1477 DVLOG(3) << "Creating Property: \"" << name
<< "\"";
1478 GesturesProp
* property
= provider
->FindProperty(device_id
, name
);
1480 // If so, delete it as we can't reuse the data structure (newly-created
1481 // property may have different data type and count, which are fixed upon
1482 // creation via the template mechanism).
1484 LOG(WARNING
) << "Gesture property \"" << name
1485 << "\" re-created. This shouldn't happen at the normal usage.";
1486 Free(device_data
, property
);
1489 // Return the found default property from conf files (could be NULL).
1490 *default_property
= provider
->GetDefaultProperty(device_id
, name
);
1494 void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data
,
1496 GesturesProp
* property
) {
1497 // Add the property to the gesture property provider. The gesture property
1498 // provider will own it from now on.
1499 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1500 provider
->AddProperty(GetDeviceId(device_data
), name
, property
);
1502 // Log the creation.
1503 DVLOG(3) << "Created active prop: " << *property
;
1506 GesturesProp
* GesturesPropFunctionsWrapper::CreateIntSingle(void* device_data
,
1510 return CreateInt(device_data
, name
, value
, 1, &init
);
1513 GesturesProp
* GesturesPropFunctionsWrapper::CreateBoolSingle(
1516 GesturesPropBool
* value
,
1517 GesturesPropBool init
) {
1518 return CreateBool(device_data
, name
, value
, 1, &init
);
1521 GesturePropertyProvider
* GesturesPropFunctionsWrapper::GetPropertyProvider(
1522 void* device_data
) {
1523 return static_cast<GestureInterpreterLibevdevCros
*>(device_data
)
1524 ->property_provider();
1527 GesturePropertyProvider::DevicePtr
1528 GesturesPropFunctionsWrapper::GetDevicePointer(void* device_data
) {
1529 return static_cast<GestureInterpreterLibevdevCros
*>(device_data
)->evdev();
1532 GesturePropertyProvider::DeviceId
GesturesPropFunctionsWrapper::GetDeviceId(
1533 void* device_data
) {
1534 return static_cast<GestureInterpreterLibevdevCros
*>(device_data
)->id();
1537 /* Global GesturesPropProvider
1539 * Used by PropRegistry in GestureInterpreter to forward property value
1540 * creations from there.
1542 const GesturesPropProvider kGesturePropProvider
= {
1543 GesturesPropFunctionsWrapper::CreateInt
,
1544 GesturesPropFunctionsWrapper::CreateShort
,
1545 GesturesPropFunctionsWrapper::CreateBool
,
1546 GesturesPropFunctionsWrapper::CreateString
,
1547 GesturesPropFunctionsWrapper::CreateReal
,
1548 GesturesPropFunctionsWrapper::RegisterHandlers
,
1549 GesturesPropFunctionsWrapper::Free
};