Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Side by Side Diff: ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc

Issue 545063006: ozone: evdev: Add gesture property provider (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase again. Move id generation logic to EventFactoryEvdev Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
6
7 #include <gestures/gestures.h>
8 #include <libevdev/libevdev.h>
9
10 #include <fnmatch.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <algorithm>
14 #include <iostream>
15 #include <vector>
16
17 #include "base/basictypes.h"
18 #include "base/containers/hash_tables.h"
19 #include "base/files/file_enumerator.h"
20 #include "base/files/file_util.h"
21 #include "base/logging.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_split.h"
24 #include "base/strings/string_tokenizer.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/stringize_macros.h"
27 #include "base/strings/stringprintf.h"
28 #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cr os.h"
29
30 // Severity level for general info logging purpose.
31 #define GPROP_LOG DVLOG
32 #define INFO_SEVERITY 1
33
34 /* Implementation of GesturesProp declared in gestures.h
35 *
36 * libgestures requires that this be in the top level namespace.
37 * */
38 class GesturesProp {
39 public:
40 typedef ui::GesturePropertyProvider::PropertyType PropertyType;
41
42 GesturesProp(const std::string& name,
43 const PropertyType type,
44 const size_t count)
45 : name_(name),
46 type_(type),
47 count_(count),
48 get_(NULL),
49 set_(NULL),
50 handler_data_(NULL) {}
51 virtual ~GesturesProp() {}
52
53 // Variant-ish interfaces for accessing the property value. Each type of
54 // property should override the corresponding interfaces for it.
55 virtual std::vector<int> GetIntValue() const {
56 NOTREACHED();
57 return std::vector<int>();
58 }
59 virtual bool SetIntValue(const std::vector<int>& value) {
60 NOTREACHED();
61 return false;
62 }
63 virtual std::vector<int16_t> GetShortValue() const {
64 NOTREACHED();
65 return std::vector<int16_t>();
66 }
67 virtual bool SetShortValue(const std::vector<int16_t>& value) {
68 NOTREACHED();
69 return false;
70 }
71 virtual std::vector<bool> GetBoolValue() const {
72 NOTREACHED();
73 return std::vector<bool>();
74 }
75 virtual bool SetBoolValue(const std::vector<bool>& value) {
76 NOTREACHED();
77 return false;
78 }
79 virtual std::string GetStringValue() const {
80 NOTREACHED();
81 return std::string();
82 }
83 virtual bool SetStringValue(const std::string& value) {
84 NOTREACHED();
85 return false;
86 }
87 virtual std::vector<double> GetDoubleValue() const {
88 NOTREACHED();
89 return std::vector<double>();
90 }
91 virtual bool SetDoubleValue(const std::vector<double>& value) {
92 NOTREACHED();
93 return false;
94 }
95
96 // Set property access handlers.
97 void SetHandlers(GesturesPropGetHandler get,
98 GesturesPropSetHandler set,
99 void* data) {
100 get_ = get;
101 set_ = set;
102 handler_data_ = data;
103 }
104
105 // Accessors.
106 const std::string& name() const { return name_; }
107 PropertyType type() const { return type_; }
108 size_t count() const { return count_; }
109 virtual bool IsReadOnly() const = 0;
110
111 protected:
112 void OnGet() const {
113 // We don't have the X server now so there is currently nothing to do when
114 // the get handler returns true.
115 // TODO(sheckylin): Re-visit this if we use handlers that modifies the
116 // property.
117 if (get_)
118 get_(handler_data_);
119 }
120
121 void OnSet() const {
122 // Call the property set handler if available.
123 if (set_)
124 set_(handler_data_);
125 }
126
127 private:
128 // For logging purpose.
129 friend std::ostream& operator<<(std::ostream& os,
130 const GesturesProp& property);
131
132 // Interfaces for getting internal pointers and stuff.
133 virtual const char** GetStringWritebackPtr() const {
134 NOTREACHED();
135 return NULL;
136 }
137 virtual bool IsAllocated() const {
138 NOTREACHED();
139 return false;
140 }
141
142 // Property name, type and number of elements.
143 std::string name_;
144 PropertyType type_;
145 size_t count_;
146
147 // Handler function pointers and the data to be passed to them when the
148 // property is accessed.
149 GesturesPropGetHandler get_;
150 GesturesPropSetHandler set_;
151 void* handler_data_;
152
153 DISALLOW_COPY_AND_ASSIGN(GesturesProp);
154 };
155
156 template <typename T>
157 class TypedGesturesProp : public GesturesProp {
158 public:
159 TypedGesturesProp(const std::string& name,
160 const PropertyType type,
161 const size_t count,
162 T* value)
163 : GesturesProp(name, type, count),
164 value_(value),
165 is_read_only_(false),
166 is_allocated_(false) {
167 Init();
168 }
169 virtual ~TypedGesturesProp() OVERRIDE {
170 if (is_allocated_)
171 delete[] value_;
172 }
173
174 // Accessors.
175 virtual bool IsReadOnly() const OVERRIDE { return is_read_only_; }
176
177 protected:
178 // Functions for setting/getting numerical properties.
179 //
180 // These two functions calls the set/get handler and should only be used in
181 // Get*Value/Set*Value functions.
182 template <typename U>
183 std::vector<U> GetNumericalPropertyValue() const {
184 // Nothing should be modified so it is OK to call the get handler first.
185 OnGet();
186 return this->template GetNumericalValue<U>();
187 }
188
189 template <typename U>
190 bool SetNumericalPropertyValue(const std::vector<U>& value) {
191 // Set the value only if not read-only and the vector size matches.
192 //
193 // As per the legacy guideline, all read-only properties (created with NULL)
194 // can't be modified. If we want to change this in the future, re-think
195 // about the different cases here (e.g., should we allow setting an array
196 // value of different size?).
197 if (is_read_only_ || value.size() != count())
198 return false;
199 bool ret = this->template SetNumericalValue(value);
200 OnSet();
201 return ret;
202 }
203
204 // Initialize a numerical property's value. Note that a (numerical) default
205 // property's value is always stored in double.
206 void InitializeNumericalProperty(const T* init,
207 const GesturesProp* default_property) {
208 if (IsDefaultPropertyUsable(default_property)) {
209 GPROP_LOG(INFO_SEVERITY) << "Default property found. Using its value ...";
210 this->template SetNumericalValue(default_property->GetDoubleValue());
211 } else {
212 // To work with the interface exposed by the gesture lib, we have no
213 // choice but to trust that the init array has sufficient size.
214 std::vector<T> temp(init, init + count());
215 this->template SetNumericalValue(temp);
216 }
217 }
218
219 // Data pointer.
220 T* value_;
221
222 // If the flag is on, it means the GesturesProp is created by passing a NULL
223 // data pointer to the creator functions. We define the property as a
224 // read-only one and that no value change will be allowed for it. Note that
225 // the flag is different from is_allocated in that StringProperty will always
226 // allocate no matter it is created with NULL or not.
227 bool is_read_only_;
228
229 private:
230 // Initialize the object.
231 void Init() {
232 // If no external data pointer is passed, we have to create our own.
233 if (!value_) {
234 value_ = new T[GesturesProp::count()];
235 is_read_only_ = true;
236 is_allocated_ = true;
237 }
238 }
239
240 // Low-level functions for setting/getting numerical properties.
241 template <typename U>
242 std::vector<U> GetNumericalValue() const {
243 // We do type-casting because the numerical types may not totally match.
244 // For example, we store bool as GesturesPropBool to be compatible with the
245 // gesture library. Also, all parsed xorg-conf property values are stored
246 // as double because we can't identify their original type lexically.
247 // TODO(sheckylin): Handle value out-of-range (e.g., double to int).
248 std::vector<U> result(count());
249 for (size_t i = 0; i < count(); ++i)
250 result[i] = static_cast<U>(value_[i]);
251 return result;
252 }
253
254 template <typename U>
255 bool SetNumericalValue(const std::vector<U>& value) {
256 for (size_t i = 0; i < count(); ++i)
257 value_[i] = static_cast<T>(value[i]);
258 return true;
259 }
260
261 // Check if a default property usable for (numerical) initialization.
262 bool IsDefaultPropertyUsable(const GesturesProp* default_property) const {
263 // We currently assumed that we won't specify any array property in the
264 // configuration files. The code needs to be updated if the assumption
265 // becomes invalid in the future.
266 return (count() == 1 && default_property &&
267 default_property->type() != PropertyType::PT_STRING);
268 }
269
270 // Accessors.
271 virtual bool IsAllocated() const OVERRIDE { return is_allocated_; }
272
273 // If the flag is on, it means the memory that the data pointer points to is
274 // allocated here. We will need to free the memory by ourselves when the
275 // GesturesProp is destroyed.
276 bool is_allocated_;
277 };
278
279 class GesturesIntProp : public TypedGesturesProp<int> {
280 public:
281 GesturesIntProp(const std::string& name,
282 const size_t count,
283 int* value,
284 const int* init,
285 const GesturesProp* default_property)
286 : TypedGesturesProp<int>(name, PropertyType::PT_INT, count, value) {
287 InitializeNumericalProperty(init, default_property);
288 }
289 virtual std::vector<int> GetIntValue() const OVERRIDE {
290 return this->template GetNumericalPropertyValue<int>();
291 }
292 virtual bool SetIntValue(const std::vector<int>& value) OVERRIDE {
293 return this->template SetNumericalPropertyValue(value);
294 }
295 };
296
297 class GesturesShortProp : public TypedGesturesProp<short> {
298 public:
299 GesturesShortProp(const std::string& name,
300 const size_t count,
301 short* value,
302 const short* init,
303 const GesturesProp* default_property)
304 : TypedGesturesProp<short>(name, PropertyType::PT_SHORT, count, value) {
305 InitializeNumericalProperty(init, default_property);
306 }
307 virtual std::vector<int16_t> GetShortValue() const OVERRIDE {
308 return this->template GetNumericalPropertyValue<int16_t>();
309 }
310 virtual bool SetShortValue(const std::vector<int16_t>& value) OVERRIDE {
311 return this->template SetNumericalPropertyValue(value);
312 }
313 };
314
315 class GesturesBoolProp : public TypedGesturesProp<GesturesPropBool> {
316 public:
317 GesturesBoolProp(const std::string& name,
318 const size_t count,
319 GesturesPropBool* value,
320 const GesturesPropBool* init,
321 const GesturesProp* default_property)
322 : TypedGesturesProp<GesturesPropBool>(name,
323 PropertyType::PT_BOOL,
324 count,
325 value) {
326 InitializeNumericalProperty(init, default_property);
327 }
328 virtual std::vector<bool> GetBoolValue() const OVERRIDE {
329 return this->template GetNumericalPropertyValue<bool>();
330 }
331 virtual bool SetBoolValue(const std::vector<bool>& value) OVERRIDE {
332 return this->template SetNumericalPropertyValue(value);
333 }
334 };
335
336 class GesturesDoubleProp : public TypedGesturesProp<double> {
337 public:
338 GesturesDoubleProp(const std::string& name,
339 const size_t count,
340 double* value,
341 const double* init,
342 const GesturesProp* default_property)
343 : TypedGesturesProp<double>(name, PropertyType::PT_REAL, count, value) {
344 InitializeNumericalProperty(init, default_property);
345 }
346 virtual std::vector<double> GetDoubleValue() const OVERRIDE {
347 return this->template GetNumericalPropertyValue<double>();
348 }
349 virtual bool SetDoubleValue(const std::vector<double>& value) OVERRIDE {
350 return this->template SetNumericalPropertyValue(value);
351 }
352 };
353
354 class GesturesStringProp : public TypedGesturesProp<std::string> {
355 public:
356 // StringProperty's memory is always allocated on this side instead of
357 // externally in the gesture lib as the original one will be destroyed right
358 // after the constructor call (check the design of StringProperty). To do
359 // this, we call the TypedGesturesProp constructor with NULL pointer so that
360 // it always allocates.
361 GesturesStringProp(const std::string& name,
362 const char** value,
363 const char* init,
364 const GesturesProp* default_property)
365 : TypedGesturesProp<std::string>(name, PropertyType::PT_STRING, 1, NULL),
366 write_back_(NULL) {
367 InitializeStringProperty(value, init, default_property);
368 }
369 virtual std::string GetStringValue() const OVERRIDE {
370 OnGet();
371 return *value_;
372 }
373 virtual bool SetStringValue(const std::string& value) OVERRIDE {
374 if (is_read_only_)
375 return false;
376 *value_ = value;
377
378 // Write back the pointer in case it may change (e.g., string
379 // re-allocation).
380 if (write_back_)
381 *(write_back_) = value_->c_str();
382 OnSet();
383 return true;
384 }
385
386 private:
387 // Initialize the object.
388 void InitializeStringProperty(const char** value,
389 const char* init,
390 const GesturesProp* default_property) {
391 // Initialize the property value similar to the numerical types.
392 if (IsDefaultPropertyUsable(default_property)) {
393 GPROP_LOG(INFO_SEVERITY) << "Default property found. Using its value ...";
394 *value_ = default_property->GetStringValue();
395 } else {
396 *value_ = init;
397 }
398
399 // If the provided pointer is not NULL, replace its content
400 // (val_ of StringProperty) with the address of our allocated string.
401 // Note that we don't have to do this for the other data types as they will
402 // use the original data pointer if possible and it is unnecessary to do so
403 // if the pointer is NULL.
404 if (value) {
405 *value = value_->c_str();
406 write_back_ = value;
407 // Set the read-only flag back to false.
408 is_read_only_ = false;
409 }
410 }
411
412 // Re-write the function with different criteria as we want string properties
413 // now.
414 bool IsDefaultPropertyUsable(const GesturesProp* default_property) const {
415 return (default_property &&
416 default_property->type() == PropertyType::PT_STRING);
417 }
418
419 virtual const char** GetStringWritebackPtr() const OVERRIDE {
420 return write_back_;
421 }
422
423 // In some cases, we don't directly use the data pointer provided by the
424 // creators due to its limitation and instead use our own types (e.g., in
425 // the case of string). We thus need to store the write back pointer so that
426 // we can update the value in the gesture lib if the property value gets
427 // changed.
428 const char** write_back_;
429 };
430
431 // Anonymous namespace for utility functions and internal constants.
432 namespace {
433
434 // The path that we will look for conf files.
435 const char kConfigurationFilePath[] = "/etc/gesture";
436
437 // We support only match types that have already been used. One should change
438 // this if we start using new types in the future. Note that most unsupported
439 // match types are either useless in CrOS or inapplicable to the non-X
440 // environment.
441 const char* kSupportedMatchTypes[] = {"MatchProduct",
442 "MatchDevicePath",
443 "MatchUSBID",
444 "MatchIsPointer",
445 "MatchIsTouchpad",
446 "MatchIsTouchscreen"};
447 const char* kUnsupportedMatchTypes[] = {"MatchVendor",
448 "MatchOS",
449 "MatchPnPID",
450 "MatchDriver",
451 "MatchTag",
452 "MatchLayout",
453 "MatchIsKeyboard",
454 "MatchIsJoystick",
455 "MatchIsTablet"};
456
457 // Special keywords for boolean values.
458 const char* kTrue[] = {"on", "true", "yes"};
459 const char* kFalse[] = {"off", "false", "no"};
460
461 // Check if a device falls into one device type category.
462 bool IsDeviceOfType(const ui::GesturePropertyProvider::DevicePtr device,
463 const ui::GesturePropertyProvider::DeviceType type) {
464 EvdevClass evdev_class = device->info.evdev_class;
465 switch (type) {
466 case ui::GesturePropertyProvider::DT_MOUSE:
467 return (evdev_class == EvdevClassMouse ||
468 evdev_class == EvdevClassMultitouchMouse);
469 break;
470 case ui::GesturePropertyProvider::DT_TOUCHPAD:
471 // Note that the behavior here is different from the inputcontrol script
472 // which actually returns touchscreen devices as well.
473 return (evdev_class == EvdevClassTouchpad);
474 break;
475 case ui::GesturePropertyProvider::DT_TOUCHSCREEN:
476 return (evdev_class == EvdevClassTouchscreen);
477 break;
478 case ui::GesturePropertyProvider::DT_MULTITOUCH:
479 return (evdev_class == EvdevClassTouchpad ||
480 evdev_class == EvdevClassTouchscreen ||
481 evdev_class == EvdevClassMultitouchMouse);
482 break;
483 case ui::GesturePropertyProvider::DT_MULTITOUCH_MOUSE:
484 return (evdev_class == EvdevClassMultitouchMouse);
485 break;
486 case ui::GesturePropertyProvider::DT_ALL:
487 return true;
488 break;
489 default:
490 NOTREACHED();
491 break;
492 }
493 return false;
494 }
495
496 // Trick to get the device path from a file descriptor.
497 std::string GetDeviceNodePath(
498 const ui::GesturePropertyProvider::DevicePtr device) {
499 std::string proc_symlink = "/proc/self/fd/" + base::IntToString(device->fd);
500 base::FilePath path;
501 if (!base::ReadSymbolicLink(base::FilePath(proc_symlink), &path))
502 return std::string();
503 return path.value();
504 }
505
506 // Check if a match criteria is currently implemented. Note that we didn't
507 // implemented all of them as some are inapplicable in the non-X world.
508 bool IsMatchTypeSupported(const std::string& match_type) {
509 for (size_t i = 0; i < arraysize(kSupportedMatchTypes); ++i)
510 if (match_type == kSupportedMatchTypes[i])
511 return true;
512 for (size_t i = 0; i < arraysize(kUnsupportedMatchTypes); ++i) {
513 if (match_type == kUnsupportedMatchTypes[i]) {
514 LOG(ERROR) << "Unsupported gestures input class match type: "
515 << match_type;
516 return false;
517 }
518 }
519 return false;
520 }
521
522 // Check if a match criteria is a device type one.
523 bool IsMatchDeviceType(const std::string& match_type) {
524 return StartsWithASCII(match_type, "MatchIs", true);
525 }
526
527 // Parse a boolean value keyword (e.g., on/off, true/false).
528 int ParseBooleanKeyword(const std::string& value) {
529 for (size_t i = 0; i < arraysize(kTrue); ++i)
530 if (LowerCaseEqualsASCII(value, kTrue[i]))
531 return 1;
532 for (size_t i = 0; i < arraysize(kFalse); ++i)
533 if (LowerCaseEqualsASCII(value, kFalse[i]))
534 return -1;
535 return 0;
536 }
537
538 // Log the value of an array property.
539 template <typename T>
540 void LogArrayProperty(std::ostream& os, const std::vector<T>& value) {
541 os << "(";
542 for (size_t i = 0; i < value.size(); ++i) {
543 if (i > 0)
544 os << ", ";
545 os << value[i];
546 }
547 os << ")";
548 }
549
550 // Property type logging function.
551 std::ostream& operator<<(std::ostream& out,
552 const ui::GesturePropertyProvider::PropertyType type) {
553 std::string s;
554 #define TYPE_CASE(TYPE) \
555 case (ui::GesturePropertyProvider::TYPE): \
556 s = #TYPE; \
557 break;
558 switch (type) {
559 TYPE_CASE(PT_INT);
560 TYPE_CASE(PT_SHORT);
561 TYPE_CASE(PT_BOOL);
562 TYPE_CASE(PT_STRING);
563 TYPE_CASE(PT_REAL);
564 default:
565 NOTREACHED();
566 break;
567 }
568 #undef TYPE_CASE
569 return out << s;
570 }
571
572 } // namespace
573
574 // GesturesProp logging function.
575 std::ostream& operator<<(std::ostream& os, const GesturesProp& prop) {
576 const GesturesProp* property = &prop;
577
578 // Output the property content.
579 os << "\"" << property->name() << "\", " << property->type() << ", "
580 << property->count() << ", (" << property->IsAllocated() << ", "
581 << property->IsReadOnly() << "), ";
582
583 // Only the string property has the write back pointer.
584 if (property->type() == ui::GesturePropertyProvider::PT_STRING)
585 os << property->GetStringWritebackPtr();
586 else
587 os << "NULL";
588
589 // Output the property values.
590 os << ", ";
591 switch (property->type()) {
592 case ui::GesturePropertyProvider::PT_INT:
593 LogArrayProperty(os, property->GetIntValue());
594 break;
595 case ui::GesturePropertyProvider::PT_SHORT:
596 LogArrayProperty(os, property->GetShortValue());
597 break;
598 case ui::GesturePropertyProvider::PT_BOOL:
599 LogArrayProperty(os, property->GetBoolValue());
600 break;
601 case ui::GesturePropertyProvider::PT_STRING:
602 os << "\"" << property->GetStringValue() << "\"";
603 break;
604 case ui::GesturePropertyProvider::PT_REAL:
605 LogArrayProperty(os, property->GetDoubleValue());
606 break;
607 default:
608 LOG(ERROR) << "Unknown gesture property type: " << property->type();
609 NOTREACHED();
610 break;
611 }
612 return os;
613 }
614
615 namespace ui {
616 namespace internal {
617
618 // Mapping table from a property name to its corresponding GesturesProp
619 // object pointer.
620 typedef base::hash_map<std::string, GesturesProp*> PropertiesMap;
621 typedef base::ScopedPtrHashMap<std::string, GesturesProp> ScopedPropertiesMap;
622
623 // Struct holding properties of a device.
624 //
625 // Note that we can't define it in GesturePropertyProvider as a nested class
626 // because ScopedPtrHashMap will require us to expose the GestureProp's
627 // destructor so that it can instantiate the object. This is something we
628 // don't want to do.
629 struct GestureDevicePropertyData {
630 GestureDevicePropertyData() {}
631
632 // Properties owned and being used by the device.
633 ScopedPropertiesMap properties;
634
635 // Unowned default properties (owned by the configuration file). Their values
636 // will be applied when a property of the same name is created. These are
637 // usually only a small portion of all properties in use.
638 PropertiesMap default_properties;
639 };
640
641 // Base class for device match criterias in conf files.
642 // Check the xorg-conf spec for more detailed information.
643 class MatchCriteria {
644 public:
645 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr;
646 explicit MatchCriteria(const std::string& arg);
647 virtual ~MatchCriteria(){};
648 virtual bool Match(const DevicePtr device) = 0;
649
650 protected:
651 std::vector<std::string> args_;
652 };
653
654 // Match a device based on its evdev name string.
655 class MatchProduct : public MatchCriteria {
656 public:
657 explicit MatchProduct(const std::string& arg);
658 virtual ~MatchProduct(){};
spang 2014/10/15 11:36:41 whitespace. Run $ git clang-format HEAD^
Shecky Lin 2014/10/16 04:53:53 I ran it again and it turns out this is what clang
659 virtual bool Match(const DevicePtr device);
660 };
661
662 // Math a device based on its device node path.
663 class MatchDevicePath : public MatchCriteria {
664 public:
665 explicit MatchDevicePath(const std::string& arg);
666 virtual ~MatchDevicePath(){};
667 virtual bool Match(const DevicePtr device);
668 };
669
670 // Math a USB device based on its USB vid and pid.
671 // Mostly used for external mice and touchpads.
672 class MatchUSBID : public MatchCriteria {
673 public:
674 explicit MatchUSBID(const std::string& arg);
675 virtual ~MatchUSBID(){};
676 virtual bool Match(const DevicePtr device);
677
678 private:
679 bool IsValidPattern(const std::string& pattern);
680 std::vector<std::string> vid_patterns_;
681 std::vector<std::string> pid_patterns_;
682 };
683
684 // Generic base class for device type math criteria.
685 class MatchDeviceType : public MatchCriteria {
686 public:
687 explicit MatchDeviceType(const std::string& arg);
688 virtual ~MatchDeviceType(){};
689 virtual bool Match(const DevicePtr device) = 0;
690
691 protected:
692 bool value_;
693 bool is_valid_;
694 };
695
696 // Check if a device is a pointer device.
697 class MatchIsPointer : public MatchDeviceType {
698 public:
699 explicit MatchIsPointer(const std::string& arg);
700 virtual ~MatchIsPointer(){};
701 virtual bool Match(const DevicePtr device);
702 };
703
704 // Check if a device is a touchpad.
705 class MatchIsTouchpad : public MatchDeviceType {
706 public:
707 explicit MatchIsTouchpad(const std::string& arg);
708 virtual ~MatchIsTouchpad(){};
709 virtual bool Match(const DevicePtr device);
710 };
711
712 // Check if a device is a touchscreen.
713 class MatchIsTouchscreen : public MatchDeviceType {
714 public:
715 explicit MatchIsTouchscreen(const std::string& arg);
716 virtual ~MatchIsTouchscreen(){};
717 virtual bool Match(const DevicePtr device);
718 };
719
720 // Struct for sections in xorg conf files.
721 struct ConfigurationSection {
722 typedef ui::GesturePropertyProvider::DevicePtr DevicePtr;
723 ConfigurationSection() {}
724 bool Match(const DevicePtr device);
725 std::string identifier;
726 ScopedVector<MatchCriteria> criterias;
727 ScopedVector<GesturesProp> properties;
728 };
729
730 MatchCriteria::MatchCriteria(const std::string& arg) {
731 // TODO(sheckylin): Should we trim all tokens here?
732 Tokenize(arg, "|", &args_);
733 if (args_.empty()) {
734 LOG(ERROR) << "Empty match pattern found, will evaluate to the default "
735 "value (true): \"" << arg << "\"";
736 }
737 }
738
739 MatchProduct::MatchProduct(const std::string& arg) : MatchCriteria(arg) {
740 }
741
742 bool MatchProduct::Match(const DevicePtr device) {
743 if (args_.empty())
744 return true;
745 std::string name(device->info.name);
746 for (size_t i = 0; i < args_.size(); ++i)
747 if (name.find(args_[i]) != std::string::npos)
748 return true;
749 return false;
750 }
751
752 MatchDevicePath::MatchDevicePath(const std::string& arg) : MatchCriteria(arg) {
753 }
754
755 bool MatchDevicePath::Match(const DevicePtr device) {
756 if (args_.empty())
757 return true;
758
759 // Check if the device path matches any pattern.
760 std::string path = GetDeviceNodePath(device);
761 if (path.empty())
762 return false;
763 for (size_t i = 0; i < args_.size(); ++i)
764 if (fnmatch(args_[i].c_str(), path.c_str(), FNM_NOESCAPE) == 0)
765 return true;
766 return false;
767 }
768
769 MatchUSBID::MatchUSBID(const std::string& arg) : MatchCriteria(arg) {
770 // Check each pattern and split valid ones into vids and pids.
771 for (size_t i = 0; i < args_.size(); ++i) {
772 if (!IsValidPattern(args_[i])) {
773 LOG(ERROR) << "Invalid USB ID: " << args_[i];
774 continue;
775 }
776 std::vector<std::string> tokens;
777 base::SplitString(args_[i], ':', &tokens);
778 vid_patterns_.push_back(base::StringToLowerASCII(tokens[0]));
779 pid_patterns_.push_back(base::StringToLowerASCII(tokens[1]));
780 }
781 if (vid_patterns_.empty()) {
782 LOG(ERROR) << "No valid USB ID pattern found, will be ignored: \"" << arg
783 << "\"";
784 }
785 }
786
787 bool MatchUSBID::Match(const DevicePtr device) {
788 if (vid_patterns_.empty())
789 return true;
790 std::string vid = base::StringPrintf("%04x", device->info.id.vendor);
791 std::string pid = base::StringPrintf("%04x", device->info.id.product);
792 for (size_t i = 0; i < vid_patterns_.size(); ++i) {
793 if (fnmatch(vid_patterns_[i].c_str(), vid.c_str(), FNM_NOESCAPE) == 0 &&
794 fnmatch(pid_patterns_[i].c_str(), pid.c_str(), FNM_NOESCAPE) == 0) {
795 return true;
796 }
797 }
798 return false;
799 }
800
801 bool MatchUSBID::IsValidPattern(const std::string& pattern) {
802 // Each USB id should be in the lsusb format, i.e., xxxx:xxxx. We choose to do
803 // a lazy check here: if the pattern contains wrong characters not in the hex
804 // number range, it won't be matched anyway.
805 int number_of_colons = 0;
806 size_t pos_of_colon = 0;
807 for (size_t i = 0; i < pattern.size(); ++i)
808 if (pattern[i] == ':')
809 ++number_of_colons, pos_of_colon = i;
810 return (number_of_colons == 1) && (pos_of_colon != 0) &&
811 (pos_of_colon != pattern.size() - 1);
812 }
813
814 MatchDeviceType::MatchDeviceType(const std::string& arg)
815 : MatchCriteria(arg), value_(true), is_valid_(false) {
816 // Default value of a match criteria is true.
817 if (args_.empty())
818 args_.push_back("on");
819
820 // We care only about the first argument.
821 int value = ParseBooleanKeyword(args_[0]);
822 if (value) {
823 is_valid_ = true;
824 value_ = value > 0;
825 }
826 if (!is_valid_) {
827 LOG(ERROR)
828 << "No valid device class boolean keyword found, will be ignored: \""
829 << arg << "\"";
830 }
831 }
832
833 MatchIsPointer::MatchIsPointer(const std::string& arg) : MatchDeviceType(arg) {
834 }
835
836 bool MatchIsPointer::Match(const DevicePtr device) {
837 if (!is_valid_)
838 return true;
839 return (value_ == (device->info.evdev_class == EvdevClassMouse ||
840 device->info.evdev_class == EvdevClassMultitouchMouse));
841 }
842
843 MatchIsTouchpad::MatchIsTouchpad(const std::string& arg)
844 : MatchDeviceType(arg) {
845 }
846
847 bool MatchIsTouchpad::Match(const DevicePtr device) {
848 if (!is_valid_)
849 return true;
850 return (value_ == (device->info.evdev_class == EvdevClassTouchpad));
851 }
852
853 MatchIsTouchscreen::MatchIsTouchscreen(const std::string& arg)
854 : MatchDeviceType(arg) {
855 }
856
857 bool MatchIsTouchscreen::Match(const DevicePtr device) {
858 if (!is_valid_)
859 return true;
860 return (value_ == (device->info.evdev_class == EvdevClassTouchscreen));
861 }
862
863 bool ConfigurationSection::Match(DevicePtr device) {
864 for (size_t i = 0; i < criterias.size(); ++i)
865 if (!criterias[i]->Match(device))
866 return false;
867 return true;
868 }
869
870 } // namespace internal
871
872 GesturePropertyProvider::GesturePropertyProvider() {
873 LoadDeviceConfigurations();
874 }
875
876 GesturePropertyProvider::~GesturePropertyProvider() {
877 }
878
879 void GesturePropertyProvider::GetDeviceIdsByType(
880 const DeviceType type,
881 std::vector<DeviceId>* device_ids) {
882 device_ids->clear();
883 DeviceMap::const_iterator it = device_map_.begin();
884 for (; it != device_map_.end(); ++it)
885 if (IsDeviceOfType(it->second, type))
886 device_ids->push_back(it->first);
887 }
888
889 GesturesProp* GesturePropertyProvider::GetProperty(const DeviceId device_id,
890 const std::string& name) {
891 return FindProperty(device_id, name);
892 }
893
894 void GesturePropertyProvider::RegisterDevice(const DeviceId id,
895 const DevicePtr device) {
896 DeviceMap::const_iterator it = device_map_.find(id);
897 if (it != device_map_.end())
898 return;
899
900 // Setup data-structures.
901 device_map_[id] = device;
902 device_data_map_.set(id, scoped_ptr<internal::GestureDevicePropertyData>(
903 new internal::GestureDevicePropertyData));
904
905 // Gather default property values for the device from the parsed conf files.
906 SetupDefaultProperties(id, device);
907 return;
908 }
909
910 void GesturePropertyProvider::UnregisterDevice(const DeviceId id) {
911 DeviceMap::const_iterator it = device_map_.find(id);
912 if (it == device_map_.end())
913 return;
914 device_data_map_.erase(id);
915 device_map_.erase(it);
916 }
917
918 void GesturePropertyProvider::AddProperty(const DeviceId device_id,
919 const std::string& name,
920 GesturesProp* property) {
921 // The look-up should never fail because ideally a property can only be
922 // created with GesturesPropCreate* functions from the gesture lib side.
923 // Therefore, we simply return on failure.
924 internal::GestureDevicePropertyData* device_data =
925 device_data_map_.get(device_id);
926 if (device_data)
927 device_data->properties.set(name, scoped_ptr<GesturesProp>(property));
928 }
929
930 void GesturePropertyProvider::DeleteProperty(const DeviceId device_id,
931 const std::string& name) {
932 internal::GestureDevicePropertyData* device_data =
933 device_data_map_.get(device_id);
934 if (device_data)
935 device_data->properties.erase(name);
936 }
937
938 GesturesProp* GesturePropertyProvider::FindProperty(const DeviceId device_id,
939 const std::string& name) {
940 internal::GestureDevicePropertyData* device_data =
941 device_data_map_.get(device_id);
942 if (!device_data)
943 return NULL;
944 return device_data->properties.get(name);
945 }
946
947 GesturesProp* GesturePropertyProvider::GetDefaultProperty(
948 const DeviceId device_id,
949 const std::string& name) {
950 internal::GestureDevicePropertyData* device_data =
951 device_data_map_.get(device_id);
952 if (!device_data)
953 return NULL;
954 internal::PropertiesMap::const_iterator ib =
955 device_data->default_properties.find(name);
956 if (ib == device_data->default_properties.end())
957 return NULL;
958 return ib->second;
959 }
960
961 void GesturePropertyProvider::LoadDeviceConfigurations() {
962 // Enumerate conf files and sort them lexicographically.
963 std::set<base::FilePath> files;
964 base::FileEnumerator file_enum(base::FilePath(kConfigurationFilePath),
965 false,
966 base::FileEnumerator::FILES,
967 "*.conf");
968 for (base::FilePath path = file_enum.Next(); !path.empty();
969 path = file_enum.Next()) {
970 files.insert(path);
971 }
972 GPROP_LOG(INFO_SEVERITY) << files.size() << " conf files were found";
973
974 // Parse conf files one-by-one.
975 for (std::set<base::FilePath>::iterator file_iter = files.begin();
976 file_iter != files.end();
977 ++file_iter) {
978 GPROP_LOG(INFO_SEVERITY) << "Parsing conf file: " << (*file_iter).value();
979 std::string content;
980 if (!base::ReadFileToString(*file_iter, &content)) {
981 LOG(ERROR) << "Can't loading gestures conf file: "
982 << (*file_iter).value();
983 continue;
984 }
985 ParseXorgConfFile(content);
986 }
987 }
988
989 void GesturePropertyProvider::ParseXorgConfFile(const std::string& content) {
990 // To simplify the parsing work, we made some assumption about the conf file
991 // format which doesn't exist in the original xorg-conf spec. Most important
992 // ones are:
993 // 1. All keywords and names are now case-sensitive. Also, underscores are not
994 // ignored.
995 // 2. Each entry takes up one and exactly one line in the file.
996 // 3. No negation of the option value even if the option name is prefixed with
997 // "No" as it may cause problems for option names that does start with "No"
998 // (e.g., "Non-linearity").
999
1000 // Break the content into sections, lines and then pieces.
1001 // Sections are delimited by the "EndSection" keyword.
1002 // Lines are delimited by "\n".
1003 // Pieces are delimited by all white-spaces.
1004 std::vector<std::string> sections;
1005 base::SplitStringUsingSubstr(content, "EndSection", &sections);
1006 for (size_t i = 0; i < sections.size(); ++i) {
1007 // Create a new configuration section.
1008 configurations_.push_back(new internal::ConfigurationSection());
1009 internal::ConfigurationSection* config = configurations_.back();
1010
1011 // Break the section into lines.
1012 base::StringTokenizer lines(sections[i], "\n");
1013 bool is_input_class_section = true;
1014 bool has_checked_section_type = false;
1015 while (is_input_class_section && lines.GetNext()) {
1016 // Parse the line w.r.t. the xorg-conf format.
1017 std::string line(lines.token());
1018
1019 // Skip empty lines.
1020 if (line.empty())
1021 continue;
1022
1023 // Treat all whitespaces as delimiters.
1024 base::StringTokenizer pieces(line, base::kWhitespaceASCII);
1025 pieces.set_quote_chars("\"");
1026 bool is_parsing = false;
1027 bool has_error = false;
1028 bool next_is_section_type = false;
1029 bool next_is_option_name = false;
1030 bool next_is_option_value = false;
1031 bool next_is_match_criteria = false;
1032 bool next_is_identifier = false;
1033 std::string match_type, option_name;
1034 while (pieces.GetNext()) {
1035 std::string piece(pieces.token());
1036
1037 // Skip empty pieces.
1038 if (piece.empty())
1039 continue;
1040
1041 // See if we are currently parsing an entry or are still looking for
1042 // one.
1043 if (is_parsing) {
1044 // Stop parsing the current line if the format is wrong.
1045 if (piece.size() <= 2 || piece[0] != '\"' ||
1046 piece[piece.size() - 1] != '\"') {
1047 LOG(ERROR) << "Error parsing line: " << lines.token();
1048 has_error = true;
1049 if (next_is_section_type)
1050 is_input_class_section = false;
1051 break;
1052 }
1053
1054 // Parse the arguments. Note that we don't break even if a whitespace
1055 // string is passed. It will just be handled in various ways based on
1056 // the entry type.
1057 std::string arg;
1058 base::TrimWhitespaceASCII(
1059 piece.substr(1, piece.size() - 2), base::TRIM_ALL, &arg);
1060 if (next_is_section_type) {
1061 // We only care about InputClass sections.
1062 if (arg != "InputClass") {
1063 has_error = true;
1064 is_input_class_section = false;
1065 } else {
1066 GPROP_LOG(INFO_SEVERITY) << "New InputClass section found";
1067 has_checked_section_type = true;
1068 }
1069 break;
1070 } else if (next_is_identifier) {
1071 GPROP_LOG(INFO_SEVERITY) << "Identifier: " << arg;
1072 config->identifier = arg;
1073 next_is_identifier = false;
1074 break;
1075 } else if (next_is_option_name) {
1076 // TODO(sheckylin): Support option "Ignore".
1077 option_name = arg;
1078 next_is_option_value = true;
1079 next_is_option_name = false;
1080 } else if (next_is_option_value) {
1081 GesturesProp* property = CreateDefaultProperty(option_name, arg);
1082 if (property)
1083 config->properties.push_back(property);
1084 next_is_option_value = false;
1085 break;
1086 } else if (next_is_match_criteria) {
1087 // Skip all match types that are not supported.
1088 if (IsMatchTypeSupported(match_type)) {
1089 internal::MatchCriteria* criteria =
1090 CreateMatchCriteria(match_type, arg);
1091 if (criteria)
1092 config->criterias.push_back(criteria);
1093 }
1094 next_is_match_criteria = false;
1095 break;
1096 }
1097 } else {
1098 // If the section type hasn't been decided yet, look for it.
1099 // Otherwise, look for valid entries according to the spec.
1100 if (has_checked_section_type) {
1101 if (piece == "Driver") {
1102 // TODO(sheckylin): Support "Driver" so that we can force a device
1103 // not to use the gesture lib.
1104 NOTIMPLEMENTED();
1105 break;
1106 } else if (piece == "Identifier") {
1107 is_parsing = true;
1108 next_is_identifier = true;
1109 continue;
1110 } else if (piece == "Option") {
1111 is_parsing = true;
1112 next_is_option_name = true;
1113 continue;
1114 } else if (piece.size() > 5 && piece.compare(0, 5, "Match") == 0) {
1115 match_type = piece;
1116 is_parsing = true;
1117 next_is_match_criteria = true;
1118 continue;
1119 }
1120 } else if (piece == "Section") {
1121 is_parsing = true;
1122 next_is_section_type = true;
1123 continue;
1124 }
1125
1126 // If none of the above is found, check if the current piece starts a
1127 // comment.
1128 if (piece.empty() || piece[0] != '#') {
1129 LOG(ERROR) << "Error parsing line: " << lines.token();
1130 has_error = true;
1131 }
1132 break;
1133 }
1134 }
1135
1136 // The value of a boolean option is skipped (default is true).
1137 if (!has_error && (next_is_option_value || next_is_match_criteria)) {
1138 if (next_is_option_value) {
1139 GesturesProp* property = CreateDefaultProperty(option_name, "on");
1140 if (property)
1141 config->properties.push_back(property);
1142 } else if (IsMatchTypeSupported(match_type) &&
1143 IsMatchDeviceType(match_type)) {
1144 internal::MatchCriteria* criteria =
1145 CreateMatchCriteria(match_type, "on");
1146 if (criteria)
1147 config->criterias.push_back(criteria);
1148 }
1149 }
1150 }
1151
1152 // Remove useless config sections.
1153 if (!is_input_class_section ||
1154 (config->criterias.empty() && config->properties.empty())) {
1155 configurations_.pop_back();
1156 }
1157 }
1158 }
1159
1160 internal::MatchCriteria* GesturePropertyProvider::CreateMatchCriteria(
1161 const std::string& match_type,
1162 const std::string& arg) {
1163 GPROP_LOG(INFO_SEVERITY) << "Creating match criteria: (" << match_type << ", "
1164 << arg << ")";
1165 if (match_type == "MatchProduct")
1166 return new internal::MatchProduct(arg);
1167 if (match_type == "MatchDevicePath")
1168 return new internal::MatchDevicePath(arg);
1169 if (match_type == "MatchUSBID")
1170 return new internal::MatchUSBID(arg);
1171 if (match_type == "MatchIsPointer")
1172 return new internal::MatchIsPointer(arg);
1173 if (match_type == "MatchIsTouchpad")
1174 return new internal::MatchIsTouchpad(arg);
1175 if (match_type == "MatchIsTouchscreen")
1176 return new internal::MatchIsTouchscreen(arg);
1177 NOTREACHED();
1178 return NULL;
1179 }
1180
1181 GesturesProp* GesturePropertyProvider::CreateDefaultProperty(
1182 const std::string& name,
1183 const std::string& value) {
1184 // Our parsing rule:
1185 // 1. No hex or oct number is accepted.
1186 // 2. All numbers will be stored as double.
1187 // 3. Array elements can be separated by both white-spaces or commas.
1188 // 4. A token is treated as numeric either if it is one of the special
1189 // keywords for boolean values (on, true, yes, off, false, no) or if
1190 // base::StringToDouble succeeds.
1191 // 5. The property is treated as numeric if and only if all of its elements
1192 // (if any) are numerics. Otherwise, it will be treated as a string.
1193 // 6. A string property will be trimmed before storing its value.
1194 GPROP_LOG(INFO_SEVERITY) << "Creating default property: (" << name << ", "
1195 << value << ")";
1196
1197 // Parse elements one-by-one.
1198 std::string delimiters(base::kWhitespaceASCII);
1199 delimiters.append(",");
1200 base::StringTokenizer tokens(value, delimiters);
1201 bool is_all_numeric = true;
1202 std::vector<double> numbers;
1203 while (tokens.GetNext()) {
1204 // Skip empty tokens.
1205 std::string token(tokens.token());
1206 if (token.empty())
1207 continue;
1208
1209 // Check if it is a boolean keyword.
1210 int bool_result = ParseBooleanKeyword(token);
1211 if (bool_result) {
1212 numbers.push_back(bool_result > 0);
1213 continue;
1214 }
1215
1216 // Check if it is a number.
1217 double real_result;
1218 bool success = base::StringToDouble(token, &real_result);
1219 if (!success) {
1220 is_all_numeric = false;
1221 break;
1222 }
1223 numbers.push_back(real_result);
1224 }
1225
1226 // Create the GesturesProp. Array properties need to contain at least one
1227 // number and may contain numbers only.
1228 GesturesProp* property = NULL;
1229 if (is_all_numeric && numbers.size()) {
1230 property = new GesturesDoubleProp(
1231 name, numbers.size(), NULL, numbers.data(), NULL);
1232 } else {
1233 property = new GesturesStringProp(name, NULL, value.c_str(), NULL);
1234 }
1235
1236 GPROP_LOG(INFO_SEVERITY) << "Prop: " << *property;
1237 // The function will always succeed for now but it may change later if we
1238 // specify some name or args as invalid.
1239 return property;
1240 }
1241
1242 void GesturePropertyProvider::SetupDefaultProperties(const DeviceId device_id,
1243 const DevicePtr device) {
1244 GPROP_LOG(INFO_SEVERITY) << "Setting up default properties for (" << device
1245 << ", " << device_id << ", " << device->info.name
1246 << ")";
1247
1248 // Go through all parsed sections.
1249 internal::PropertiesMap& property_map =
1250 device_data_map_.get(device_id)->default_properties;
1251 for (size_t i = 0; i < configurations_.size(); ++i) {
1252 if (configurations_[i]->Match(device)) {
1253 GPROP_LOG(INFO_SEVERITY) << "Conf section \""
1254 << configurations_[i]->identifier
1255 << "\" is matched";
1256 for (size_t j = 0; j < configurations_[i]->properties.size(); j++) {
1257 GesturesProp* property = configurations_[i]->properties[j];
1258 // We can't use insert here because a property may be set for several
1259 // times along the way.
1260 property_map[property->name()] = property;
1261 }
1262 }
1263 }
1264 }
1265
1266 GesturesProp* GesturesPropFunctionsWrapper::CreateInt(void* device_data,
1267 const char* name,
1268 int* value,
1269 size_t count,
1270 const int* init) {
1271 return CreateProperty<int, GesturesIntProp>(
1272 device_data, name, value, count, init);
1273 }
1274
1275 GesturesProp* GesturesPropFunctionsWrapper::CreateShort(void* device_data,
1276 const char* name,
1277 short* value,
1278 size_t count,
1279 const short* init) {
1280 return CreateProperty<short, GesturesShortProp>(
1281 device_data, name, value, count, init);
1282 }
1283
1284 GesturesProp* GesturesPropFunctionsWrapper::CreateBool(
1285 void* device_data,
1286 const char* name,
1287 GesturesPropBool* value,
1288 size_t count,
1289 const GesturesPropBool* init) {
1290 return CreateProperty<GesturesPropBool, GesturesBoolProp>(
1291 device_data, name, value, count, init);
1292 }
1293
1294 GesturesProp* GesturesPropFunctionsWrapper::CreateReal(void* device_data,
1295 const char* name,
1296 double* value,
1297 size_t count,
1298 const double* init) {
1299 return CreateProperty<double, GesturesDoubleProp>(
1300 device_data, name, value, count, init);
1301 }
1302
1303 GesturesProp* GesturesPropFunctionsWrapper::CreateString(void* device_data,
1304 const char* name,
1305 const char** value,
1306 const char* init) {
1307 GesturesProp* default_property = NULL;
1308 if (!PreCreateProperty(device_data, name, &default_property))
1309 return NULL;
1310 GesturesProp* property =
1311 new GesturesStringProp(name, value, init, default_property);
1312
1313 PostCreateProperty(device_data, name, property);
1314 return property;
1315 }
1316
1317 void GesturesPropFunctionsWrapper::RegisterHandlers(
1318 void* device_data,
1319 GesturesProp* property,
1320 void* handler_data,
1321 GesturesPropGetHandler get,
1322 GesturesPropSetHandler set) {
1323 // Sanity checks
1324 if (!device_data || !property)
1325 return;
1326
1327 property->SetHandlers(get, set, handler_data);
1328 }
1329
1330 void GesturesPropFunctionsWrapper::Free(void* device_data,
1331 GesturesProp* property) {
1332 if (!property)
1333 return;
1334 GesturePropertyProvider* provider = GetPropertyProvider(device_data);
1335
1336 // No need to manually delete the prop pointer as it is implicitly handled
1337 // with scoped ptr.
1338 GPROP_LOG(3) << "Freeing Property: \"" << property->name() << "\"";
1339 provider->DeleteProperty(GetDeviceId(device_data), property->name());
1340 }
1341
1342 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties(
1343 void* device_data,
1344 GestureDeviceProperties* properties) {
1345 if (!device_data)
1346 return false;
1347 GesturePropertyProvider::DevicePtr device = GetDevicePointer(device_data);
1348
1349 /* Create Device Properties */
1350
1351 // Read Only properties.
1352 CreateString(
1353 device_data, "Device Node", NULL, GetDeviceNodePath(device).c_str());
1354 short vid = static_cast<short>(device->info.id.vendor);
1355 CreateShort(device_data, "Device Vendor ID", NULL, 1, &vid);
1356 short pid = static_cast<short>(device->info.id.product);
1357 CreateShort(device_data, "Device Product ID", NULL, 1, &pid);
1358
1359 // Useable trackpad area. If not configured in .conf file,
1360 // use x/y valuator min/max as reported by kernel driver.
1361 CreateIntSingle(device_data,
1362 "Active Area Left",
1363 &properties->area_left,
1364 Event_Get_Left(device));
1365 CreateIntSingle(device_data,
1366 "Active Area Right",
1367 &properties->area_right,
1368 Event_Get_Right(device));
1369 CreateIntSingle(device_data,
1370 "Active Area Top",
1371 &properties->area_top,
1372 Event_Get_Top(device));
1373 CreateIntSingle(device_data,
1374 "Active Area Bottom",
1375 &properties->area_bottom,
1376 Event_Get_Bottom(device));
1377
1378 // Trackpad resolution (pixels/mm). If not configured in .conf file,
1379 // use x/y resolution as reported by kernel driver.
1380 CreateIntSingle(device_data,
1381 "Vertical Resolution",
1382 &properties->res_y,
1383 Event_Get_Res_Y(device));
1384 CreateIntSingle(device_data,
1385 "Horizontal Resolution",
1386 &properties->res_x,
1387 Event_Get_Res_X(device));
1388
1389 // Trackpad orientation minimum/maximum. If not configured in .conf file,
1390 // use min/max as reported by kernel driver.
1391 CreateIntSingle(device_data,
1392 "Orientation Minimum",
1393 &properties->orientation_minimum,
1394 Event_Get_Orientation_Minimum(device));
1395 CreateIntSingle(device_data,
1396 "Orientation Maximum",
1397 &properties->orientation_maximum,
1398 Event_Get_Orientation_Maximum(device));
1399
1400 // Log dump property. Will call Event_Dump_Debug_Log when its value is being
1401 // set.
1402 GesturesProp* dump_debug_log_prop = CreateBoolSingle(
1403 device_data, "Dump Debug Log", &properties->dump_debug_log, false);
1404 RegisterHandlers(
1405 device_data, dump_debug_log_prop, device, NULL, Event_Dump_Debug_Log);
1406
1407 // Whether to do the gesture recognition or just passing the multi-touch data
1408 // to upper layers.
1409 CreateBoolSingle(device_data,
1410 "Raw Touch Passthrough",
1411 &properties->raw_passthrough,
1412 false);
1413 return true;
1414 }
1415
1416 void GesturesPropFunctionsWrapper::UnregisterDevice(void* device_data) {
1417 GesturePropertyProvider* provider = GetPropertyProvider(device_data);
1418 provider->UnregisterDevice(GetDeviceId(device_data));
1419 }
1420
1421 template <typename T, class PROPTYPE>
1422 GesturesProp* GesturesPropFunctionsWrapper::CreateProperty(void* device_data,
1423 const char* name,
1424 T* value,
1425 size_t count,
1426 const T* init) {
1427 // Create the property. Use the default property value if possible.
1428 GesturesProp* default_property = NULL;
1429 if (!PreCreateProperty(device_data, name, &default_property))
1430 return NULL;
1431 GesturesProp* property =
1432 new PROPTYPE(name, count, value, init, default_property);
1433
1434 // Start tracking the property in the provider.
1435 PostCreateProperty(device_data, name, property);
1436 return property;
1437 }
1438
1439 bool GesturesPropFunctionsWrapper::PreCreateProperty(
1440 void* device_data,
1441 const char* name,
1442 GesturesProp** default_property) {
1443 GesturePropertyProvider* provider = GetPropertyProvider(device_data);
1444 GesturePropertyProvider::DeviceId device_id = GetDeviceId(device_data);
1445
1446 // Register the device in the property provider if not yet.
1447 provider->RegisterDevice(device_id, GetDevicePointer(device_data));
1448
1449 // First, see if the GesturesProp already exists.
1450 GPROP_LOG(3) << "Creating Property: \"" << name << "\"";
1451 GesturesProp* property = provider->FindProperty(device_id, name);
1452
1453 // If so, delete it as we can't reuse the data structure (newly-created
1454 // property may have different data type and count, which are fixed upon
1455 // creation via the template mechanism).
1456 if (property) {
1457 LOG(WARNING) << "Gesture property \"" << name
1458 << "\" re-created. This shouldn't happen at the normal usage.";
1459 Free(device_data, property);
1460 }
1461
1462 // Return the found default property from conf files (could be NULL).
1463 *default_property = provider->GetDefaultProperty(device_id, name);
1464 return true;
1465 }
1466
1467 void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data,
1468 const char* name,
1469 GesturesProp* property) {
1470 // Add the property to the gesture property provider. The gesture property
1471 // provider will own it from now on.
1472 GesturePropertyProvider* provider = GetPropertyProvider(device_data);
1473 provider->AddProperty(GetDeviceId(device_data), name, property);
1474
1475 // Log the creation.
1476 GPROP_LOG(INFO_SEVERITY) << "Created active prop: " << *property;
1477 }
1478
1479 GesturesProp* GesturesPropFunctionsWrapper::CreateIntSingle(void* device_data,
1480 const char* name,
1481 int* value,
1482 int init) {
1483 return CreateInt(device_data, name, value, 1, &init);
1484 }
1485
1486 GesturesProp* GesturesPropFunctionsWrapper::CreateBoolSingle(
1487 void* device_data,
1488 const char* name,
1489 GesturesPropBool* value,
1490 GesturesPropBool init) {
1491 return CreateBool(device_data, name, value, 1, &init);
1492 }
1493
1494 GesturePropertyProvider* GesturesPropFunctionsWrapper::GetPropertyProvider(
1495 void* device_data) {
1496 return static_cast<GestureInterpreterLibevdevCros*>(device_data)
1497 ->property_provider();
1498 }
1499
1500 GesturePropertyProvider::DevicePtr
1501 GesturesPropFunctionsWrapper::GetDevicePointer(void* device_data) {
1502 return static_cast<GestureInterpreterLibevdevCros*>(device_data)->evdev();
1503 }
1504
1505 GesturePropertyProvider::DeviceId
1506 GesturesPropFunctionsWrapper::GetDeviceId(void* device_data) {
1507 return static_cast<GestureInterpreterLibevdevCros*>(device_data)->id();
1508 }
1509
1510 /* Global GesturesPropProvider
1511 *
1512 * Used by PropRegistry in GestureInterpreter to forward property value
1513 * creations from there.
1514 * */
1515 const GesturesPropProvider kGesturePropProvider = {
1516 GesturesPropFunctionsWrapper::CreateInt,
1517 GesturesPropFunctionsWrapper::CreateShort,
1518 GesturesPropFunctionsWrapper::CreateBool,
1519 GesturesPropFunctionsWrapper::CreateString,
1520 GesturesPropFunctionsWrapper::CreateReal,
1521 GesturesPropFunctionsWrapper::RegisterHandlers,
1522 GesturesPropFunctionsWrapper::Free};
1523
1524 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698