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

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

Powered by Google App Engine
This is Rietveld 408576698