Replace remaining Tokenize calls to SplitString
[chromium-blink-merge.git] / ui / events / ozone / evdev / libgestures_glue / gesture_property_provider.cc
blob45cd381677d540d299147f1bf1cab3617e91e913
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>
10 #include <fnmatch.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <algorithm>
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,
33 const size_t count)
34 : name_(name),
35 type_(type),
36 count_(count),
37 get_(NULL),
38 set_(NULL),
39 handler_data_(NULL) {
42 std::vector<int> GesturesProp::GetIntValue() const {
43 NOTREACHED();
44 return std::vector<int>();
47 bool GesturesProp::SetIntValue(const std::vector<int>& value) {
48 NOTREACHED();
49 return false;
52 std::vector<int16_t> GesturesProp::GetShortValue() const {
53 NOTREACHED();
54 return std::vector<int16_t>();
57 bool GesturesProp::SetShortValue(const std::vector<int16_t>& value) {
58 NOTREACHED();
59 return false;
62 std::vector<bool> GesturesProp::GetBoolValue() const {
63 NOTREACHED();
64 return std::vector<bool>();
67 bool GesturesProp::SetBoolValue(const std::vector<bool>& value) {
68 NOTREACHED();
69 return false;
72 std::string GesturesProp::GetStringValue() const {
73 NOTREACHED();
74 return std::string();
77 bool GesturesProp::SetStringValue(const std::string& value) {
78 NOTREACHED();
79 return false;
82 std::vector<double> GesturesProp::GetDoubleValue() const {
83 NOTREACHED();
84 return std::vector<double>();
87 bool GesturesProp::SetDoubleValue(const std::vector<double>& value) {
88 NOTREACHED();
89 return false;
92 void GesturesProp::SetHandlers(GesturesPropGetHandler get,
93 GesturesPropSetHandler set,
94 void* data) {
95 get_ = get;
96 set_ = set;
97 handler_data_ = data;
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
104 // property.
105 if (get_)
106 get_(handler_data_);
109 void GesturesProp::OnSet() const {
110 // Call the property set handler if available.
111 if (set_)
112 set_(handler_data_);
115 const char** GesturesProp::GetStringWritebackPtr() const {
116 NOTREACHED();
117 return NULL;
120 bool GesturesProp::IsAllocated() const {
121 NOTREACHED();
122 return false;
125 // Type-templated GesturesProp.
126 template <typename T>
127 class TypedGesturesProp : public GesturesProp {
128 public:
129 TypedGesturesProp(const std::string& name,
130 const PropertyType type,
131 const size_t count,
132 T* value)
133 : GesturesProp(name, type, count),
134 value_(value),
135 is_read_only_(false),
136 is_allocated_(false) {
137 Init();
139 ~TypedGesturesProp() override {
140 if (is_allocated_)
141 delete[] value_;
144 // Accessors.
145 bool IsReadOnly() const override { return is_read_only_; }
147 protected:
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.
155 OnGet();
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())
168 return false;
169 bool ret = this->template SetNumericalValue(value);
170 OnSet();
171 return ret;
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());
181 } else {
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);
189 // Data pointer.
190 T* value_;
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.
197 bool is_read_only_;
199 private:
200 // Initialize the object.
201 void Init() {
202 // If no external data pointer is passed, we have to create our own.
203 if (!value_) {
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]);
221 return result;
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]);
228 return true;
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);
240 // Accessors.
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.
246 bool is_allocated_;
249 class GesturesIntProp : public TypedGesturesProp<int> {
250 public:
251 GesturesIntProp(const std::string& name,
252 const size_t count,
253 int* value,
254 const int* init,
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> {
268 public:
269 GesturesShortProp(const std::string& name,
270 const size_t count,
271 short* value,
272 const short* init,
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> {
286 public:
287 GesturesBoolProp(const std::string& name,
288 const size_t count,
289 GesturesPropBool* value,
290 const GesturesPropBool* init,
291 const GesturesProp* default_property)
292 : TypedGesturesProp<GesturesPropBool>(name,
293 PropertyType::PT_BOOL,
294 count,
295 value) {
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> {
307 public:
308 GesturesDoubleProp(const std::string& name,
309 const size_t count,
310 double* value,
311 const double* init,
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> {
325 public:
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,
332 const char** value,
333 const char* init,
334 const GesturesProp* default_property)
335 : TypedGesturesProp<std::string>(name, PropertyType::PT_STRING, 1, NULL),
336 write_back_(NULL) {
337 InitializeStringProperty(value, init, default_property);
339 std::string GetStringValue() const override {
340 OnGet();
341 return *value_;
343 bool SetStringValue(const std::string& value) override {
344 if (is_read_only_)
345 return false;
346 *value_ = value;
348 // Write back the pointer in case it may change (e.g., string
349 // re-allocation).
350 if (write_back_)
351 *(write_back_) = value_->c_str();
352 OnSet();
353 return true;
356 private:
357 // Initialize the object.
358 void InitializeStringProperty(const char** value,
359 const char* init,
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();
365 } else {
366 *value_ = init;
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.
374 if (value) {
375 *value = value_->c_str();
376 write_back_ = value;
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
383 // now.
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
395 // changed.
396 const char** write_back_;
399 // Anonymous namespace for utility functions and internal constants.
400 namespace {
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
408 // environment.
409 const char* kSupportedMatchTypes[] = {"MatchProduct",
410 "MatchDevicePath",
411 "MatchUSBID",
412 "MatchIsPointer",
413 "MatchIsTouchpad",
414 "MatchIsTouchscreen"};
415 const char* kUnsupportedMatchTypes[] = {"MatchVendor",
416 "MatchOS",
417 "MatchPnPID",
418 "MatchDriver",
419 "MatchTag",
420 "MatchLayout",
421 "MatchIsKeyboard",
422 "MatchIsJoystick",
423 "MatchIsTablet"};
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];
440 } else {
441 is_mouse = (evdev_class == EvdevClassMouse ||
442 evdev_class == EvdevClassMultitouchMouse);
444 if (device_touchpad_property) {
445 is_touchpad = device_touchpad_property->GetBoolValue()[0];
446 } else {
447 is_touchpad = (evdev_class == EvdevClassTouchpad ||
448 evdev_class == EvdevClassTouchscreen ||
449 evdev_class == EvdevClassMultitouchMouse);
452 switch (type) {
453 case ui::DT_KEYBOARD:
454 return (evdev_class == EvdevClassKeyboard);
455 break;
456 case ui::DT_MOUSE:
457 return is_mouse;
458 break;
459 case ui::DT_TOUCHPAD:
460 return (!is_mouse) && is_touchpad;
461 break;
462 case ui::DT_TOUCHSCREEN:
463 return (evdev_class == EvdevClassTouchscreen);
464 break;
465 case ui::DT_MULTITOUCH:
466 return is_touchpad;
467 break;
468 case ui::DT_MULTITOUCH_MOUSE:
469 return is_mouse && is_touchpad;
470 break;
471 case ui::DT_ALL:
472 return true;
473 break;
474 default:
475 break;
477 return false;
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);
484 base::FilePath path;
485 if (!base::ReadSymbolicLink(base::FilePath(proc_symlink), &path))
486 return std::string();
487 return path.value();
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])
495 return true;
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: "
499 << match_type;
500 return false;
503 return false;
506 // Check if a match criteria is a device type one.
507 bool IsMatchDeviceType(const std::string& match_type) {
508 return base::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 (base::LowerCaseEqualsASCII(value, kTrue[i]))
515 return 1;
517 for (size_t i = 0; i < arraysize(kFalse); ++i) {
518 if (base::LowerCaseEqualsASCII(value, kFalse[i]))
519 return -1;
521 return 0;
524 // Log the value of an array property.
525 template <typename T>
526 void LogArrayProperty(std::ostream& os, const std::vector<T>& value) {
527 os << "(";
528 for (size_t i = 0; i < value.size(); ++i) {
529 if (i > 0)
530 os << ", ";
531 os << value[i];
533 os << ")";
536 // Property type logging function.
537 std::ostream& operator<<(std::ostream& out,
538 const ui::GesturePropertyProvider::PropertyType type) {
539 std::string s;
540 #define TYPE_CASE(TYPE) \
541 case (ui::GesturePropertyProvider::TYPE): \
542 s = #TYPE; \
543 break;
544 switch (type) {
545 TYPE_CASE(PT_INT);
546 TYPE_CASE(PT_SHORT);
547 TYPE_CASE(PT_BOOL);
548 TYPE_CASE(PT_STRING);
549 TYPE_CASE(PT_REAL);
550 default:
551 NOTREACHED();
552 break;
554 #undef TYPE_CASE
555 return out << s;
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);
564 } // namespace
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();
578 else
579 os << "NULL";
581 // Output the property values.
582 os << ", ";
583 switch (property->type()) {
584 case ui::GesturePropertyProvider::PT_INT:
585 LogArrayProperty(os, property->GetIntValue());
586 break;
587 case ui::GesturePropertyProvider::PT_SHORT:
588 LogArrayProperty(os, property->GetShortValue());
589 break;
590 case ui::GesturePropertyProvider::PT_BOOL:
591 LogArrayProperty(os, property->GetBoolValue());
592 break;
593 case ui::GesturePropertyProvider::PT_STRING:
594 os << "\"" << property->GetStringValue() << "\"";
595 break;
596 case ui::GesturePropertyProvider::PT_REAL:
597 LogArrayProperty(os, property->GetDoubleValue());
598 break;
599 default:
600 LOG(ERROR) << "Unknown gesture property type: " << property->type();
601 NOTREACHED();
602 break;
604 return os;
607 namespace ui {
608 namespace internal {
610 // Mapping table from a property name to its corresponding GesturesProp
611 // object pointer.
612 typedef base::hash_map<std::string, GesturesProp*> PropertiesMap;
613 typedef base::ScopedPtrHashMap<std::string, scoped_ptr<GesturesProp>>
614 ScopedPropertiesMap;
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
621 // don't want to do.
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 {
637 public:
638 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr;
639 explicit MatchCriteria(const std::string& arg);
640 virtual ~MatchCriteria() {}
641 virtual bool Match(const DevicePtr device) = 0;
643 protected:
644 std::vector<std::string> args_;
647 // Match a device based on its evdev name string.
648 class MatchProduct : public MatchCriteria {
649 public:
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 {
657 public:
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 {
666 public:
667 explicit MatchUSBID(const std::string& arg);
668 ~MatchUSBID() override {}
669 bool Match(const DevicePtr device) override;
671 private:
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 {
679 public:
680 explicit MatchDeviceType(const std::string& arg);
681 ~MatchDeviceType() override {}
683 protected:
684 bool value_;
685 bool is_valid_;
688 // Check if a device is a pointer device.
689 class MatchIsPointer : public MatchDeviceType {
690 public:
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 {
698 public:
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 {
706 public:
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);
726 if (args_.empty()) {
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) {
736 if (args_.empty())
737 return true;
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)
741 return true;
742 return false;
745 MatchDevicePath::MatchDevicePath(const std::string& arg) : MatchCriteria(arg) {
748 bool MatchDevicePath::Match(const DevicePtr device) {
749 if (args_.empty())
750 return true;
752 // Check if the device path matches any pattern.
753 std::string path = GetDeviceNodePath(device);
754 if (path.empty())
755 return false;
756 for (size_t i = 0; i < args_.size(); ++i)
757 if (fnmatch(args_[i].c_str(), path.c_str(), FNM_NOESCAPE) == 0)
758 return true;
759 return false;
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];
767 continue;
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
776 << "\"";
780 bool MatchUSBID::Match(const DevicePtr device) {
781 if (vid_patterns_.empty())
782 return true;
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) {
788 return true;
791 return false;
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.
810 if (args_.empty())
811 args_.push_back("on");
813 // We care only about the first argument.
814 int value = ParseBooleanKeyword(args_[0]);
815 if (value) {
816 is_valid_ = true;
817 value_ = value > 0;
819 if (!is_valid_) {
820 LOG(ERROR)
821 << "No valid device class boolean keyword found, will be ignored: \""
822 << arg << "\"";
826 MatchIsPointer::MatchIsPointer(const std::string& arg) : MatchDeviceType(arg) {
829 bool MatchIsPointer::Match(const DevicePtr device) {
830 if (!is_valid_)
831 return true;
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) {
841 if (!is_valid_)
842 return true;
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) {
851 if (!is_valid_)
852 return true;
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))
859 return false;
860 return true;
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) {
875 bool exists = false;
876 DeviceMap::const_iterator it = device_map_.begin();
877 for (; it != device_map_.end(); ++it) {
878 if (IsDeviceIdOfType(it->first, type)) {
879 exists = true;
880 if (device_ids)
881 device_ids->push_back(it->first);
884 return exists;
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())
891 return false;
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);
906 if (!device_data)
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);
915 return names;
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())
930 return;
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);
940 return;
943 void GesturePropertyProvider::UnregisterDevice(const DeviceId id) {
944 DeviceMap::const_iterator it = device_map_.find(id);
945 if (it == device_map_.end())
946 return;
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);
959 if (device_data)
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);
967 if (device_data)
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);
975 if (!device_data)
976 return NULL;
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);
985 if (!device_data)
986 return NULL;
987 internal::PropertiesMap::const_iterator ib =
988 device_data->default_properties.find(name);
989 if (ib == device_data->default_properties.end())
990 return NULL;
991 return ib->second;
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),
998 false,
999 base::FileEnumerator::FILES,
1000 "*.conf");
1001 for (base::FilePath path = file_enum.Next(); !path.empty();
1002 path = file_enum.Next()) {
1003 files.insert(path);
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();
1010 ++file_iter) {
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();
1016 continue;
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
1025 // ones are:
1026 // 1. All keywords and names are now case-sensitive. Also, underscores are not
1027 // ignored.
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", &sections);
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.
1053 if (line.empty())
1054 continue;
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.
1071 if (piece.empty())
1072 continue;
1074 // See if we are currently parsing an entry or are still looking for
1075 // one.
1076 if (is_parsing) {
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();
1081 has_error = true;
1082 if (next_is_section_type)
1083 is_input_class_section = false;
1084 break;
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
1089 // the entry type.
1090 std::string arg;
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") {
1096 has_error = true;
1097 is_input_class_section = false;
1098 } else {
1099 DVLOG(2) << "New InputClass section found";
1100 has_checked_section_type = true;
1102 break;
1103 } else if (next_is_identifier) {
1104 DVLOG(2) << "Identifier: " << arg;
1105 config->identifier = arg;
1106 next_is_identifier = false;
1107 break;
1108 } else if (next_is_option_name) {
1109 // TODO(sheckylin): Support option "Ignore".
1110 option_name = arg;
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);
1115 if (property)
1116 config->properties.push_back(property);
1117 next_is_option_value = false;
1118 break;
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);
1124 if (criteria)
1125 config->criterias.push_back(criteria);
1127 next_is_match_criteria = false;
1128 break;
1130 } else {
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.
1136 break;
1137 } else if (piece == "Identifier") {
1138 is_parsing = true;
1139 next_is_identifier = true;
1140 continue;
1141 } else if (piece == "Option") {
1142 is_parsing = true;
1143 next_is_option_name = true;
1144 continue;
1145 } else if (piece.size() > 5 && piece.compare(0, 5, "Match") == 0) {
1146 match_type = piece;
1147 is_parsing = true;
1148 next_is_match_criteria = true;
1149 continue;
1151 } else if (piece == "Section") {
1152 is_parsing = true;
1153 next_is_section_type = true;
1154 continue;
1157 // If none of the above is found, check if the current piece starts a
1158 // comment.
1159 if (piece.empty() || piece[0] != '#') {
1160 LOG(ERROR) << "Error parsing line: " << lines.token();
1161 has_error = true;
1163 break;
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");
1171 if (property)
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");
1177 if (criteria)
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);
1207 NOTREACHED();
1208 return NULL;
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());
1235 if (token.empty())
1236 continue;
1238 // Check if it is a boolean keyword.
1239 int bool_result = ParseBooleanKeyword(token);
1240 if (bool_result) {
1241 numbers.push_back(bool_result > 0);
1242 continue;
1245 // Check if it is a number.
1246 double real_result;
1247 bool success = base::StringToDouble(token, &real_result);
1248 if (!success) {
1249 is_all_numeric = false;
1250 break;
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);
1261 } else {
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.
1268 return property;
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
1282 << "\" is matched";
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,
1294 const char* name,
1295 int* value,
1296 size_t count,
1297 const int* init) {
1298 return CreateProperty<int, GesturesIntProp>(
1299 device_data, name, value, count, init);
1302 GesturesProp* GesturesPropFunctionsWrapper::CreateShort(void* device_data,
1303 const char* name,
1304 short* value,
1305 size_t count,
1306 const short* init) {
1307 return CreateProperty<short, GesturesShortProp>(
1308 device_data, name, value, count, init);
1311 GesturesProp* GesturesPropFunctionsWrapper::CreateBool(
1312 void* device_data,
1313 const char* name,
1314 GesturesPropBool* value,
1315 size_t count,
1316 const GesturesPropBool* init) {
1317 return CreateProperty<GesturesPropBool, GesturesBoolProp>(
1318 device_data, name, value, count, init);
1321 GesturesProp* GesturesPropFunctionsWrapper::CreateReal(void* device_data,
1322 const char* name,
1323 double* value,
1324 size_t count,
1325 const double* init) {
1326 return CreateProperty<double, GesturesDoubleProp>(
1327 device_data, name, value, count, init);
1330 GesturesProp* GesturesPropFunctionsWrapper::CreateString(void* device_data,
1331 const char* name,
1332 const char** value,
1333 const char* init) {
1334 GesturesProp* default_property = NULL;
1335 if (!PreCreateProperty(device_data, name, &default_property))
1336 return NULL;
1337 GesturesProp* property =
1338 new GesturesStringProp(name, value, init, default_property);
1340 PostCreateProperty(device_data, name, property);
1341 return property;
1344 void GesturesPropFunctionsWrapper::RegisterHandlers(
1345 void* device_data,
1346 GesturesProp* property,
1347 void* handler_data,
1348 GesturesPropGetHandler get,
1349 GesturesPropSetHandler set) {
1350 // Sanity checks
1351 if (!device_data || !property)
1352 return;
1354 property->SetHandlers(get, set, handler_data);
1357 void GesturesPropFunctionsWrapper::Free(void* device_data,
1358 GesturesProp* property) {
1359 if (!property)
1360 return;
1361 GesturePropertyProvider* provider = GetPropertyProvider(device_data);
1363 // No need to manually delete the prop pointer as it is implicitly handled
1364 // with scoped ptr.
1365 DVLOG(3) << "Freeing Property: \"" << property->name() << "\"";
1366 provider->DeleteProperty(GetDeviceId(device_data), property->name());
1369 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties(
1370 void* device_data,
1371 GestureDeviceProperties* properties) {
1372 if (!device_data)
1373 return false;
1374 GesturePropertyProvider::DevicePtr device = GetDevicePointer(device_data);
1376 /* Create Device Properties */
1378 // Read Only properties.
1379 CreateString(
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,
1389 "Active Area Left",
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,
1397 "Active Area Top",
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",
1409 &properties->res_y,
1410 Event_Get_Res_Y(device));
1411 CreateIntSingle(device_data,
1412 "Horizontal Resolution",
1413 &properties->res_x,
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
1428 // set.
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
1435 // to upper layers.
1436 CreateBoolSingle(device_data,
1437 "Raw Touch Passthrough",
1438 &properties->raw_passthrough,
1439 false);
1440 return true;
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,
1450 const char* name,
1451 T* value,
1452 size_t count,
1453 const T* init) {
1454 // Create the property. Use the default property value if possible.
1455 GesturesProp* default_property = NULL;
1456 if (!PreCreateProperty(device_data, name, &default_property))
1457 return NULL;
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);
1463 return property;
1466 bool GesturesPropFunctionsWrapper::PreCreateProperty(
1467 void* device_data,
1468 const char* name,
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).
1483 if (property) {
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);
1491 return true;
1494 void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data,
1495 const char* name,
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,
1507 const char* name,
1508 int* value,
1509 int init) {
1510 return CreateInt(device_data, name, value, 1, &init);
1513 GesturesProp* GesturesPropFunctionsWrapper::CreateBoolSingle(
1514 void* device_data,
1515 const char* name,
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.
1541 * */
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};
1551 } // namespace ui