| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h" |
| |
| #include <gestures/gestures.h> |
| #include <libevdev/libevdev.h> |
| |
| #include <fnmatch.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <algorithm> |
| #include <iostream> |
| #include <vector> |
| |
| #include "base/basictypes.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_tokenizer.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringize_macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h" |
| |
| // Severity level for general info logging purpose. |
| #define GPROP_LOG DVLOG |
| #define INFO_SEVERITY 1 |
| |
| /* Implementation of GesturesProp declared in gestures.h |
| * |
| * libgestures requires that this be in the top level namespace. |
| * */ |
| class GesturesProp { |
| public: |
| typedef ui::GesturePropertyProvider::PropertyType PropertyType; |
| |
| GesturesProp(const std::string& name, |
| const PropertyType type, |
| const size_t count) |
| : name_(name), |
| type_(type), |
| count_(count), |
| get_(NULL), |
| set_(NULL), |
| handler_data_(NULL) {} |
| virtual ~GesturesProp() {} |
| |
| // Variant-ish interfaces for accessing the property value. Each type of |
| // property should override the corresponding interfaces for it. |
| virtual std::vector<int> GetIntValue() const { |
| NOTREACHED(); |
| return std::vector<int>(); |
| } |
| virtual bool SetIntValue(const std::vector<int>& value) { |
| NOTREACHED(); |
| return false; |
| } |
| virtual std::vector<int16_t> GetShortValue() const { |
| NOTREACHED(); |
| return std::vector<int16_t>(); |
| } |
| virtual bool SetShortValue(const std::vector<int16_t>& value) { |
| NOTREACHED(); |
| return false; |
| } |
| virtual std::vector<bool> GetBoolValue() const { |
| NOTREACHED(); |
| return std::vector<bool>(); |
| } |
| virtual bool SetBoolValue(const std::vector<bool>& value) { |
| NOTREACHED(); |
| return false; |
| } |
| virtual std::string GetStringValue() const { |
| NOTREACHED(); |
| return std::string(); |
| } |
| virtual bool SetStringValue(const std::string& value) { |
| NOTREACHED(); |
| return false; |
| } |
| virtual std::vector<double> GetDoubleValue() const { |
| NOTREACHED(); |
| return std::vector<double>(); |
| } |
| virtual bool SetDoubleValue(const std::vector<double>& value) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| // Set property access handlers. |
| void SetHandlers(GesturesPropGetHandler get, |
| GesturesPropSetHandler set, |
| void* data) { |
| get_ = get; |
| set_ = set; |
| handler_data_ = data; |
| } |
| |
| // Accessors. |
| const std::string& name() const { return name_; } |
| PropertyType type() const { return type_; } |
| size_t count() const { return count_; } |
| virtual bool IsReadOnly() const = 0; |
| |
| protected: |
| void OnGet() const { |
| // We don't have the X server now so there is currently nothing to do when |
| // the get handler returns true. |
| // TODO(sheckylin): Re-visit this if we use handlers that modifies the |
| // property. |
| if (get_) |
| get_(handler_data_); |
| } |
| |
| void OnSet() const { |
| // Call the property set handler if available. |
| if (set_) |
| set_(handler_data_); |
| } |
| |
| private: |
| // For logging purpose. |
| friend std::ostream& operator<<(std::ostream& os, |
| const GesturesProp& property); |
| |
| // Interfaces for getting internal pointers and stuff. |
| virtual const char** GetStringWritebackPtr() const { |
| NOTREACHED(); |
| return NULL; |
| } |
| virtual bool IsAllocated() const { |
| NOTREACHED(); |
| return false; |
| } |
| |
| // Property name, type and number of elements. |
| std::string name_; |
| PropertyType type_; |
| size_t count_; |
| |
| // Handler function pointers and the data to be passed to them when the |
| // property is accessed. |
| GesturesPropGetHandler get_; |
| GesturesPropSetHandler set_; |
| void* handler_data_; |
| |
| DISALLOW_COPY_AND_ASSIGN(GesturesProp); |
| }; |
| |
| template <typename T> |
| class TypedGesturesProp : public GesturesProp { |
| public: |
| TypedGesturesProp(const std::string& name, |
| const PropertyType type, |
| const size_t count, |
| T* value) |
| : GesturesProp(name, type, count), |
| value_(value), |
| is_read_only_(false), |
| is_allocated_(false) { |
| Init(); |
| } |
| ~TypedGesturesProp() override { |
| if (is_allocated_) |
| delete[] value_; |
| } |
| |
| // Accessors. |
| bool IsReadOnly() const override { return is_read_only_; } |
| |
| protected: |
| // Functions for setting/getting numerical properties. |
| // |
| // These two functions calls the set/get handler and should only be used in |
| // Get*Value/Set*Value functions. |
| template <typename U> |
| std::vector<U> GetNumericalPropertyValue() const { |
| // Nothing should be modified so it is OK to call the get handler first. |
| OnGet(); |
| return this->template GetNumericalValue<U>(); |
| } |
| |
| template <typename U> |
| bool SetNumericalPropertyValue(const std::vector<U>& value) { |
| // Set the value only if not read-only and the vector size matches. |
| // |
| // As per the legacy guideline, all read-only properties (created with NULL) |
| // can't be modified. If we want to change this in the future, re-think |
| // about the different cases here (e.g., should we allow setting an array |
| // value of different size?). |
| if (is_read_only_ || value.size() != count()) |
| return false; |
| bool ret = this->template SetNumericalValue(value); |
| OnSet(); |
| return ret; |
| } |
| |
| // Initialize a numerical property's value. Note that a (numerical) default |
| // property's value is always stored in double. |
| void InitializeNumericalProperty(const T* init, |
| const GesturesProp* default_property) { |
| if (IsDefaultPropertyUsable(default_property)) { |
| GPROP_LOG(INFO_SEVERITY) << "Default property found. Using its value ..."; |
| this->template SetNumericalValue(default_property->GetDoubleValue()); |
| } else { |
| // To work with the interface exposed by the gesture lib, we have no |
| // choice but to trust that the init array has sufficient size. |
| std::vector<T> temp(init, init + count()); |
| this->template SetNumericalValue(temp); |
| } |
| } |
| |
| // Data pointer. |
| T* value_; |
| |
| // If the flag is on, it means the GesturesProp is created by passing a NULL |
| // data pointer to the creator functions. We define the property as a |
| // read-only one and that no value change will be allowed for it. Note that |
| // the flag is different from is_allocated in that StringProperty will always |
| // allocate no matter it is created with NULL or not. |
| bool is_read_only_; |
| |
| private: |
| // Initialize the object. |
| void Init() { |
| // If no external data pointer is passed, we have to create our own. |
| if (!value_) { |
| value_ = new T[GesturesProp::count()]; |
| is_read_only_ = true; |
| is_allocated_ = true; |
| } |
| } |
| |
| // Low-level functions for setting/getting numerical properties. |
| template <typename U> |
| std::vector<U> GetNumericalValue() const { |
| // We do type-casting because the numerical types may not totally match. |
| // For example, we store bool as GesturesPropBool to be compatible with the |
| // gesture library. Also, all parsed xorg-conf property values are stored |
| // as double because we can't identify their original type lexically. |
| // TODO(sheckylin): Handle value out-of-range (e.g., double to int). |
| std::vector<U> result(count()); |
| for (size_t i = 0; i < count(); ++i) |
| result[i] = static_cast<U>(value_[i]); |
| return result; |
| } |
| |
| template <typename U> |
| bool SetNumericalValue(const std::vector<U>& value) { |
| for (size_t i = 0; i < count(); ++i) |
| value_[i] = static_cast<T>(value[i]); |
| return true; |
| } |
| |
| // Check if a default property usable for (numerical) initialization. |
| bool IsDefaultPropertyUsable(const GesturesProp* default_property) const { |
| // We currently assumed that we won't specify any array property in the |
| // configuration files. The code needs to be updated if the assumption |
| // becomes invalid in the future. |
| return (count() == 1 && default_property && |
| default_property->type() != PropertyType::PT_STRING); |
| } |
| |
| // Accessors. |
| bool IsAllocated() const override { return is_allocated_; } |
| |
| // If the flag is on, it means the memory that the data pointer points to is |
| // allocated here. We will need to free the memory by ourselves when the |
| // GesturesProp is destroyed. |
| bool is_allocated_; |
| }; |
| |
| class GesturesIntProp : public TypedGesturesProp<int> { |
| public: |
| GesturesIntProp(const std::string& name, |
| const size_t count, |
| int* value, |
| const int* init, |
| const GesturesProp* default_property) |
| : TypedGesturesProp<int>(name, PropertyType::PT_INT, count, value) { |
| InitializeNumericalProperty(init, default_property); |
| } |
| std::vector<int> GetIntValue() const override { |
| return this->template GetNumericalPropertyValue<int>(); |
| } |
| bool SetIntValue(const std::vector<int>& value) override { |
| return this->template SetNumericalPropertyValue(value); |
| } |
| }; |
| |
| class GesturesShortProp : public TypedGesturesProp<short> { |
| public: |
| GesturesShortProp(const std::string& name, |
| const size_t count, |
| short* value, |
| const short* init, |
| const GesturesProp* default_property) |
| : TypedGesturesProp<short>(name, PropertyType::PT_SHORT, count, value) { |
| InitializeNumericalProperty(init, default_property); |
| } |
| std::vector<int16_t> GetShortValue() const override { |
| return this->template GetNumericalPropertyValue<int16_t>(); |
| } |
| bool SetShortValue(const std::vector<int16_t>& value) override { |
| return this->template SetNumericalPropertyValue(value); |
| } |
| }; |
| |
| class GesturesBoolProp : public TypedGesturesProp<GesturesPropBool> { |
| public: |
| GesturesBoolProp(const std::string& name, |
| const size_t count, |
| GesturesPropBool* value, |
| const GesturesPropBool* init, |
| const GesturesProp* default_property) |
| : TypedGesturesProp<GesturesPropBool>(name, |
| PropertyType::PT_BOOL, |
| count, |
| value) { |
| InitializeNumericalProperty(init, default_property); |
| } |
| std::vector<bool> GetBoolValue() const override { |
| return this->template GetNumericalPropertyValue<bool>(); |
| } |
| bool SetBoolValue(const std::vector<bool>& value) override { |
| return this->template SetNumericalPropertyValue(value); |
| } |
| }; |
| |
| class GesturesDoubleProp : public TypedGesturesProp<double> { |
| public: |
| GesturesDoubleProp(const std::string& name, |
| const size_t count, |
| double* value, |
| const double* init, |
| const GesturesProp* default_property) |
| : TypedGesturesProp<double>(name, PropertyType::PT_REAL, count, value) { |
| InitializeNumericalProperty(init, default_property); |
| } |
| std::vector<double> GetDoubleValue() const override { |
| return this->template GetNumericalPropertyValue<double>(); |
| } |
| bool SetDoubleValue(const std::vector<double>& value) override { |
| return this->template SetNumericalPropertyValue(value); |
| } |
| }; |
| |
| class GesturesStringProp : public TypedGesturesProp<std::string> { |
| public: |
| // StringProperty's memory is always allocated on this side instead of |
| // externally in the gesture lib as the original one will be destroyed right |
| // after the constructor call (check the design of StringProperty). To do |
| // this, we call the TypedGesturesProp constructor with NULL pointer so that |
| // it always allocates. |
| GesturesStringProp(const std::string& name, |
| const char** value, |
| const char* init, |
| const GesturesProp* default_property) |
| : TypedGesturesProp<std::string>(name, PropertyType::PT_STRING, 1, NULL), |
| write_back_(NULL) { |
| InitializeStringProperty(value, init, default_property); |
| } |
| std::string GetStringValue() const override { |
| OnGet(); |
| return *value_; |
| } |
| bool SetStringValue(const std::string& value) override { |
| if (is_read_only_) |
| return false; |
| *value_ = value; |
| |
| // Write back the pointer in case it may change (e.g., string |
| // re-allocation). |
| if (write_back_) |
| *(write_back_) = value_->c_str(); |
| OnSet(); |
| return true; |
| } |
| |
| private: |
| // Initialize the object. |
| void InitializeStringProperty(const char** value, |
| const char* init, |
| const GesturesProp* default_property) { |
| // Initialize the property value similar to the numerical types. |
| if (IsDefaultPropertyUsable(default_property)) { |
| GPROP_LOG(INFO_SEVERITY) << "Default property found. Using its value ..."; |
| *value_ = default_property->GetStringValue(); |
| } else { |
| *value_ = init; |
| } |
| |
| // If the provided pointer is not NULL, replace its content |
| // (val_ of StringProperty) with the address of our allocated string. |
| // Note that we don't have to do this for the other data types as they will |
| // use the original data pointer if possible and it is unnecessary to do so |
| // if the pointer is NULL. |
| if (value) { |
| *value = value_->c_str(); |
| write_back_ = value; |
| // Set the read-only flag back to false. |
| is_read_only_ = false; |
| } |
| } |
| |
| // Re-write the function with different criteria as we want string properties |
| // now. |
| bool IsDefaultPropertyUsable(const GesturesProp* default_property) const { |
| return (default_property && |
| default_property->type() == PropertyType::PT_STRING); |
| } |
| |
| const char** GetStringWritebackPtr() const override { return write_back_; } |
| |
| // In some cases, we don't directly use the data pointer provided by the |
| // creators due to its limitation and instead use our own types (e.g., in |
| // the case of string). We thus need to store the write back pointer so that |
| // we can update the value in the gesture lib if the property value gets |
| // changed. |
| const char** write_back_; |
| }; |
| |
| // Anonymous namespace for utility functions and internal constants. |
| namespace { |
| |
| // The path that we will look for conf files. |
| const char kConfigurationFilePath[] = "/etc/gesture"; |
| |
| // We support only match types that have already been used. One should change |
| // this if we start using new types in the future. Note that most unsupported |
| // match types are either useless in CrOS or inapplicable to the non-X |
| // environment. |
| const char* kSupportedMatchTypes[] = {"MatchProduct", |
| "MatchDevicePath", |
| "MatchUSBID", |
| "MatchIsPointer", |
| "MatchIsTouchpad", |
| "MatchIsTouchscreen"}; |
| const char* kUnsupportedMatchTypes[] = {"MatchVendor", |
| "MatchOS", |
| "MatchPnPID", |
| "MatchDriver", |
| "MatchTag", |
| "MatchLayout", |
| "MatchIsKeyboard", |
| "MatchIsJoystick", |
| "MatchIsTablet"}; |
| |
| // Special keywords for boolean values. |
| const char* kTrue[] = {"on", "true", "yes"}; |
| const char* kFalse[] = {"off", "false", "no"}; |
| |
| // Check if a device falls into one device type category. |
| bool IsDeviceOfType(const ui::GesturePropertyProvider::DevicePtr device, |
| const ui::GesturePropertyProvider::DeviceType type) { |
| EvdevClass evdev_class = device->info.evdev_class; |
| switch (type) { |
| case ui::GesturePropertyProvider::DT_MOUSE: |
| return (evdev_class == EvdevClassMouse || |
| evdev_class == EvdevClassMultitouchMouse); |
| break; |
| case ui::GesturePropertyProvider::DT_TOUCHPAD: |
| // Note that the behavior here is different from the inputcontrol script |
| // which actually returns touchscreen devices as well. |
| return (evdev_class == EvdevClassTouchpad); |
| break; |
| case ui::GesturePropertyProvider::DT_TOUCHSCREEN: |
| return (evdev_class == EvdevClassTouchscreen); |
| break; |
| case ui::GesturePropertyProvider::DT_MULTITOUCH: |
| return (evdev_class == EvdevClassTouchpad || |
| evdev_class == EvdevClassTouchscreen || |
| evdev_class == EvdevClassMultitouchMouse); |
| break; |
| case ui::GesturePropertyProvider::DT_MULTITOUCH_MOUSE: |
| return (evdev_class == EvdevClassMultitouchMouse); |
| break; |
| case ui::GesturePropertyProvider::DT_ALL: |
| return true; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return false; |
| } |
| |
| // Trick to get the device path from a file descriptor. |
| std::string GetDeviceNodePath( |
| const ui::GesturePropertyProvider::DevicePtr device) { |
| std::string proc_symlink = "/proc/self/fd/" + base::IntToString(device->fd); |
| base::FilePath path; |
| if (!base::ReadSymbolicLink(base::FilePath(proc_symlink), &path)) |
| return std::string(); |
| return path.value(); |
| } |
| |
| // Check if a match criteria is currently implemented. Note that we didn't |
| // implemented all of them as some are inapplicable in the non-X world. |
| bool IsMatchTypeSupported(const std::string& match_type) { |
| for (size_t i = 0; i < arraysize(kSupportedMatchTypes); ++i) |
| if (match_type == kSupportedMatchTypes[i]) |
| return true; |
| for (size_t i = 0; i < arraysize(kUnsupportedMatchTypes); ++i) { |
| if (match_type == kUnsupportedMatchTypes[i]) { |
| LOG(ERROR) << "Unsupported gestures input class match type: " |
| << match_type; |
| return false; |
| } |
| } |
| return false; |
| } |
| |
| // Check if a match criteria is a device type one. |
| bool IsMatchDeviceType(const std::string& match_type) { |
| return StartsWithASCII(match_type, "MatchIs", true); |
| } |
| |
| // Parse a boolean value keyword (e.g., on/off, true/false). |
| int ParseBooleanKeyword(const std::string& value) { |
| for (size_t i = 0; i < arraysize(kTrue); ++i) |
| if (LowerCaseEqualsASCII(value, kTrue[i])) |
| return 1; |
| for (size_t i = 0; i < arraysize(kFalse); ++i) |
| if (LowerCaseEqualsASCII(value, kFalse[i])) |
| return -1; |
| return 0; |
| } |
| |
| // Log the value of an array property. |
| template <typename T> |
| void LogArrayProperty(std::ostream& os, const std::vector<T>& value) { |
| os << "("; |
| for (size_t i = 0; i < value.size(); ++i) { |
| if (i > 0) |
| os << ", "; |
| os << value[i]; |
| } |
| os << ")"; |
| } |
| |
| // Property type logging function. |
| std::ostream& operator<<(std::ostream& out, |
| const ui::GesturePropertyProvider::PropertyType type) { |
| std::string s; |
| #define TYPE_CASE(TYPE) \ |
| case (ui::GesturePropertyProvider::TYPE): \ |
| s = #TYPE; \ |
| break; |
| switch (type) { |
| TYPE_CASE(PT_INT); |
| TYPE_CASE(PT_SHORT); |
| TYPE_CASE(PT_BOOL); |
| TYPE_CASE(PT_STRING); |
| TYPE_CASE(PT_REAL); |
| default: |
| NOTREACHED(); |
| break; |
| } |
| #undef TYPE_CASE |
| return out << s; |
| } |
| |
| } // namespace |
| |
| // GesturesProp logging function. |
| std::ostream& operator<<(std::ostream& os, const GesturesProp& prop) { |
| const GesturesProp* property = ∝ |
| |
| // Output the property content. |
| os << "\"" << property->name() << "\", " << property->type() << ", " |
| << property->count() << ", (" << property->IsAllocated() << ", " |
| << property->IsReadOnly() << "), "; |
| |
| // Only the string property has the write back pointer. |
| if (property->type() == ui::GesturePropertyProvider::PT_STRING) |
| os << property->GetStringWritebackPtr(); |
| else |
| os << "NULL"; |
| |
| // Output the property values. |
| os << ", "; |
| switch (property->type()) { |
| case ui::GesturePropertyProvider::PT_INT: |
| LogArrayProperty(os, property->GetIntValue()); |
| break; |
| case ui::GesturePropertyProvider::PT_SHORT: |
| LogArrayProperty(os, property->GetShortValue()); |
| break; |
| case ui::GesturePropertyProvider::PT_BOOL: |
| LogArrayProperty(os, property->GetBoolValue()); |
| break; |
| case ui::GesturePropertyProvider::PT_STRING: |
| os << "\"" << property->GetStringValue() << "\""; |
| break; |
| case ui::GesturePropertyProvider::PT_REAL: |
| LogArrayProperty(os, property->GetDoubleValue()); |
| break; |
| default: |
| LOG(ERROR) << "Unknown gesture property type: " << property->type(); |
| NOTREACHED(); |
| break; |
| } |
| return os; |
| } |
| |
| namespace ui { |
| namespace internal { |
| |
| // Mapping table from a property name to its corresponding GesturesProp |
| // object pointer. |
| typedef base::hash_map<std::string, GesturesProp*> PropertiesMap; |
| typedef base::ScopedPtrHashMap<std::string, GesturesProp> ScopedPropertiesMap; |
| |
| // Struct holding properties of a device. |
| // |
| // Note that we can't define it in GesturePropertyProvider as a nested class |
| // because ScopedPtrHashMap will require us to expose the GestureProp's |
| // destructor so that it can instantiate the object. This is something we |
| // don't want to do. |
| struct GestureDevicePropertyData { |
| GestureDevicePropertyData() {} |
| |
| // Properties owned and being used by the device. |
| ScopedPropertiesMap properties; |
| |
| // Unowned default properties (owned by the configuration file). Their values |
| // will be applied when a property of the same name is created. These are |
| // usually only a small portion of all properties in use. |
| PropertiesMap default_properties; |
| }; |
| |
| // Base class for device match criterias in conf files. |
| // Check the xorg-conf spec for more detailed information. |
| class MatchCriteria { |
| public: |
| typedef ui::GesturePropertyProvider::DevicePtr DevicePtr; |
| explicit MatchCriteria(const std::string& arg); |
| virtual ~MatchCriteria() {} |
| virtual bool Match(const DevicePtr device) = 0; |
| |
| protected: |
| std::vector<std::string> args_; |
| }; |
| |
| // Match a device based on its evdev name string. |
| class MatchProduct : public MatchCriteria { |
| public: |
| explicit MatchProduct(const std::string& arg); |
| virtual ~MatchProduct() {} |
| virtual bool Match(const DevicePtr device); |
| }; |
| |
| // Math a device based on its device node path. |
| class MatchDevicePath : public MatchCriteria { |
| public: |
| explicit MatchDevicePath(const std::string& arg); |
| virtual ~MatchDevicePath() {} |
| virtual bool Match(const DevicePtr device); |
| }; |
| |
| // Math a USB device based on its USB vid and pid. |
| // Mostly used for external mice and touchpads. |
| class MatchUSBID : public MatchCriteria { |
| public: |
| explicit MatchUSBID(const std::string& arg); |
| virtual ~MatchUSBID() {} |
| virtual bool Match(const DevicePtr device); |
| |
| private: |
| bool IsValidPattern(const std::string& pattern); |
| std::vector<std::string> vid_patterns_; |
| std::vector<std::string> pid_patterns_; |
| }; |
| |
| // Generic base class for device type math criteria. |
| class MatchDeviceType : public MatchCriteria { |
| public: |
| explicit MatchDeviceType(const std::string& arg); |
| virtual ~MatchDeviceType() {} |
| virtual bool Match(const DevicePtr device) = 0; |
| |
| protected: |
| bool value_; |
| bool is_valid_; |
| }; |
| |
| // Check if a device is a pointer device. |
| class MatchIsPointer : public MatchDeviceType { |
| public: |
| explicit MatchIsPointer(const std::string& arg); |
| virtual ~MatchIsPointer() {} |
| virtual bool Match(const DevicePtr device); |
| }; |
| |
| // Check if a device is a touchpad. |
| class MatchIsTouchpad : public MatchDeviceType { |
| public: |
| explicit MatchIsTouchpad(const std::string& arg); |
| virtual ~MatchIsTouchpad() {} |
| virtual bool Match(const DevicePtr device); |
| }; |
| |
| // Check if a device is a touchscreen. |
| class MatchIsTouchscreen : public MatchDeviceType { |
| public: |
| explicit MatchIsTouchscreen(const std::string& arg); |
| virtual ~MatchIsTouchscreen() {} |
| virtual bool Match(const DevicePtr device); |
| }; |
| |
| // Struct for sections in xorg conf files. |
| struct ConfigurationSection { |
| typedef ui::GesturePropertyProvider::DevicePtr DevicePtr; |
| ConfigurationSection() {} |
| bool Match(const DevicePtr device); |
| std::string identifier; |
| ScopedVector<MatchCriteria> criterias; |
| ScopedVector<GesturesProp> properties; |
| }; |
| |
| MatchCriteria::MatchCriteria(const std::string& arg) { |
| // TODO(sheckylin): Should we trim all tokens here? |
| Tokenize(arg, "|", &args_); |
| if (args_.empty()) { |
| LOG(ERROR) << "Empty match pattern found, will evaluate to the default " |
| "value (true): \"" << arg << "\""; |
| } |
| } |
| |
| MatchProduct::MatchProduct(const std::string& arg) : MatchCriteria(arg) { |
| } |
| |
| bool MatchProduct::Match(const DevicePtr device) { |
| if (args_.empty()) |
| return true; |
| std::string name(device->info.name); |
| for (size_t i = 0; i < args_.size(); ++i) |
| if (name.find(args_[i]) != std::string::npos) |
| return true; |
| return false; |
| } |
| |
| MatchDevicePath::MatchDevicePath(const std::string& arg) : MatchCriteria(arg) { |
| } |
| |
| bool MatchDevicePath::Match(const DevicePtr device) { |
| if (args_.empty()) |
| return true; |
| |
| // Check if the device path matches any pattern. |
| std::string path = GetDeviceNodePath(device); |
| if (path.empty()) |
| return false; |
| for (size_t i = 0; i < args_.size(); ++i) |
| if (fnmatch(args_[i].c_str(), path.c_str(), FNM_NOESCAPE) == 0) |
| return true; |
| return false; |
| } |
| |
| MatchUSBID::MatchUSBID(const std::string& arg) : MatchCriteria(arg) { |
| // Check each pattern and split valid ones into vids and pids. |
| for (size_t i = 0; i < args_.size(); ++i) { |
| if (!IsValidPattern(args_[i])) { |
| LOG(ERROR) << "Invalid USB ID: " << args_[i]; |
| continue; |
| } |
| std::vector<std::string> tokens; |
| base::SplitString(args_[i], ':', &tokens); |
| vid_patterns_.push_back(base::StringToLowerASCII(tokens[0])); |
| pid_patterns_.push_back(base::StringToLowerASCII(tokens[1])); |
| } |
| if (vid_patterns_.empty()) { |
| LOG(ERROR) << "No valid USB ID pattern found, will be ignored: \"" << arg |
| << "\""; |
| } |
| } |
| |
| bool MatchUSBID::Match(const DevicePtr device) { |
| if (vid_patterns_.empty()) |
| return true; |
| std::string vid = base::StringPrintf("%04x", device->info.id.vendor); |
| std::string pid = base::StringPrintf("%04x", device->info.id.product); |
| for (size_t i = 0; i < vid_patterns_.size(); ++i) { |
| if (fnmatch(vid_patterns_[i].c_str(), vid.c_str(), FNM_NOESCAPE) == 0 && |
| fnmatch(pid_patterns_[i].c_str(), pid.c_str(), FNM_NOESCAPE) == 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool MatchUSBID::IsValidPattern(const std::string& pattern) { |
| // Each USB id should be in the lsusb format, i.e., xxxx:xxxx. We choose to do |
| // a lazy check here: if the pattern contains wrong characters not in the hex |
| // number range, it won't be matched anyway. |
| int number_of_colons = 0; |
| size_t pos_of_colon = 0; |
| for (size_t i = 0; i < pattern.size(); ++i) |
| if (pattern[i] == ':') |
| ++number_of_colons, pos_of_colon = i; |
| return (number_of_colons == 1) && (pos_of_colon != 0) && |
| (pos_of_colon != pattern.size() - 1); |
| } |
| |
| MatchDeviceType::MatchDeviceType(const std::string& arg) |
| : MatchCriteria(arg), value_(true), is_valid_(false) { |
| // Default value of a match criteria is true. |
| if (args_.empty()) |
| args_.push_back("on"); |
| |
| // We care only about the first argument. |
| int value = ParseBooleanKeyword(args_[0]); |
| if (value) { |
| is_valid_ = true; |
| value_ = value > 0; |
| } |
| if (!is_valid_) { |
| LOG(ERROR) |
| << "No valid device class boolean keyword found, will be ignored: \"" |
| << arg << "\""; |
| } |
| } |
| |
| MatchIsPointer::MatchIsPointer(const std::string& arg) : MatchDeviceType(arg) { |
| } |
| |
| bool MatchIsPointer::Match(const DevicePtr device) { |
| if (!is_valid_) |
| return true; |
| return (value_ == (device->info.evdev_class == EvdevClassMouse || |
| device->info.evdev_class == EvdevClassMultitouchMouse)); |
| } |
| |
| MatchIsTouchpad::MatchIsTouchpad(const std::string& arg) |
| : MatchDeviceType(arg) { |
| } |
| |
| bool MatchIsTouchpad::Match(const DevicePtr device) { |
| if (!is_valid_) |
| return true; |
| return (value_ == (device->info.evdev_class == EvdevClassTouchpad)); |
| } |
| |
| MatchIsTouchscreen::MatchIsTouchscreen(const std::string& arg) |
| : MatchDeviceType(arg) { |
| } |
| |
| bool MatchIsTouchscreen::Match(const DevicePtr device) { |
| if (!is_valid_) |
| return true; |
| return (value_ == (device->info.evdev_class == EvdevClassTouchscreen)); |
| } |
| |
| bool ConfigurationSection::Match(DevicePtr device) { |
| for (size_t i = 0; i < criterias.size(); ++i) |
| if (!criterias[i]->Match(device)) |
| return false; |
| return true; |
| } |
| |
| } // namespace internal |
| |
| GesturePropertyProvider::GesturePropertyProvider() { |
| LoadDeviceConfigurations(); |
| } |
| |
| GesturePropertyProvider::~GesturePropertyProvider() { |
| } |
| |
| void GesturePropertyProvider::GetDeviceIdsByType( |
| const DeviceType type, |
| std::vector<DeviceId>* device_ids) { |
| device_ids->clear(); |
| DeviceMap::const_iterator it = device_map_.begin(); |
| for (; it != device_map_.end(); ++it) |
| if (IsDeviceOfType(it->second, type)) |
| device_ids->push_back(it->first); |
| } |
| |
| GesturesProp* GesturePropertyProvider::GetProperty(const DeviceId device_id, |
| const std::string& name) { |
| return FindProperty(device_id, name); |
| } |
| |
| void GesturePropertyProvider::RegisterDevice(const DeviceId id, |
| const DevicePtr device) { |
| DeviceMap::const_iterator it = device_map_.find(id); |
| if (it != device_map_.end()) |
| return; |
| |
| // Setup data-structures. |
| device_map_[id] = device; |
| device_data_map_.set(id, |
| scoped_ptr<internal::GestureDevicePropertyData>( |
| new internal::GestureDevicePropertyData)); |
| |
| // Gather default property values for the device from the parsed conf files. |
| SetupDefaultProperties(id, device); |
| return; |
| } |
| |
| void GesturePropertyProvider::UnregisterDevice(const DeviceId id) { |
| DeviceMap::const_iterator it = device_map_.find(id); |
| if (it == device_map_.end()) |
| return; |
| device_data_map_.erase(id); |
| device_map_.erase(it); |
| } |
| |
| void GesturePropertyProvider::AddProperty(const DeviceId device_id, |
| const std::string& name, |
| GesturesProp* property) { |
| // The look-up should never fail because ideally a property can only be |
| // created with GesturesPropCreate* functions from the gesture lib side. |
| // Therefore, we simply return on failure. |
| internal::GestureDevicePropertyData* device_data = |
| device_data_map_.get(device_id); |
| if (device_data) |
| device_data->properties.set(name, scoped_ptr<GesturesProp>(property)); |
| } |
| |
| void GesturePropertyProvider::DeleteProperty(const DeviceId device_id, |
| const std::string& name) { |
| internal::GestureDevicePropertyData* device_data = |
| device_data_map_.get(device_id); |
| if (device_data) |
| device_data->properties.erase(name); |
| } |
| |
| GesturesProp* GesturePropertyProvider::FindProperty(const DeviceId device_id, |
| const std::string& name) { |
| internal::GestureDevicePropertyData* device_data = |
| device_data_map_.get(device_id); |
| if (!device_data) |
| return NULL; |
| return device_data->properties.get(name); |
| } |
| |
| GesturesProp* GesturePropertyProvider::GetDefaultProperty( |
| const DeviceId device_id, |
| const std::string& name) { |
| internal::GestureDevicePropertyData* device_data = |
| device_data_map_.get(device_id); |
| if (!device_data) |
| return NULL; |
| internal::PropertiesMap::const_iterator ib = |
| device_data->default_properties.find(name); |
| if (ib == device_data->default_properties.end()) |
| return NULL; |
| return ib->second; |
| } |
| |
| void GesturePropertyProvider::LoadDeviceConfigurations() { |
| // Enumerate conf files and sort them lexicographically. |
| std::set<base::FilePath> files; |
| base::FileEnumerator file_enum(base::FilePath(kConfigurationFilePath), |
| false, |
| base::FileEnumerator::FILES, |
| "*.conf"); |
| for (base::FilePath path = file_enum.Next(); !path.empty(); |
| path = file_enum.Next()) { |
| files.insert(path); |
| } |
| GPROP_LOG(INFO_SEVERITY) << files.size() << " conf files were found"; |
| |
| // Parse conf files one-by-one. |
| for (std::set<base::FilePath>::iterator file_iter = files.begin(); |
| file_iter != files.end(); |
| ++file_iter) { |
| GPROP_LOG(INFO_SEVERITY) << "Parsing conf file: " << (*file_iter).value(); |
| std::string content; |
| if (!base::ReadFileToString(*file_iter, &content)) { |
| LOG(ERROR) << "Can't loading gestures conf file: " |
| << (*file_iter).value(); |
| continue; |
| } |
| ParseXorgConfFile(content); |
| } |
| } |
| |
| void GesturePropertyProvider::ParseXorgConfFile(const std::string& content) { |
| // To simplify the parsing work, we made some assumption about the conf file |
| // format which doesn't exist in the original xorg-conf spec. Most important |
| // ones are: |
| // 1. All keywords and names are now case-sensitive. Also, underscores are not |
| // ignored. |
| // 2. Each entry takes up one and exactly one line in the file. |
| // 3. No negation of the option value even if the option name is prefixed with |
| // "No" as it may cause problems for option names that does start with "No" |
| // (e.g., "Non-linearity"). |
| |
| // Break the content into sections, lines and then pieces. |
| // Sections are delimited by the "EndSection" keyword. |
| // Lines are delimited by "\n". |
| // Pieces are delimited by all white-spaces. |
| std::vector<std::string> sections; |
| base::SplitStringUsingSubstr(content, "EndSection", §ions); |
| for (size_t i = 0; i < sections.size(); ++i) { |
| // Create a new configuration section. |
| configurations_.push_back(new internal::ConfigurationSection()); |
| internal::ConfigurationSection* config = configurations_.back(); |
| |
| // Break the section into lines. |
| base::StringTokenizer lines(sections[i], "\n"); |
| bool is_input_class_section = true; |
| bool has_checked_section_type = false; |
| while (is_input_class_section && lines.GetNext()) { |
| // Parse the line w.r.t. the xorg-conf format. |
| std::string line(lines.token()); |
| |
| // Skip empty lines. |
| if (line.empty()) |
| continue; |
| |
| // Treat all whitespaces as delimiters. |
| base::StringTokenizer pieces(line, base::kWhitespaceASCII); |
| pieces.set_quote_chars("\""); |
| bool is_parsing = false; |
| bool has_error = false; |
| bool next_is_section_type = false; |
| bool next_is_option_name = false; |
| bool next_is_option_value = false; |
| bool next_is_match_criteria = false; |
| bool next_is_identifier = false; |
| std::string match_type, option_name; |
| while (pieces.GetNext()) { |
| std::string piece(pieces.token()); |
| |
| // Skip empty pieces. |
| if (piece.empty()) |
| continue; |
| |
| // See if we are currently parsing an entry or are still looking for |
| // one. |
| if (is_parsing) { |
| // Stop parsing the current line if the format is wrong. |
| if (piece.size() <= 2 || piece[0] != '\"' || |
| piece[piece.size() - 1] != '\"') { |
| LOG(ERROR) << "Error parsing line: " << lines.token(); |
| has_error = true; |
| if (next_is_section_type) |
| is_input_class_section = false; |
| break; |
| } |
| |
| // Parse the arguments. Note that we don't break even if a whitespace |
| // string is passed. It will just be handled in various ways based on |
| // the entry type. |
| std::string arg; |
| base::TrimWhitespaceASCII( |
| piece.substr(1, piece.size() - 2), base::TRIM_ALL, &arg); |
| if (next_is_section_type) { |
| // We only care about InputClass sections. |
| if (arg != "InputClass") { |
| has_error = true; |
| is_input_class_section = false; |
| } else { |
| GPROP_LOG(INFO_SEVERITY) << "New InputClass section found"; |
| has_checked_section_type = true; |
| } |
| break; |
| } else if (next_is_identifier) { |
| GPROP_LOG(INFO_SEVERITY) << "Identifier: " << arg; |
| config->identifier = arg; |
| next_is_identifier = false; |
| break; |
| } else if (next_is_option_name) { |
| // TODO(sheckylin): Support option "Ignore". |
| option_name = arg; |
| next_is_option_value = true; |
| next_is_option_name = false; |
| } else if (next_is_option_value) { |
| GesturesProp* property = CreateDefaultProperty(option_name, arg); |
| if (property) |
| config->properties.push_back(property); |
| next_is_option_value = false; |
| break; |
| } else if (next_is_match_criteria) { |
| // Skip all match types that are not supported. |
| if (IsMatchTypeSupported(match_type)) { |
| internal::MatchCriteria* criteria = |
| CreateMatchCriteria(match_type, arg); |
| if (criteria) |
| config->criterias.push_back(criteria); |
| } |
| next_is_match_criteria = false; |
| break; |
| } |
| } else { |
| // If the section type hasn't been decided yet, look for it. |
| // Otherwise, look for valid entries according to the spec. |
| if (has_checked_section_type) { |
| if (piece == "Driver") { |
| // TODO(sheckylin): Support "Driver" so that we can force a device |
| // not to use the gesture lib. |
| NOTIMPLEMENTED(); |
| break; |
| } else if (piece == "Identifier") { |
| is_parsing = true; |
| next_is_identifier = true; |
| continue; |
| } else if (piece == "Option") { |
| is_parsing = true; |
| next_is_option_name = true; |
| continue; |
| } else if (piece.size() > 5 && piece.compare(0, 5, "Match") == 0) { |
| match_type = piece; |
| is_parsing = true; |
| next_is_match_criteria = true; |
| continue; |
| } |
| } else if (piece == "Section") { |
| is_parsing = true; |
| next_is_section_type = true; |
| continue; |
| } |
| |
| // If none of the above is found, check if the current piece starts a |
| // comment. |
| if (piece.empty() || piece[0] != '#') { |
| LOG(ERROR) << "Error parsing line: " << lines.token(); |
| has_error = true; |
| } |
| break; |
| } |
| } |
| |
| // The value of a boolean option is skipped (default is true). |
| if (!has_error && (next_is_option_value || next_is_match_criteria)) { |
| if (next_is_option_value) { |
| GesturesProp* property = CreateDefaultProperty(option_name, "on"); |
| if (property) |
| config->properties.push_back(property); |
| } else if (IsMatchTypeSupported(match_type) && |
| IsMatchDeviceType(match_type)) { |
| internal::MatchCriteria* criteria = |
| CreateMatchCriteria(match_type, "on"); |
| if (criteria) |
| config->criterias.push_back(criteria); |
| } |
| } |
| } |
| |
| // Remove useless config sections. |
| if (!is_input_class_section || |
| (config->criterias.empty() && config->properties.empty())) { |
| configurations_.pop_back(); |
| } |
| } |
| } |
| |
| internal::MatchCriteria* GesturePropertyProvider::CreateMatchCriteria( |
| const std::string& match_type, |
| const std::string& arg) { |
| GPROP_LOG(INFO_SEVERITY) << "Creating match criteria: (" << match_type << ", " |
| << arg << ")"; |
| if (match_type == "MatchProduct") |
| return new internal::MatchProduct(arg); |
| if (match_type == "MatchDevicePath") |
| return new internal::MatchDevicePath(arg); |
| if (match_type == "MatchUSBID") |
| return new internal::MatchUSBID(arg); |
| if (match_type == "MatchIsPointer") |
| return new internal::MatchIsPointer(arg); |
| if (match_type == "MatchIsTouchpad") |
| return new internal::MatchIsTouchpad(arg); |
| if (match_type == "MatchIsTouchscreen") |
| return new internal::MatchIsTouchscreen(arg); |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| GesturesProp* GesturePropertyProvider::CreateDefaultProperty( |
| const std::string& name, |
| const std::string& value) { |
| // Our parsing rule: |
| // 1. No hex or oct number is accepted. |
| // 2. All numbers will be stored as double. |
| // 3. Array elements can be separated by both white-spaces or commas. |
| // 4. A token is treated as numeric either if it is one of the special |
| // keywords for boolean values (on, true, yes, off, false, no) or if |
| // base::StringToDouble succeeds. |
| // 5. The property is treated as numeric if and only if all of its elements |
| // (if any) are numerics. Otherwise, it will be treated as a string. |
| // 6. A string property will be trimmed before storing its value. |
| GPROP_LOG(INFO_SEVERITY) << "Creating default property: (" << name << ", " |
| << value << ")"; |
| |
| // Parse elements one-by-one. |
| std::string delimiters(base::kWhitespaceASCII); |
| delimiters.append(","); |
| base::StringTokenizer tokens(value, delimiters); |
| bool is_all_numeric = true; |
| std::vector<double> numbers; |
| while (tokens.GetNext()) { |
| // Skip empty tokens. |
| std::string token(tokens.token()); |
| if (token.empty()) |
| continue; |
| |
| // Check if it is a boolean keyword. |
| int bool_result = ParseBooleanKeyword(token); |
| if (bool_result) { |
| numbers.push_back(bool_result > 0); |
| continue; |
| } |
| |
| // Check if it is a number. |
| double real_result; |
| bool success = base::StringToDouble(token, &real_result); |
| if (!success) { |
| is_all_numeric = false; |
| break; |
| } |
| numbers.push_back(real_result); |
| } |
| |
| // Create the GesturesProp. Array properties need to contain at least one |
| // number and may contain numbers only. |
| GesturesProp* property = NULL; |
| if (is_all_numeric && numbers.size()) { |
| property = new GesturesDoubleProp( |
| name, numbers.size(), NULL, numbers.data(), NULL); |
| } else { |
| property = new GesturesStringProp(name, NULL, value.c_str(), NULL); |
| } |
| |
| GPROP_LOG(INFO_SEVERITY) << "Prop: " << *property; |
| // The function will always succeed for now but it may change later if we |
| // specify some name or args as invalid. |
| return property; |
| } |
| |
| void GesturePropertyProvider::SetupDefaultProperties(const DeviceId device_id, |
| const DevicePtr device) { |
| GPROP_LOG(INFO_SEVERITY) << "Setting up default properties for (" << device |
| << ", " << device_id << ", " << device->info.name |
| << ")"; |
| |
| // Go through all parsed sections. |
| internal::PropertiesMap& property_map = |
| device_data_map_.get(device_id)->default_properties; |
| for (size_t i = 0; i < configurations_.size(); ++i) { |
| if (configurations_[i]->Match(device)) { |
| GPROP_LOG(INFO_SEVERITY) << "Conf section \"" |
| << configurations_[i]->identifier |
| << "\" is matched"; |
| for (size_t j = 0; j < configurations_[i]->properties.size(); j++) { |
| GesturesProp* property = configurations_[i]->properties[j]; |
| // We can't use insert here because a property may be set for several |
| // times along the way. |
| property_map[property->name()] = property; |
| } |
| } |
| } |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateInt(void* device_data, |
| const char* name, |
| int* value, |
| size_t count, |
| const int* init) { |
| return CreateProperty<int, GesturesIntProp>( |
| device_data, name, value, count, init); |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateShort(void* device_data, |
| const char* name, |
| short* value, |
| size_t count, |
| const short* init) { |
| return CreateProperty<short, GesturesShortProp>( |
| device_data, name, value, count, init); |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateBool( |
| void* device_data, |
| const char* name, |
| GesturesPropBool* value, |
| size_t count, |
| const GesturesPropBool* init) { |
| return CreateProperty<GesturesPropBool, GesturesBoolProp>( |
| device_data, name, value, count, init); |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateReal(void* device_data, |
| const char* name, |
| double* value, |
| size_t count, |
| const double* init) { |
| return CreateProperty<double, GesturesDoubleProp>( |
| device_data, name, value, count, init); |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateString(void* device_data, |
| const char* name, |
| const char** value, |
| const char* init) { |
| GesturesProp* default_property = NULL; |
| if (!PreCreateProperty(device_data, name, &default_property)) |
| return NULL; |
| GesturesProp* property = |
| new GesturesStringProp(name, value, init, default_property); |
| |
| PostCreateProperty(device_data, name, property); |
| return property; |
| } |
| |
| void GesturesPropFunctionsWrapper::RegisterHandlers( |
| void* device_data, |
| GesturesProp* property, |
| void* handler_data, |
| GesturesPropGetHandler get, |
| GesturesPropSetHandler set) { |
| // Sanity checks |
| if (!device_data || !property) |
| return; |
| |
| property->SetHandlers(get, set, handler_data); |
| } |
| |
| void GesturesPropFunctionsWrapper::Free(void* device_data, |
| GesturesProp* property) { |
| if (!property) |
| return; |
| GesturePropertyProvider* provider = GetPropertyProvider(device_data); |
| |
| // No need to manually delete the prop pointer as it is implicitly handled |
| // with scoped ptr. |
| GPROP_LOG(3) << "Freeing Property: \"" << property->name() << "\""; |
| provider->DeleteProperty(GetDeviceId(device_data), property->name()); |
| } |
| |
| bool GesturesPropFunctionsWrapper::InitializeDeviceProperties( |
| void* device_data, |
| GestureDeviceProperties* properties) { |
| if (!device_data) |
| return false; |
| GesturePropertyProvider::DevicePtr device = GetDevicePointer(device_data); |
| |
| /* Create Device Properties */ |
| |
| // Read Only properties. |
| CreateString( |
| device_data, "Device Node", NULL, GetDeviceNodePath(device).c_str()); |
| short vid = static_cast<short>(device->info.id.vendor); |
| CreateShort(device_data, "Device Vendor ID", NULL, 1, &vid); |
| short pid = static_cast<short>(device->info.id.product); |
| CreateShort(device_data, "Device Product ID", NULL, 1, &pid); |
| |
| // Useable trackpad area. If not configured in .conf file, |
| // use x/y valuator min/max as reported by kernel driver. |
| CreateIntSingle(device_data, |
| "Active Area Left", |
| &properties->area_left, |
| Event_Get_Left(device)); |
| CreateIntSingle(device_data, |
| "Active Area Right", |
| &properties->area_right, |
| Event_Get_Right(device)); |
| CreateIntSingle(device_data, |
| "Active Area Top", |
| &properties->area_top, |
| Event_Get_Top(device)); |
| CreateIntSingle(device_data, |
| "Active Area Bottom", |
| &properties->area_bottom, |
| Event_Get_Bottom(device)); |
| |
| // Trackpad resolution (pixels/mm). If not configured in .conf file, |
| // use x/y resolution as reported by kernel driver. |
| CreateIntSingle(device_data, |
| "Vertical Resolution", |
| &properties->res_y, |
| Event_Get_Res_Y(device)); |
| CreateIntSingle(device_data, |
| "Horizontal Resolution", |
| &properties->res_x, |
| Event_Get_Res_X(device)); |
| |
| // Trackpad orientation minimum/maximum. If not configured in .conf file, |
| // use min/max as reported by kernel driver. |
| CreateIntSingle(device_data, |
| "Orientation Minimum", |
| &properties->orientation_minimum, |
| Event_Get_Orientation_Minimum(device)); |
| CreateIntSingle(device_data, |
| "Orientation Maximum", |
| &properties->orientation_maximum, |
| Event_Get_Orientation_Maximum(device)); |
| |
| // Log dump property. Will call Event_Dump_Debug_Log when its value is being |
| // set. |
| GesturesProp* dump_debug_log_prop = CreateBoolSingle( |
| device_data, "Dump Debug Log", &properties->dump_debug_log, false); |
| RegisterHandlers( |
| device_data, dump_debug_log_prop, device, NULL, Event_Dump_Debug_Log); |
| |
| // Whether to do the gesture recognition or just passing the multi-touch data |
| // to upper layers. |
| CreateBoolSingle(device_data, |
| "Raw Touch Passthrough", |
| &properties->raw_passthrough, |
| false); |
| return true; |
| } |
| |
| void GesturesPropFunctionsWrapper::UnregisterDevice(void* device_data) { |
| GesturePropertyProvider* provider = GetPropertyProvider(device_data); |
| provider->UnregisterDevice(GetDeviceId(device_data)); |
| } |
| |
| template <typename T, class PROPTYPE> |
| GesturesProp* GesturesPropFunctionsWrapper::CreateProperty(void* device_data, |
| const char* name, |
| T* value, |
| size_t count, |
| const T* init) { |
| // Create the property. Use the default property value if possible. |
| GesturesProp* default_property = NULL; |
| if (!PreCreateProperty(device_data, name, &default_property)) |
| return NULL; |
| GesturesProp* property = |
| new PROPTYPE(name, count, value, init, default_property); |
| |
| // Start tracking the property in the provider. |
| PostCreateProperty(device_data, name, property); |
| return property; |
| } |
| |
| bool GesturesPropFunctionsWrapper::PreCreateProperty( |
| void* device_data, |
| const char* name, |
| GesturesProp** default_property) { |
| GesturePropertyProvider* provider = GetPropertyProvider(device_data); |
| GesturePropertyProvider::DeviceId device_id = GetDeviceId(device_data); |
| |
| // Register the device in the property provider if not yet. |
| provider->RegisterDevice(device_id, GetDevicePointer(device_data)); |
| |
| // First, see if the GesturesProp already exists. |
| GPROP_LOG(3) << "Creating Property: \"" << name << "\""; |
| GesturesProp* property = provider->FindProperty(device_id, name); |
| |
| // If so, delete it as we can't reuse the data structure (newly-created |
| // property may have different data type and count, which are fixed upon |
| // creation via the template mechanism). |
| if (property) { |
| LOG(WARNING) << "Gesture property \"" << name |
| << "\" re-created. This shouldn't happen at the normal usage."; |
| Free(device_data, property); |
| } |
| |
| // Return the found default property from conf files (could be NULL). |
| *default_property = provider->GetDefaultProperty(device_id, name); |
| return true; |
| } |
| |
| void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data, |
| const char* name, |
| GesturesProp* property) { |
| // Add the property to the gesture property provider. The gesture property |
| // provider will own it from now on. |
| GesturePropertyProvider* provider = GetPropertyProvider(device_data); |
| provider->AddProperty(GetDeviceId(device_data), name, property); |
| |
| // Log the creation. |
| GPROP_LOG(INFO_SEVERITY) << "Created active prop: " << *property; |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateIntSingle(void* device_data, |
| const char* name, |
| int* value, |
| int init) { |
| return CreateInt(device_data, name, value, 1, &init); |
| } |
| |
| GesturesProp* GesturesPropFunctionsWrapper::CreateBoolSingle( |
| void* device_data, |
| const char* name, |
| GesturesPropBool* value, |
| GesturesPropBool init) { |
| return CreateBool(device_data, name, value, 1, &init); |
| } |
| |
| GesturePropertyProvider* GesturesPropFunctionsWrapper::GetPropertyProvider( |
| void* device_data) { |
| return static_cast<GestureInterpreterLibevdevCros*>(device_data) |
| ->property_provider(); |
| } |
| |
| GesturePropertyProvider::DevicePtr |
| GesturesPropFunctionsWrapper::GetDevicePointer(void* device_data) { |
| return static_cast<GestureInterpreterLibevdevCros*>(device_data)->evdev(); |
| } |
| |
| GesturePropertyProvider::DeviceId GesturesPropFunctionsWrapper::GetDeviceId( |
| void* device_data) { |
| return static_cast<GestureInterpreterLibevdevCros*>(device_data)->id(); |
| } |
| |
| /* Global GesturesPropProvider |
| * |
| * Used by PropRegistry in GestureInterpreter to forward property value |
| * creations from there. |
| * */ |
| const GesturesPropProvider kGesturePropProvider = { |
| GesturesPropFunctionsWrapper::CreateInt, |
| GesturesPropFunctionsWrapper::CreateShort, |
| GesturesPropFunctionsWrapper::CreateBool, |
| GesturesPropFunctionsWrapper::CreateString, |
| GesturesPropFunctionsWrapper::CreateReal, |
| GesturesPropFunctionsWrapper::RegisterHandlers, |
| GesturesPropFunctionsWrapper::Free}; |
| |
| } // namespace ui |