Change ScopedPtrHashMap's 2nd template parameter
[chromium-blink-merge.git] / ui / events / ozone / evdev / libgestures_glue / gesture_property_provider.cc
blobb3289ffc82d109e09b9a3740ce239110c83ba53b
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 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]))
515 return 1;
516 for (size_t i = 0; i < arraysize(kFalse); ++i)
517 if (LowerCaseEqualsASCII(value, kFalse[i]))
518 return -1;
519 return 0;
522 // Log the value of an array property.
523 template <typename T>
524 void LogArrayProperty(std::ostream& os, const std::vector<T>& value) {
525 os << "(";
526 for (size_t i = 0; i < value.size(); ++i) {
527 if (i > 0)
528 os << ", ";
529 os << value[i];
531 os << ")";
534 // Property type logging function.
535 std::ostream& operator<<(std::ostream& out,
536 const ui::GesturePropertyProvider::PropertyType type) {
537 std::string s;
538 #define TYPE_CASE(TYPE) \
539 case (ui::GesturePropertyProvider::TYPE): \
540 s = #TYPE; \
541 break;
542 switch (type) {
543 TYPE_CASE(PT_INT);
544 TYPE_CASE(PT_SHORT);
545 TYPE_CASE(PT_BOOL);
546 TYPE_CASE(PT_STRING);
547 TYPE_CASE(PT_REAL);
548 default:
549 NOTREACHED();
550 break;
552 #undef TYPE_CASE
553 return out << s;
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);
562 } // namespace
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();
576 else
577 os << "NULL";
579 // Output the property values.
580 os << ", ";
581 switch (property->type()) {
582 case ui::GesturePropertyProvider::PT_INT:
583 LogArrayProperty(os, property->GetIntValue());
584 break;
585 case ui::GesturePropertyProvider::PT_SHORT:
586 LogArrayProperty(os, property->GetShortValue());
587 break;
588 case ui::GesturePropertyProvider::PT_BOOL:
589 LogArrayProperty(os, property->GetBoolValue());
590 break;
591 case ui::GesturePropertyProvider::PT_STRING:
592 os << "\"" << property->GetStringValue() << "\"";
593 break;
594 case ui::GesturePropertyProvider::PT_REAL:
595 LogArrayProperty(os, property->GetDoubleValue());
596 break;
597 default:
598 LOG(ERROR) << "Unknown gesture property type: " << property->type();
599 NOTREACHED();
600 break;
602 return os;
605 namespace ui {
606 namespace internal {
608 // Mapping table from a property name to its corresponding GesturesProp
609 // object pointer.
610 typedef base::hash_map<std::string, GesturesProp*> PropertiesMap;
611 typedef base::ScopedPtrHashMap<std::string, scoped_ptr<GesturesProp>>
612 ScopedPropertiesMap;
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
619 // don't want to do.
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 {
635 public:
636 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr;
637 explicit MatchCriteria(const std::string& arg);
638 virtual ~MatchCriteria() {}
639 virtual bool Match(const DevicePtr device) = 0;
641 protected:
642 std::vector<std::string> args_;
645 // Match a device based on its evdev name string.
646 class MatchProduct : public MatchCriteria {
647 public:
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 {
655 public:
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 {
664 public:
665 explicit MatchUSBID(const std::string& arg);
666 ~MatchUSBID() override {}
667 bool Match(const DevicePtr device) override;
669 private:
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 {
677 public:
678 explicit MatchDeviceType(const std::string& arg);
679 ~MatchDeviceType() override {}
681 protected:
682 bool value_;
683 bool is_valid_;
686 // Check if a device is a pointer device.
687 class MatchIsPointer : public MatchDeviceType {
688 public:
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 {
696 public:
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 {
704 public:
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_);
723 if (args_.empty()) {
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) {
733 if (args_.empty())
734 return true;
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)
738 return true;
739 return false;
742 MatchDevicePath::MatchDevicePath(const std::string& arg) : MatchCriteria(arg) {
745 bool MatchDevicePath::Match(const DevicePtr device) {
746 if (args_.empty())
747 return true;
749 // Check if the device path matches any pattern.
750 std::string path = GetDeviceNodePath(device);
751 if (path.empty())
752 return false;
753 for (size_t i = 0; i < args_.size(); ++i)
754 if (fnmatch(args_[i].c_str(), path.c_str(), FNM_NOESCAPE) == 0)
755 return true;
756 return false;
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];
764 continue;
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
773 << "\"";
777 bool MatchUSBID::Match(const DevicePtr device) {
778 if (vid_patterns_.empty())
779 return true;
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) {
785 return true;
788 return false;
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.
807 if (args_.empty())
808 args_.push_back("on");
810 // We care only about the first argument.
811 int value = ParseBooleanKeyword(args_[0]);
812 if (value) {
813 is_valid_ = true;
814 value_ = value > 0;
816 if (!is_valid_) {
817 LOG(ERROR)
818 << "No valid device class boolean keyword found, will be ignored: \""
819 << arg << "\"";
823 MatchIsPointer::MatchIsPointer(const std::string& arg) : MatchDeviceType(arg) {
826 bool MatchIsPointer::Match(const DevicePtr device) {
827 if (!is_valid_)
828 return true;
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) {
838 if (!is_valid_)
839 return true;
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) {
848 if (!is_valid_)
849 return true;
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))
856 return false;
857 return true;
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) {
872 bool exists = false;
873 DeviceMap::const_iterator it = device_map_.begin();
874 for (; it != device_map_.end(); ++it) {
875 if (IsDeviceIdOfType(it->first, type)) {
876 exists = true;
877 if (device_ids)
878 device_ids->push_back(it->first);
881 return exists;
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())
888 return false;
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);
903 if (!device_data)
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);
912 return names;
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())
927 return;
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);
937 return;
940 void GesturePropertyProvider::UnregisterDevice(const DeviceId id) {
941 DeviceMap::const_iterator it = device_map_.find(id);
942 if (it == device_map_.end())
943 return;
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);
956 if (device_data)
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);
964 if (device_data)
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);
972 if (!device_data)
973 return NULL;
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);
982 if (!device_data)
983 return NULL;
984 internal::PropertiesMap::const_iterator ib =
985 device_data->default_properties.find(name);
986 if (ib == device_data->default_properties.end())
987 return NULL;
988 return ib->second;
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),
995 false,
996 base::FileEnumerator::FILES,
997 "*.conf");
998 for (base::FilePath path = file_enum.Next(); !path.empty();
999 path = file_enum.Next()) {
1000 files.insert(path);
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();
1007 ++file_iter) {
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();
1013 continue;
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
1022 // ones are:
1023 // 1. All keywords and names are now case-sensitive. Also, underscores are not
1024 // ignored.
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", &sections);
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.
1050 if (line.empty())
1051 continue;
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.
1068 if (piece.empty())
1069 continue;
1071 // See if we are currently parsing an entry or are still looking for
1072 // one.
1073 if (is_parsing) {
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();
1078 has_error = true;
1079 if (next_is_section_type)
1080 is_input_class_section = false;
1081 break;
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
1086 // the entry type.
1087 std::string arg;
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") {
1093 has_error = true;
1094 is_input_class_section = false;
1095 } else {
1096 DVLOG(2) << "New InputClass section found";
1097 has_checked_section_type = true;
1099 break;
1100 } else if (next_is_identifier) {
1101 DVLOG(2) << "Identifier: " << arg;
1102 config->identifier = arg;
1103 next_is_identifier = false;
1104 break;
1105 } else if (next_is_option_name) {
1106 // TODO(sheckylin): Support option "Ignore".
1107 option_name = arg;
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);
1112 if (property)
1113 config->properties.push_back(property);
1114 next_is_option_value = false;
1115 break;
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);
1121 if (criteria)
1122 config->criterias.push_back(criteria);
1124 next_is_match_criteria = false;
1125 break;
1127 } else {
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.
1133 break;
1134 } else if (piece == "Identifier") {
1135 is_parsing = true;
1136 next_is_identifier = true;
1137 continue;
1138 } else if (piece == "Option") {
1139 is_parsing = true;
1140 next_is_option_name = true;
1141 continue;
1142 } else if (piece.size() > 5 && piece.compare(0, 5, "Match") == 0) {
1143 match_type = piece;
1144 is_parsing = true;
1145 next_is_match_criteria = true;
1146 continue;
1148 } else if (piece == "Section") {
1149 is_parsing = true;
1150 next_is_section_type = true;
1151 continue;
1154 // If none of the above is found, check if the current piece starts a
1155 // comment.
1156 if (piece.empty() || piece[0] != '#') {
1157 LOG(ERROR) << "Error parsing line: " << lines.token();
1158 has_error = true;
1160 break;
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");
1168 if (property)
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");
1174 if (criteria)
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);
1204 NOTREACHED();
1205 return NULL;
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());
1232 if (token.empty())
1233 continue;
1235 // Check if it is a boolean keyword.
1236 int bool_result = ParseBooleanKeyword(token);
1237 if (bool_result) {
1238 numbers.push_back(bool_result > 0);
1239 continue;
1242 // Check if it is a number.
1243 double real_result;
1244 bool success = base::StringToDouble(token, &real_result);
1245 if (!success) {
1246 is_all_numeric = false;
1247 break;
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);
1258 } else {
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.
1265 return property;
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
1279 << "\" is matched";
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,
1291 const char* name,
1292 int* value,
1293 size_t count,
1294 const int* init) {
1295 return CreateProperty<int, GesturesIntProp>(
1296 device_data, name, value, count, init);
1299 GesturesProp* GesturesPropFunctionsWrapper::CreateShort(void* device_data,
1300 const char* name,
1301 short* value,
1302 size_t count,
1303 const short* init) {
1304 return CreateProperty<short, GesturesShortProp>(
1305 device_data, name, value, count, init);
1308 GesturesProp* GesturesPropFunctionsWrapper::CreateBool(
1309 void* device_data,
1310 const char* name,
1311 GesturesPropBool* value,
1312 size_t count,
1313 const GesturesPropBool* init) {
1314 return CreateProperty<GesturesPropBool, GesturesBoolProp>(
1315 device_data, name, value, count, init);
1318 GesturesProp* GesturesPropFunctionsWrapper::CreateReal(void* device_data,
1319 const char* name,
1320 double* value,
1321 size_t count,
1322 const double* init) {
1323 return CreateProperty<double, GesturesDoubleProp>(
1324 device_data, name, value, count, init);
1327 GesturesProp* GesturesPropFunctionsWrapper::CreateString(void* device_data,
1328 const char* name,
1329 const char** value,
1330 const char* init) {
1331 GesturesProp* default_property = NULL;
1332 if (!PreCreateProperty(device_data, name, &default_property))
1333 return NULL;
1334 GesturesProp* property =
1335 new GesturesStringProp(name, value, init, default_property);
1337 PostCreateProperty(device_data, name, property);
1338 return property;
1341 void GesturesPropFunctionsWrapper::RegisterHandlers(
1342 void* device_data,
1343 GesturesProp* property,
1344 void* handler_data,
1345 GesturesPropGetHandler get,
1346 GesturesPropSetHandler set) {
1347 // Sanity checks
1348 if (!device_data || !property)
1349 return;
1351 property->SetHandlers(get, set, handler_data);
1354 void GesturesPropFunctionsWrapper::Free(void* device_data,
1355 GesturesProp* property) {
1356 if (!property)
1357 return;
1358 GesturePropertyProvider* provider = GetPropertyProvider(device_data);
1360 // No need to manually delete the prop pointer as it is implicitly handled
1361 // with scoped ptr.
1362 DVLOG(3) << "Freeing Property: \"" << property->name() << "\"";
1363 provider->DeleteProperty(GetDeviceId(device_data), property->name());
1366 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties(
1367 void* device_data,
1368 GestureDeviceProperties* properties) {
1369 if (!device_data)
1370 return false;
1371 GesturePropertyProvider::DevicePtr device = GetDevicePointer(device_data);
1373 /* Create Device Properties */
1375 // Read Only properties.
1376 CreateString(
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,
1386 "Active Area Left",
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,
1394 "Active Area Top",
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",
1406 &properties->res_y,
1407 Event_Get_Res_Y(device));
1408 CreateIntSingle(device_data,
1409 "Horizontal Resolution",
1410 &properties->res_x,
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
1425 // set.
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
1432 // to upper layers.
1433 CreateBoolSingle(device_data,
1434 "Raw Touch Passthrough",
1435 &properties->raw_passthrough,
1436 false);
1437 return true;
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,
1447 const char* name,
1448 T* value,
1449 size_t count,
1450 const T* init) {
1451 // Create the property. Use the default property value if possible.
1452 GesturesProp* default_property = NULL;
1453 if (!PreCreateProperty(device_data, name, &default_property))
1454 return NULL;
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);
1460 return property;
1463 bool GesturesPropFunctionsWrapper::PreCreateProperty(
1464 void* device_data,
1465 const char* name,
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).
1480 if (property) {
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);
1488 return true;
1491 void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data,
1492 const char* name,
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,
1504 const char* name,
1505 int* value,
1506 int init) {
1507 return CreateInt(device_data, name, value, 1, &init);
1510 GesturesProp* GesturesPropFunctionsWrapper::CreateBoolSingle(
1511 void* device_data,
1512 const char* name,
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.
1538 * */
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};
1548 } // namespace ui