OLD | NEW |
---|---|
(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 = ∝ | |
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", §ions); | |
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 | |
OLD | NEW |