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 StartsWithASCII(match_type
, "MatchIs", true);
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 (LowerCaseEqualsASCII(value
, kTrue
[i
]))
516 for (size_t i
= 0; i
< arraysize(kFalse
); ++i
)
517 if (LowerCaseEqualsASCII(value
, kFalse
[i
]))
522 // Log the value of an array property.
523 template <typename T
>
524 void LogArrayProperty(std::ostream
& os
, const std::vector
<T
>& value
) {
526 for (size_t i
= 0; i
< value
.size(); ++i
) {
534 // Property type logging function.
535 std::ostream
& operator<<(std::ostream
& out
,
536 const ui::GesturePropertyProvider::PropertyType type
) {
538 #define TYPE_CASE(TYPE) \
539 case (ui::GesturePropertyProvider::TYPE): \
546 TYPE_CASE(PT_STRING
);
556 // A relay function that dumps evdev log to a place that we have access to
557 // (the default directory is inaccessible without X11).
558 void DumpTouchEvdevDebugLog(void* data
) {
559 Event_Dump_Debug_Log_To(data
, ui::kTouchpadEvdevLogPath
);
564 // GesturesProp logging function.
565 std::ostream
& operator<<(std::ostream
& os
, const GesturesProp
& prop
) {
566 const GesturesProp
* property
= &prop
;
568 // Output the property content.
569 os
<< "\"" << property
->name() << "\", " << property
->type() << ", "
570 << property
->count() << ", (" << property
->IsAllocated() << ", "
571 << property
->IsReadOnly() << "), ";
573 // Only the string property has the write back pointer.
574 if (property
->type() == ui::GesturePropertyProvider::PT_STRING
)
575 os
<< property
->GetStringWritebackPtr();
579 // Output the property values.
581 switch (property
->type()) {
582 case ui::GesturePropertyProvider::PT_INT
:
583 LogArrayProperty(os
, property
->GetIntValue());
585 case ui::GesturePropertyProvider::PT_SHORT
:
586 LogArrayProperty(os
, property
->GetShortValue());
588 case ui::GesturePropertyProvider::PT_BOOL
:
589 LogArrayProperty(os
, property
->GetBoolValue());
591 case ui::GesturePropertyProvider::PT_STRING
:
592 os
<< "\"" << property
->GetStringValue() << "\"";
594 case ui::GesturePropertyProvider::PT_REAL
:
595 LogArrayProperty(os
, property
->GetDoubleValue());
598 LOG(ERROR
) << "Unknown gesture property type: " << property
->type();
608 // Mapping table from a property name to its corresponding GesturesProp
610 typedef base::hash_map
<std::string
, GesturesProp
*> PropertiesMap
;
611 typedef base::ScopedPtrHashMap
<std::string
, scoped_ptr
<GesturesProp
>>
614 // Struct holding properties of a device.
616 // Note that we can't define it in GesturePropertyProvider as a nested class
617 // because ScopedPtrHashMap will require us to expose the GestureProp's
618 // destructor so that it can instantiate the object. This is something we
620 struct GestureDevicePropertyData
{
621 GestureDevicePropertyData() {}
623 // Properties owned and being used by the device.
624 ScopedPropertiesMap properties
;
626 // Unowned default properties (owned by the configuration file). Their values
627 // will be applied when a property of the same name is created. These are
628 // usually only a small portion of all properties in use.
629 PropertiesMap default_properties
;
632 // Base class for device match criterias in conf files.
633 // Check the xorg-conf spec for more detailed information.
634 class MatchCriteria
{
636 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr
;
637 explicit MatchCriteria(const std::string
& arg
);
638 virtual ~MatchCriteria() {}
639 virtual bool Match(const DevicePtr device
) = 0;
642 std::vector
<std::string
> args_
;
645 // Match a device based on its evdev name string.
646 class MatchProduct
: public MatchCriteria
{
648 explicit MatchProduct(const std::string
& arg
);
649 ~MatchProduct() override
{}
650 bool Match(const DevicePtr device
) override
;
653 // Math a device based on its device node path.
654 class MatchDevicePath
: public MatchCriteria
{
656 explicit MatchDevicePath(const std::string
& arg
);
657 ~MatchDevicePath() override
{}
658 bool Match(const DevicePtr device
) override
;
661 // Math a USB device based on its USB vid and pid.
662 // Mostly used for external mice and touchpads.
663 class MatchUSBID
: public MatchCriteria
{
665 explicit MatchUSBID(const std::string
& arg
);
666 ~MatchUSBID() override
{}
667 bool Match(const DevicePtr device
) override
;
670 bool IsValidPattern(const std::string
& pattern
);
671 std::vector
<std::string
> vid_patterns_
;
672 std::vector
<std::string
> pid_patterns_
;
675 // Generic base class for device type math criteria.
676 class MatchDeviceType
: public MatchCriteria
{
678 explicit MatchDeviceType(const std::string
& arg
);
679 ~MatchDeviceType() override
{}
686 // Check if a device is a pointer device.
687 class MatchIsPointer
: public MatchDeviceType
{
689 explicit MatchIsPointer(const std::string
& arg
);
690 ~MatchIsPointer() override
{}
691 bool Match(const DevicePtr device
) override
;
694 // Check if a device is a touchpad.
695 class MatchIsTouchpad
: public MatchDeviceType
{
697 explicit MatchIsTouchpad(const std::string
& arg
);
698 ~MatchIsTouchpad() override
{}
699 bool Match(const DevicePtr device
) override
;
702 // Check if a device is a touchscreen.
703 class MatchIsTouchscreen
: public MatchDeviceType
{
705 explicit MatchIsTouchscreen(const std::string
& arg
);
706 ~MatchIsTouchscreen() override
{}
707 bool Match(const DevicePtr device
) override
;
710 // Struct for sections in xorg conf files.
711 struct ConfigurationSection
{
712 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr
;
713 ConfigurationSection() {}
714 bool Match(const DevicePtr device
);
715 std::string identifier
;
716 ScopedVector
<MatchCriteria
> criterias
;
717 ScopedVector
<GesturesProp
> properties
;
720 MatchCriteria::MatchCriteria(const std::string
& arg
) {
721 // TODO(sheckylin): Should we trim all tokens here?
722 Tokenize(arg
, "|", &args_
);
724 LOG(ERROR
) << "Empty match pattern found, will evaluate to the default "
725 "value (true): \"" << arg
<< "\"";
729 MatchProduct::MatchProduct(const std::string
& arg
) : MatchCriteria(arg
) {
732 bool MatchProduct::Match(const DevicePtr device
) {
735 std::string
name(device
->info
.name
);
736 for (size_t i
= 0; i
< args_
.size(); ++i
)
737 if (name
.find(args_
[i
]) != std::string::npos
)
742 MatchDevicePath::MatchDevicePath(const std::string
& arg
) : MatchCriteria(arg
) {
745 bool MatchDevicePath::Match(const DevicePtr device
) {
749 // Check if the device path matches any pattern.
750 std::string path
= GetDeviceNodePath(device
);
753 for (size_t i
= 0; i
< args_
.size(); ++i
)
754 if (fnmatch(args_
[i
].c_str(), path
.c_str(), FNM_NOESCAPE
) == 0)
759 MatchUSBID::MatchUSBID(const std::string
& arg
) : MatchCriteria(arg
) {
760 // Check each pattern and split valid ones into vids and pids.
761 for (size_t i
= 0; i
< args_
.size(); ++i
) {
762 if (!IsValidPattern(args_
[i
])) {
763 LOG(ERROR
) << "Invalid USB ID: " << args_
[i
];
766 std::vector
<std::string
> tokens
;
767 base::SplitString(args_
[i
], ':', &tokens
);
768 vid_patterns_
.push_back(base::StringToLowerASCII(tokens
[0]));
769 pid_patterns_
.push_back(base::StringToLowerASCII(tokens
[1]));
771 if (vid_patterns_
.empty()) {
772 LOG(ERROR
) << "No valid USB ID pattern found, will be ignored: \"" << arg
777 bool MatchUSBID::Match(const DevicePtr device
) {
778 if (vid_patterns_
.empty())
780 std::string vid
= base::StringPrintf("%04x", device
->info
.id
.vendor
);
781 std::string pid
= base::StringPrintf("%04x", device
->info
.id
.product
);
782 for (size_t i
= 0; i
< vid_patterns_
.size(); ++i
) {
783 if (fnmatch(vid_patterns_
[i
].c_str(), vid
.c_str(), FNM_NOESCAPE
) == 0 &&
784 fnmatch(pid_patterns_
[i
].c_str(), pid
.c_str(), FNM_NOESCAPE
) == 0) {
791 bool MatchUSBID::IsValidPattern(const std::string
& pattern
) {
792 // Each USB id should be in the lsusb format, i.e., xxxx:xxxx. We choose to do
793 // a lazy check here: if the pattern contains wrong characters not in the hex
794 // number range, it won't be matched anyway.
795 int number_of_colons
= 0;
796 size_t pos_of_colon
= 0;
797 for (size_t i
= 0; i
< pattern
.size(); ++i
)
798 if (pattern
[i
] == ':')
799 ++number_of_colons
, pos_of_colon
= i
;
800 return (number_of_colons
== 1) && (pos_of_colon
!= 0) &&
801 (pos_of_colon
!= pattern
.size() - 1);
804 MatchDeviceType::MatchDeviceType(const std::string
& arg
)
805 : MatchCriteria(arg
), value_(true), is_valid_(false) {
806 // Default value of a match criteria is true.
808 args_
.push_back("on");
810 // We care only about the first argument.
811 int value
= ParseBooleanKeyword(args_
[0]);
818 << "No valid device class boolean keyword found, will be ignored: \""
823 MatchIsPointer::MatchIsPointer(const std::string
& arg
) : MatchDeviceType(arg
) {
826 bool MatchIsPointer::Match(const DevicePtr device
) {
829 return (value_
== (device
->info
.evdev_class
== EvdevClassMouse
||
830 device
->info
.evdev_class
== EvdevClassMultitouchMouse
));
833 MatchIsTouchpad::MatchIsTouchpad(const std::string
& arg
)
834 : MatchDeviceType(arg
) {
837 bool MatchIsTouchpad::Match(const DevicePtr device
) {
840 return (value_
== (device
->info
.evdev_class
== EvdevClassTouchpad
));
843 MatchIsTouchscreen::MatchIsTouchscreen(const std::string
& arg
)
844 : MatchDeviceType(arg
) {
847 bool MatchIsTouchscreen::Match(const DevicePtr device
) {
850 return (value_
== (device
->info
.evdev_class
== EvdevClassTouchscreen
));
853 bool ConfigurationSection::Match(DevicePtr device
) {
854 for (size_t i
= 0; i
< criterias
.size(); ++i
)
855 if (!criterias
[i
]->Match(device
))
860 } // namespace internal
862 GesturePropertyProvider::GesturePropertyProvider() {
863 LoadDeviceConfigurations();
866 GesturePropertyProvider::~GesturePropertyProvider() {
869 bool GesturePropertyProvider::GetDeviceIdsByType(
870 const EventDeviceType type
,
871 std::vector
<DeviceId
>* device_ids
) {
873 DeviceMap::const_iterator it
= device_map_
.begin();
874 for (; it
!= device_map_
.end(); ++it
) {
875 if (IsDeviceIdOfType(it
->first
, type
)) {
878 device_ids
->push_back(it
->first
);
884 bool GesturePropertyProvider::IsDeviceIdOfType(const DeviceId device_id
,
885 const EventDeviceType type
) {
886 DeviceMap::const_iterator it
= device_map_
.find(device_id
);
887 if (it
== device_map_
.end())
889 return IsDeviceOfType(it
->second
, type
,
890 GetProperty(device_id
, "Device Mouse"),
891 GetProperty(device_id
, "Device Touchpad"));
894 GesturesProp
* GesturePropertyProvider::GetProperty(const DeviceId device_id
,
895 const std::string
& name
) {
896 return FindProperty(device_id
, name
);
899 std::vector
<std::string
> GesturePropertyProvider::GetPropertyNamesById(
900 const DeviceId device_id
) {
901 internal::GestureDevicePropertyData
* device_data
=
902 device_data_map_
.get(device_id
);
904 return std::vector
<std::string
>();
906 // Dump all property names of the device.
907 std::vector
<std::string
> names
;
908 for (internal::ScopedPropertiesMap::const_iterator it
=
909 device_data
->properties
.begin();
910 it
!= device_data
->properties
.end(); ++it
)
911 names
.push_back(it
->first
);
915 std::string
GesturePropertyProvider::GetDeviceNameById(
916 const DeviceId device_id
) {
917 DeviceMap::const_iterator it
= device_map_
.find(device_id
);
918 if (it
== device_map_
.end())
919 return std::string();
920 return std::string(it
->second
->info
.name
);
923 void GesturePropertyProvider::RegisterDevice(const DeviceId id
,
924 const DevicePtr device
) {
925 DeviceMap::const_iterator it
= device_map_
.find(id
);
926 if (it
!= device_map_
.end())
929 // Setup data-structures.
930 device_map_
[id
] = device
;
931 device_data_map_
.set(id
,
932 scoped_ptr
<internal::GestureDevicePropertyData
>(
933 new internal::GestureDevicePropertyData
));
935 // Gather default property values for the device from the parsed conf files.
936 SetupDefaultProperties(id
, device
);
940 void GesturePropertyProvider::UnregisterDevice(const DeviceId id
) {
941 DeviceMap::const_iterator it
= device_map_
.find(id
);
942 if (it
== device_map_
.end())
944 device_data_map_
.erase(id
);
945 device_map_
.erase(it
);
948 void GesturePropertyProvider::AddProperty(const DeviceId device_id
,
949 const std::string
& name
,
950 GesturesProp
* property
) {
951 // The look-up should never fail because ideally a property can only be
952 // created with GesturesPropCreate* functions from the gesture lib side.
953 // Therefore, we simply return on failure.
954 internal::GestureDevicePropertyData
* device_data
=
955 device_data_map_
.get(device_id
);
957 device_data
->properties
.set(name
, scoped_ptr
<GesturesProp
>(property
));
960 void GesturePropertyProvider::DeleteProperty(const DeviceId device_id
,
961 const std::string
& name
) {
962 internal::GestureDevicePropertyData
* device_data
=
963 device_data_map_
.get(device_id
);
965 device_data
->properties
.erase(name
);
968 GesturesProp
* GesturePropertyProvider::FindProperty(const DeviceId device_id
,
969 const std::string
& name
) {
970 internal::GestureDevicePropertyData
* device_data
=
971 device_data_map_
.get(device_id
);
974 return device_data
->properties
.get(name
);
977 GesturesProp
* GesturePropertyProvider::GetDefaultProperty(
978 const DeviceId device_id
,
979 const std::string
& name
) {
980 internal::GestureDevicePropertyData
* device_data
=
981 device_data_map_
.get(device_id
);
984 internal::PropertiesMap::const_iterator ib
=
985 device_data
->default_properties
.find(name
);
986 if (ib
== device_data
->default_properties
.end())
991 void GesturePropertyProvider::LoadDeviceConfigurations() {
992 // Enumerate conf files and sort them lexicographically.
993 std::set
<base::FilePath
> files
;
994 base::FileEnumerator
file_enum(base::FilePath(kConfigurationFilePath
),
996 base::FileEnumerator::FILES
,
998 for (base::FilePath path
= file_enum
.Next(); !path
.empty();
999 path
= file_enum
.Next()) {
1002 DVLOG(2) << files
.size() << " conf files were found";
1004 // Parse conf files one-by-one.
1005 for (std::set
<base::FilePath
>::iterator file_iter
= files
.begin();
1006 file_iter
!= files
.end();
1008 DVLOG(2) << "Parsing conf file: " << (*file_iter
).value();
1009 std::string content
;
1010 if (!base::ReadFileToString(*file_iter
, &content
)) {
1011 LOG(ERROR
) << "Can't loading gestures conf file: "
1012 << (*file_iter
).value();
1015 ParseXorgConfFile(content
);
1019 void GesturePropertyProvider::ParseXorgConfFile(const std::string
& content
) {
1020 // To simplify the parsing work, we made some assumption about the conf file
1021 // format which doesn't exist in the original xorg-conf spec. Most important
1023 // 1. All keywords and names are now case-sensitive. Also, underscores are not
1025 // 2. Each entry takes up one and exactly one line in the file.
1026 // 3. No negation of the option value even if the option name is prefixed with
1027 // "No" as it may cause problems for option names that does start with "No"
1028 // (e.g., "Non-linearity").
1030 // Break the content into sections, lines and then pieces.
1031 // Sections are delimited by the "EndSection" keyword.
1032 // Lines are delimited by "\n".
1033 // Pieces are delimited by all white-spaces.
1034 std::vector
<std::string
> sections
;
1035 base::SplitStringUsingSubstr(content
, "EndSection", §ions
);
1036 for (size_t i
= 0; i
< sections
.size(); ++i
) {
1037 // Create a new configuration section.
1038 configurations_
.push_back(new internal::ConfigurationSection());
1039 internal::ConfigurationSection
* config
= configurations_
.back();
1041 // Break the section into lines.
1042 base::StringTokenizer
lines(sections
[i
], "\n");
1043 bool is_input_class_section
= true;
1044 bool has_checked_section_type
= false;
1045 while (is_input_class_section
&& lines
.GetNext()) {
1046 // Parse the line w.r.t. the xorg-conf format.
1047 std::string
line(lines
.token());
1049 // Skip empty lines.
1053 // Treat all whitespaces as delimiters.
1054 base::StringTokenizer
pieces(line
, base::kWhitespaceASCII
);
1055 pieces
.set_quote_chars("\"");
1056 bool is_parsing
= false;
1057 bool has_error
= false;
1058 bool next_is_section_type
= false;
1059 bool next_is_option_name
= false;
1060 bool next_is_option_value
= false;
1061 bool next_is_match_criteria
= false;
1062 bool next_is_identifier
= false;
1063 std::string match_type
, option_name
;
1064 while (pieces
.GetNext()) {
1065 std::string
piece(pieces
.token());
1067 // Skip empty pieces.
1071 // See if we are currently parsing an entry or are still looking for
1074 // Stop parsing the current line if the format is wrong.
1075 if (piece
.size() <= 2 || piece
[0] != '\"' ||
1076 piece
[piece
.size() - 1] != '\"') {
1077 LOG(ERROR
) << "Error parsing line: " << lines
.token();
1079 if (next_is_section_type
)
1080 is_input_class_section
= false;
1084 // Parse the arguments. Note that we don't break even if a whitespace
1085 // string is passed. It will just be handled in various ways based on
1088 base::TrimWhitespaceASCII(
1089 piece
.substr(1, piece
.size() - 2), base::TRIM_ALL
, &arg
);
1090 if (next_is_section_type
) {
1091 // We only care about InputClass sections.
1092 if (arg
!= "InputClass") {
1094 is_input_class_section
= false;
1096 DVLOG(2) << "New InputClass section found";
1097 has_checked_section_type
= true;
1100 } else if (next_is_identifier
) {
1101 DVLOG(2) << "Identifier: " << arg
;
1102 config
->identifier
= arg
;
1103 next_is_identifier
= false;
1105 } else if (next_is_option_name
) {
1106 // TODO(sheckylin): Support option "Ignore".
1108 next_is_option_value
= true;
1109 next_is_option_name
= false;
1110 } else if (next_is_option_value
) {
1111 GesturesProp
* property
= CreateDefaultProperty(option_name
, arg
);
1113 config
->properties
.push_back(property
);
1114 next_is_option_value
= false;
1116 } else if (next_is_match_criteria
) {
1117 // Skip all match types that are not supported.
1118 if (IsMatchTypeSupported(match_type
)) {
1119 internal::MatchCriteria
* criteria
=
1120 CreateMatchCriteria(match_type
, arg
);
1122 config
->criterias
.push_back(criteria
);
1124 next_is_match_criteria
= false;
1128 // If the section type hasn't been decided yet, look for it.
1129 // Otherwise, look for valid entries according to the spec.
1130 if (has_checked_section_type
) {
1131 if (piece
== "Driver") {
1132 // "Driver" field is meaningless for non-X11 setup.
1134 } else if (piece
== "Identifier") {
1136 next_is_identifier
= true;
1138 } else if (piece
== "Option") {
1140 next_is_option_name
= true;
1142 } else if (piece
.size() > 5 && piece
.compare(0, 5, "Match") == 0) {
1145 next_is_match_criteria
= true;
1148 } else if (piece
== "Section") {
1150 next_is_section_type
= true;
1154 // If none of the above is found, check if the current piece starts a
1156 if (piece
.empty() || piece
[0] != '#') {
1157 LOG(ERROR
) << "Error parsing line: " << lines
.token();
1164 // The value of a boolean option is skipped (default is true).
1165 if (!has_error
&& (next_is_option_value
|| next_is_match_criteria
)) {
1166 if (next_is_option_value
) {
1167 GesturesProp
* property
= CreateDefaultProperty(option_name
, "on");
1169 config
->properties
.push_back(property
);
1170 } else if (IsMatchTypeSupported(match_type
) &&
1171 IsMatchDeviceType(match_type
)) {
1172 internal::MatchCriteria
* criteria
=
1173 CreateMatchCriteria(match_type
, "on");
1175 config
->criterias
.push_back(criteria
);
1180 // Remove useless config sections.
1181 if (!is_input_class_section
||
1182 (config
->criterias
.empty() && config
->properties
.empty())) {
1183 configurations_
.pop_back();
1188 internal::MatchCriteria
* GesturePropertyProvider::CreateMatchCriteria(
1189 const std::string
& match_type
,
1190 const std::string
& arg
) {
1191 DVLOG(2) << "Creating match criteria: (" << match_type
<< ", " << arg
<< ")";
1192 if (match_type
== "MatchProduct")
1193 return new internal::MatchProduct(arg
);
1194 if (match_type
== "MatchDevicePath")
1195 return new internal::MatchDevicePath(arg
);
1196 if (match_type
== "MatchUSBID")
1197 return new internal::MatchUSBID(arg
);
1198 if (match_type
== "MatchIsPointer")
1199 return new internal::MatchIsPointer(arg
);
1200 if (match_type
== "MatchIsTouchpad")
1201 return new internal::MatchIsTouchpad(arg
);
1202 if (match_type
== "MatchIsTouchscreen")
1203 return new internal::MatchIsTouchscreen(arg
);
1208 GesturesProp
* GesturePropertyProvider::CreateDefaultProperty(
1209 const std::string
& name
,
1210 const std::string
& value
) {
1211 // Our parsing rule:
1212 // 1. No hex or oct number is accepted.
1213 // 2. All numbers will be stored as double.
1214 // 3. Array elements can be separated by both white-spaces or commas.
1215 // 4. A token is treated as numeric either if it is one of the special
1216 // keywords for boolean values (on, true, yes, off, false, no) or if
1217 // base::StringToDouble succeeds.
1218 // 5. The property is treated as numeric if and only if all of its elements
1219 // (if any) are numerics. Otherwise, it will be treated as a string.
1220 // 6. A string property will be trimmed before storing its value.
1221 DVLOG(2) << "Creating default property: (" << name
<< ", " << value
<< ")";
1223 // Parse elements one-by-one.
1224 std::string
delimiters(base::kWhitespaceASCII
);
1225 delimiters
.append(",");
1226 base::StringTokenizer
tokens(value
, delimiters
);
1227 bool is_all_numeric
= true;
1228 std::vector
<double> numbers
;
1229 while (tokens
.GetNext()) {
1230 // Skip empty tokens.
1231 std::string
token(tokens
.token());
1235 // Check if it is a boolean keyword.
1236 int bool_result
= ParseBooleanKeyword(token
);
1238 numbers
.push_back(bool_result
> 0);
1242 // Check if it is a number.
1244 bool success
= base::StringToDouble(token
, &real_result
);
1246 is_all_numeric
= false;
1249 numbers
.push_back(real_result
);
1252 // Create the GesturesProp. Array properties need to contain at least one
1253 // number and may contain numbers only.
1254 GesturesProp
* property
= NULL
;
1255 if (is_all_numeric
&& numbers
.size()) {
1256 property
= new GesturesDoubleProp(
1257 name
, numbers
.size(), NULL
, numbers
.data(), NULL
);
1259 property
= new GesturesStringProp(name
, NULL
, value
.c_str(), NULL
);
1262 DVLOG(2) << "Prop: " << *property
;
1263 // The function will always succeed for now but it may change later if we
1264 // specify some name or args as invalid.
1268 void GesturePropertyProvider::SetupDefaultProperties(const DeviceId device_id
,
1269 const DevicePtr device
) {
1270 DVLOG(2) << "Setting up default properties for (" << device
<< ", "
1271 << device_id
<< ", " << device
->info
.name
<< ")";
1273 // Go through all parsed sections.
1274 internal::PropertiesMap
& property_map
=
1275 device_data_map_
.get(device_id
)->default_properties
;
1276 for (size_t i
= 0; i
< configurations_
.size(); ++i
) {
1277 if (configurations_
[i
]->Match(device
)) {
1278 DVLOG(2) << "Conf section \"" << configurations_
[i
]->identifier
1280 for (size_t j
= 0; j
< configurations_
[i
]->properties
.size(); j
++) {
1281 GesturesProp
* property
= configurations_
[i
]->properties
[j
];
1282 // We can't use insert here because a property may be set for several
1283 // times along the way.
1284 property_map
[property
->name()] = property
;
1290 GesturesProp
* GesturesPropFunctionsWrapper::CreateInt(void* device_data
,
1295 return CreateProperty
<int, GesturesIntProp
>(
1296 device_data
, name
, value
, count
, init
);
1299 GesturesProp
* GesturesPropFunctionsWrapper::CreateShort(void* device_data
,
1303 const short* init
) {
1304 return CreateProperty
<short, GesturesShortProp
>(
1305 device_data
, name
, value
, count
, init
);
1308 GesturesProp
* GesturesPropFunctionsWrapper::CreateBool(
1311 GesturesPropBool
* value
,
1313 const GesturesPropBool
* init
) {
1314 return CreateProperty
<GesturesPropBool
, GesturesBoolProp
>(
1315 device_data
, name
, value
, count
, init
);
1318 GesturesProp
* GesturesPropFunctionsWrapper::CreateReal(void* device_data
,
1322 const double* init
) {
1323 return CreateProperty
<double, GesturesDoubleProp
>(
1324 device_data
, name
, value
, count
, init
);
1327 GesturesProp
* GesturesPropFunctionsWrapper::CreateString(void* device_data
,
1331 GesturesProp
* default_property
= NULL
;
1332 if (!PreCreateProperty(device_data
, name
, &default_property
))
1334 GesturesProp
* property
=
1335 new GesturesStringProp(name
, value
, init
, default_property
);
1337 PostCreateProperty(device_data
, name
, property
);
1341 void GesturesPropFunctionsWrapper::RegisterHandlers(
1343 GesturesProp
* property
,
1345 GesturesPropGetHandler get
,
1346 GesturesPropSetHandler set
) {
1348 if (!device_data
|| !property
)
1351 property
->SetHandlers(get
, set
, handler_data
);
1354 void GesturesPropFunctionsWrapper::Free(void* device_data
,
1355 GesturesProp
* property
) {
1358 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1360 // No need to manually delete the prop pointer as it is implicitly handled
1362 DVLOG(3) << "Freeing Property: \"" << property
->name() << "\"";
1363 provider
->DeleteProperty(GetDeviceId(device_data
), property
->name());
1366 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties(
1368 GestureDeviceProperties
* properties
) {
1371 GesturePropertyProvider::DevicePtr device
= GetDevicePointer(device_data
);
1373 /* Create Device Properties */
1375 // Read Only properties.
1377 device_data
, "Device Node", NULL
, GetDeviceNodePath(device
).c_str());
1378 short vid
= static_cast<short>(device
->info
.id
.vendor
);
1379 CreateShort(device_data
, "Device Vendor ID", NULL
, 1, &vid
);
1380 short pid
= static_cast<short>(device
->info
.id
.product
);
1381 CreateShort(device_data
, "Device Product ID", NULL
, 1, &pid
);
1383 // Useable trackpad area. If not configured in .conf file,
1384 // use x/y valuator min/max as reported by kernel driver.
1385 CreateIntSingle(device_data
,
1387 &properties
->area_left
,
1388 Event_Get_Left(device
));
1389 CreateIntSingle(device_data
,
1390 "Active Area Right",
1391 &properties
->area_right
,
1392 Event_Get_Right(device
));
1393 CreateIntSingle(device_data
,
1395 &properties
->area_top
,
1396 Event_Get_Top(device
));
1397 CreateIntSingle(device_data
,
1398 "Active Area Bottom",
1399 &properties
->area_bottom
,
1400 Event_Get_Bottom(device
));
1402 // Trackpad resolution (pixels/mm). If not configured in .conf file,
1403 // use x/y resolution as reported by kernel driver.
1404 CreateIntSingle(device_data
,
1405 "Vertical Resolution",
1407 Event_Get_Res_Y(device
));
1408 CreateIntSingle(device_data
,
1409 "Horizontal Resolution",
1411 Event_Get_Res_X(device
));
1413 // Trackpad orientation minimum/maximum. If not configured in .conf file,
1414 // use min/max as reported by kernel driver.
1415 CreateIntSingle(device_data
,
1416 "Orientation Minimum",
1417 &properties
->orientation_minimum
,
1418 Event_Get_Orientation_Minimum(device
));
1419 CreateIntSingle(device_data
,
1420 "Orientation Maximum",
1421 &properties
->orientation_maximum
,
1422 Event_Get_Orientation_Maximum(device
));
1424 // Log dump property. Will call Event_Dump_Debug_Log when its value is being
1426 GesturesProp
* dump_debug_log_prop
= CreateBoolSingle(
1427 device_data
, "Dump Debug Log", &properties
->dump_debug_log
, false);
1428 RegisterHandlers(device_data
, dump_debug_log_prop
, device
, NULL
,
1429 DumpTouchEvdevDebugLog
);
1431 // Whether to do the gesture recognition or just passing the multi-touch data
1433 CreateBoolSingle(device_data
,
1434 "Raw Touch Passthrough",
1435 &properties
->raw_passthrough
,
1440 void GesturesPropFunctionsWrapper::UnregisterDevice(void* device_data
) {
1441 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1442 provider
->UnregisterDevice(GetDeviceId(device_data
));
1445 template <typename T
, class PROPTYPE
>
1446 GesturesProp
* GesturesPropFunctionsWrapper::CreateProperty(void* device_data
,
1451 // Create the property. Use the default property value if possible.
1452 GesturesProp
* default_property
= NULL
;
1453 if (!PreCreateProperty(device_data
, name
, &default_property
))
1455 GesturesProp
* property
=
1456 new PROPTYPE(name
, count
, value
, init
, default_property
);
1458 // Start tracking the property in the provider.
1459 PostCreateProperty(device_data
, name
, property
);
1463 bool GesturesPropFunctionsWrapper::PreCreateProperty(
1466 GesturesProp
** default_property
) {
1467 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1468 GesturePropertyProvider::DeviceId device_id
= GetDeviceId(device_data
);
1470 // Register the device in the property provider if not yet.
1471 provider
->RegisterDevice(device_id
, GetDevicePointer(device_data
));
1473 // First, see if the GesturesProp already exists.
1474 DVLOG(3) << "Creating Property: \"" << name
<< "\"";
1475 GesturesProp
* property
= provider
->FindProperty(device_id
, name
);
1477 // If so, delete it as we can't reuse the data structure (newly-created
1478 // property may have different data type and count, which are fixed upon
1479 // creation via the template mechanism).
1481 LOG(WARNING
) << "Gesture property \"" << name
1482 << "\" re-created. This shouldn't happen at the normal usage.";
1483 Free(device_data
, property
);
1486 // Return the found default property from conf files (could be NULL).
1487 *default_property
= provider
->GetDefaultProperty(device_id
, name
);
1491 void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data
,
1493 GesturesProp
* property
) {
1494 // Add the property to the gesture property provider. The gesture property
1495 // provider will own it from now on.
1496 GesturePropertyProvider
* provider
= GetPropertyProvider(device_data
);
1497 provider
->AddProperty(GetDeviceId(device_data
), name
, property
);
1499 // Log the creation.
1500 DVLOG(3) << "Created active prop: " << *property
;
1503 GesturesProp
* GesturesPropFunctionsWrapper::CreateIntSingle(void* device_data
,
1507 return CreateInt(device_data
, name
, value
, 1, &init
);
1510 GesturesProp
* GesturesPropFunctionsWrapper::CreateBoolSingle(
1513 GesturesPropBool
* value
,
1514 GesturesPropBool init
) {
1515 return CreateBool(device_data
, name
, value
, 1, &init
);
1518 GesturePropertyProvider
* GesturesPropFunctionsWrapper::GetPropertyProvider(
1519 void* device_data
) {
1520 return static_cast<GestureInterpreterLibevdevCros
*>(device_data
)
1521 ->property_provider();
1524 GesturePropertyProvider::DevicePtr
1525 GesturesPropFunctionsWrapper::GetDevicePointer(void* device_data
) {
1526 return static_cast<GestureInterpreterLibevdevCros
*>(device_data
)->evdev();
1529 GesturePropertyProvider::DeviceId
GesturesPropFunctionsWrapper::GetDeviceId(
1530 void* device_data
) {
1531 return static_cast<GestureInterpreterLibevdevCros
*>(device_data
)->id();
1534 /* Global GesturesPropProvider
1536 * Used by PropRegistry in GestureInterpreter to forward property value
1537 * creations from there.
1539 const GesturesPropProvider kGesturePropProvider
= {
1540 GesturesPropFunctionsWrapper::CreateInt
,
1541 GesturesPropFunctionsWrapper::CreateShort
,
1542 GesturesPropFunctionsWrapper::CreateBool
,
1543 GesturesPropFunctionsWrapper::CreateString
,
1544 GesturesPropFunctionsWrapper::CreateReal
,
1545 GesturesPropFunctionsWrapper::RegisterHandlers
,
1546 GesturesPropFunctionsWrapper::Free
};