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(){}; | |
spang
2014/10/20 14:32:57
Your problem is the semicolon. Remove it and add t
| |
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(){}; | |
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, | |
903 scoped_ptr<internal::GestureDevicePropertyData>( | |
904 new internal::GestureDevicePropertyData)); | |
905 | |
906 // Gather default property values for the device from the parsed conf files. | |
907 SetupDefaultProperties(id, device); | |
908 return; | |
909 } | |
910 | |
911 void GesturePropertyProvider::UnregisterDevice(const DeviceId id) { | |
912 DeviceMap::const_iterator it = device_map_.find(id); | |
913 if (it == device_map_.end()) | |
914 return; | |
915 device_data_map_.erase(id); | |
916 device_map_.erase(it); | |
917 } | |
918 | |
919 void GesturePropertyProvider::AddProperty(const DeviceId device_id, | |
920 const std::string& name, | |
921 GesturesProp* property) { | |
922 // The look-up should never fail because ideally a property can only be | |
923 // created with GesturesPropCreate* functions from the gesture lib side. | |
924 // Therefore, we simply return on failure. | |
925 internal::GestureDevicePropertyData* device_data = | |
926 device_data_map_.get(device_id); | |
927 if (device_data) | |
928 device_data->properties.set(name, scoped_ptr<GesturesProp>(property)); | |
929 } | |
930 | |
931 void GesturePropertyProvider::DeleteProperty(const DeviceId device_id, | |
932 const std::string& name) { | |
933 internal::GestureDevicePropertyData* device_data = | |
934 device_data_map_.get(device_id); | |
935 if (device_data) | |
936 device_data->properties.erase(name); | |
937 } | |
938 | |
939 GesturesProp* GesturePropertyProvider::FindProperty(const DeviceId device_id, | |
940 const std::string& name) { | |
941 internal::GestureDevicePropertyData* device_data = | |
942 device_data_map_.get(device_id); | |
943 if (!device_data) | |
944 return NULL; | |
945 return device_data->properties.get(name); | |
946 } | |
947 | |
948 GesturesProp* GesturePropertyProvider::GetDefaultProperty( | |
949 const DeviceId device_id, | |
950 const std::string& name) { | |
951 internal::GestureDevicePropertyData* device_data = | |
952 device_data_map_.get(device_id); | |
953 if (!device_data) | |
954 return NULL; | |
955 internal::PropertiesMap::const_iterator ib = | |
956 device_data->default_properties.find(name); | |
957 if (ib == device_data->default_properties.end()) | |
958 return NULL; | |
959 return ib->second; | |
960 } | |
961 | |
962 void GesturePropertyProvider::LoadDeviceConfigurations() { | |
963 // Enumerate conf files and sort them lexicographically. | |
964 std::set<base::FilePath> files; | |
965 base::FileEnumerator file_enum(base::FilePath(kConfigurationFilePath), | |
966 false, | |
967 base::FileEnumerator::FILES, | |
968 "*.conf"); | |
969 for (base::FilePath path = file_enum.Next(); !path.empty(); | |
970 path = file_enum.Next()) { | |
971 files.insert(path); | |
972 } | |
973 GPROP_LOG(INFO_SEVERITY) << files.size() << " conf files were found"; | |
974 | |
975 // Parse conf files one-by-one. | |
976 for (std::set<base::FilePath>::iterator file_iter = files.begin(); | |
977 file_iter != files.end(); | |
978 ++file_iter) { | |
979 GPROP_LOG(INFO_SEVERITY) << "Parsing conf file: " << (*file_iter).value(); | |
980 std::string content; | |
981 if (!base::ReadFileToString(*file_iter, &content)) { | |
982 LOG(ERROR) << "Can't loading gestures conf file: " | |
983 << (*file_iter).value(); | |
984 continue; | |
985 } | |
986 ParseXorgConfFile(content); | |
987 } | |
988 } | |
989 | |
990 void GesturePropertyProvider::ParseXorgConfFile(const std::string& content) { | |
991 // To simplify the parsing work, we made some assumption about the conf file | |
992 // format which doesn't exist in the original xorg-conf spec. Most important | |
993 // ones are: | |
994 // 1. All keywords and names are now case-sensitive. Also, underscores are not | |
995 // ignored. | |
996 // 2. Each entry takes up one and exactly one line in the file. | |
997 // 3. No negation of the option value even if the option name is prefixed with | |
998 // "No" as it may cause problems for option names that does start with "No" | |
999 // (e.g., "Non-linearity"). | |
1000 | |
1001 // Break the content into sections, lines and then pieces. | |
1002 // Sections are delimited by the "EndSection" keyword. | |
1003 // Lines are delimited by "\n". | |
1004 // Pieces are delimited by all white-spaces. | |
1005 std::vector<std::string> sections; | |
1006 base::SplitStringUsingSubstr(content, "EndSection", §ions); | |
1007 for (size_t i = 0; i < sections.size(); ++i) { | |
1008 // Create a new configuration section. | |
1009 configurations_.push_back(new internal::ConfigurationSection()); | |
1010 internal::ConfigurationSection* config = configurations_.back(); | |
1011 | |
1012 // Break the section into lines. | |
1013 base::StringTokenizer lines(sections[i], "\n"); | |
1014 bool is_input_class_section = true; | |
1015 bool has_checked_section_type = false; | |
1016 while (is_input_class_section && lines.GetNext()) { | |
1017 // Parse the line w.r.t. the xorg-conf format. | |
1018 std::string line(lines.token()); | |
1019 | |
1020 // Skip empty lines. | |
1021 if (line.empty()) | |
1022 continue; | |
1023 | |
1024 // Treat all whitespaces as delimiters. | |
1025 base::StringTokenizer pieces(line, base::kWhitespaceASCII); | |
1026 pieces.set_quote_chars("\""); | |
1027 bool is_parsing = false; | |
1028 bool has_error = false; | |
1029 bool next_is_section_type = false; | |
1030 bool next_is_option_name = false; | |
1031 bool next_is_option_value = false; | |
1032 bool next_is_match_criteria = false; | |
1033 bool next_is_identifier = false; | |
1034 std::string match_type, option_name; | |
1035 while (pieces.GetNext()) { | |
1036 std::string piece(pieces.token()); | |
1037 | |
1038 // Skip empty pieces. | |
1039 if (piece.empty()) | |
1040 continue; | |
1041 | |
1042 // See if we are currently parsing an entry or are still looking for | |
1043 // one. | |
1044 if (is_parsing) { | |
1045 // Stop parsing the current line if the format is wrong. | |
1046 if (piece.size() <= 2 || piece[0] != '\"' || | |
1047 piece[piece.size() - 1] != '\"') { | |
1048 LOG(ERROR) << "Error parsing line: " << lines.token(); | |
1049 has_error = true; | |
1050 if (next_is_section_type) | |
1051 is_input_class_section = false; | |
1052 break; | |
1053 } | |
1054 | |
1055 // Parse the arguments. Note that we don't break even if a whitespace | |
1056 // string is passed. It will just be handled in various ways based on | |
1057 // the entry type. | |
1058 std::string arg; | |
1059 base::TrimWhitespaceASCII( | |
1060 piece.substr(1, piece.size() - 2), base::TRIM_ALL, &arg); | |
1061 if (next_is_section_type) { | |
1062 // We only care about InputClass sections. | |
1063 if (arg != "InputClass") { | |
1064 has_error = true; | |
1065 is_input_class_section = false; | |
1066 } else { | |
1067 GPROP_LOG(INFO_SEVERITY) << "New InputClass section found"; | |
1068 has_checked_section_type = true; | |
1069 } | |
1070 break; | |
1071 } else if (next_is_identifier) { | |
1072 GPROP_LOG(INFO_SEVERITY) << "Identifier: " << arg; | |
1073 config->identifier = arg; | |
1074 next_is_identifier = false; | |
1075 break; | |
1076 } else if (next_is_option_name) { | |
1077 // TODO(sheckylin): Support option "Ignore". | |
1078 option_name = arg; | |
1079 next_is_option_value = true; | |
1080 next_is_option_name = false; | |
1081 } else if (next_is_option_value) { | |
1082 GesturesProp* property = CreateDefaultProperty(option_name, arg); | |
1083 if (property) | |
1084 config->properties.push_back(property); | |
1085 next_is_option_value = false; | |
1086 break; | |
1087 } else if (next_is_match_criteria) { | |
1088 // Skip all match types that are not supported. | |
1089 if (IsMatchTypeSupported(match_type)) { | |
1090 internal::MatchCriteria* criteria = | |
1091 CreateMatchCriteria(match_type, arg); | |
1092 if (criteria) | |
1093 config->criterias.push_back(criteria); | |
1094 } | |
1095 next_is_match_criteria = false; | |
1096 break; | |
1097 } | |
1098 } else { | |
1099 // If the section type hasn't been decided yet, look for it. | |
1100 // Otherwise, look for valid entries according to the spec. | |
1101 if (has_checked_section_type) { | |
1102 if (piece == "Driver") { | |
1103 // TODO(sheckylin): Support "Driver" so that we can force a device | |
1104 // not to use the gesture lib. | |
1105 NOTIMPLEMENTED(); | |
1106 break; | |
1107 } else if (piece == "Identifier") { | |
1108 is_parsing = true; | |
1109 next_is_identifier = true; | |
1110 continue; | |
1111 } else if (piece == "Option") { | |
1112 is_parsing = true; | |
1113 next_is_option_name = true; | |
1114 continue; | |
1115 } else if (piece.size() > 5 && piece.compare(0, 5, "Match") == 0) { | |
1116 match_type = piece; | |
1117 is_parsing = true; | |
1118 next_is_match_criteria = true; | |
1119 continue; | |
1120 } | |
1121 } else if (piece == "Section") { | |
1122 is_parsing = true; | |
1123 next_is_section_type = true; | |
1124 continue; | |
1125 } | |
1126 | |
1127 // If none of the above is found, check if the current piece starts a | |
1128 // comment. | |
1129 if (piece.empty() || piece[0] != '#') { | |
1130 LOG(ERROR) << "Error parsing line: " << lines.token(); | |
1131 has_error = true; | |
1132 } | |
1133 break; | |
1134 } | |
1135 } | |
1136 | |
1137 // The value of a boolean option is skipped (default is true). | |
1138 if (!has_error && (next_is_option_value || next_is_match_criteria)) { | |
1139 if (next_is_option_value) { | |
1140 GesturesProp* property = CreateDefaultProperty(option_name, "on"); | |
1141 if (property) | |
1142 config->properties.push_back(property); | |
1143 } else if (IsMatchTypeSupported(match_type) && | |
1144 IsMatchDeviceType(match_type)) { | |
1145 internal::MatchCriteria* criteria = | |
1146 CreateMatchCriteria(match_type, "on"); | |
1147 if (criteria) | |
1148 config->criterias.push_back(criteria); | |
1149 } | |
1150 } | |
1151 } | |
1152 | |
1153 // Remove useless config sections. | |
1154 if (!is_input_class_section || | |
1155 (config->criterias.empty() && config->properties.empty())) { | |
1156 configurations_.pop_back(); | |
1157 } | |
1158 } | |
1159 } | |
1160 | |
1161 internal::MatchCriteria* GesturePropertyProvider::CreateMatchCriteria( | |
1162 const std::string& match_type, | |
1163 const std::string& arg) { | |
1164 GPROP_LOG(INFO_SEVERITY) << "Creating match criteria: (" << match_type << ", " | |
1165 << arg << ")"; | |
1166 if (match_type == "MatchProduct") | |
1167 return new internal::MatchProduct(arg); | |
1168 if (match_type == "MatchDevicePath") | |
1169 return new internal::MatchDevicePath(arg); | |
1170 if (match_type == "MatchUSBID") | |
1171 return new internal::MatchUSBID(arg); | |
1172 if (match_type == "MatchIsPointer") | |
1173 return new internal::MatchIsPointer(arg); | |
1174 if (match_type == "MatchIsTouchpad") | |
1175 return new internal::MatchIsTouchpad(arg); | |
1176 if (match_type == "MatchIsTouchscreen") | |
1177 return new internal::MatchIsTouchscreen(arg); | |
1178 NOTREACHED(); | |
1179 return NULL; | |
1180 } | |
1181 | |
1182 GesturesProp* GesturePropertyProvider::CreateDefaultProperty( | |
1183 const std::string& name, | |
1184 const std::string& value) { | |
1185 // Our parsing rule: | |
1186 // 1. No hex or oct number is accepted. | |
1187 // 2. All numbers will be stored as double. | |
1188 // 3. Array elements can be separated by both white-spaces or commas. | |
1189 // 4. A token is treated as numeric either if it is one of the special | |
1190 // keywords for boolean values (on, true, yes, off, false, no) or if | |
1191 // base::StringToDouble succeeds. | |
1192 // 5. The property is treated as numeric if and only if all of its elements | |
1193 // (if any) are numerics. Otherwise, it will be treated as a string. | |
1194 // 6. A string property will be trimmed before storing its value. | |
1195 GPROP_LOG(INFO_SEVERITY) << "Creating default property: (" << name << ", " | |
1196 << value << ")"; | |
1197 | |
1198 // Parse elements one-by-one. | |
1199 std::string delimiters(base::kWhitespaceASCII); | |
1200 delimiters.append(","); | |
1201 base::StringTokenizer tokens(value, delimiters); | |
1202 bool is_all_numeric = true; | |
1203 std::vector<double> numbers; | |
1204 while (tokens.GetNext()) { | |
1205 // Skip empty tokens. | |
1206 std::string token(tokens.token()); | |
1207 if (token.empty()) | |
1208 continue; | |
1209 | |
1210 // Check if it is a boolean keyword. | |
1211 int bool_result = ParseBooleanKeyword(token); | |
1212 if (bool_result) { | |
1213 numbers.push_back(bool_result > 0); | |
1214 continue; | |
1215 } | |
1216 | |
1217 // Check if it is a number. | |
1218 double real_result; | |
1219 bool success = base::StringToDouble(token, &real_result); | |
1220 if (!success) { | |
1221 is_all_numeric = false; | |
1222 break; | |
1223 } | |
1224 numbers.push_back(real_result); | |
1225 } | |
1226 | |
1227 // Create the GesturesProp. Array properties need to contain at least one | |
1228 // number and may contain numbers only. | |
1229 GesturesProp* property = NULL; | |
1230 if (is_all_numeric && numbers.size()) { | |
1231 property = new GesturesDoubleProp( | |
1232 name, numbers.size(), NULL, numbers.data(), NULL); | |
1233 } else { | |
1234 property = new GesturesStringProp(name, NULL, value.c_str(), NULL); | |
1235 } | |
1236 | |
1237 GPROP_LOG(INFO_SEVERITY) << "Prop: " << *property; | |
1238 // The function will always succeed for now but it may change later if we | |
1239 // specify some name or args as invalid. | |
1240 return property; | |
1241 } | |
1242 | |
1243 void GesturePropertyProvider::SetupDefaultProperties(const DeviceId device_id, | |
1244 const DevicePtr device) { | |
1245 GPROP_LOG(INFO_SEVERITY) << "Setting up default properties for (" << device | |
1246 << ", " << device_id << ", " << device->info.name | |
1247 << ")"; | |
1248 | |
1249 // Go through all parsed sections. | |
1250 internal::PropertiesMap& property_map = | |
1251 device_data_map_.get(device_id)->default_properties; | |
1252 for (size_t i = 0; i < configurations_.size(); ++i) { | |
1253 if (configurations_[i]->Match(device)) { | |
1254 GPROP_LOG(INFO_SEVERITY) << "Conf section \"" | |
1255 << configurations_[i]->identifier | |
1256 << "\" is matched"; | |
1257 for (size_t j = 0; j < configurations_[i]->properties.size(); j++) { | |
1258 GesturesProp* property = configurations_[i]->properties[j]; | |
1259 // We can't use insert here because a property may be set for several | |
1260 // times along the way. | |
1261 property_map[property->name()] = property; | |
1262 } | |
1263 } | |
1264 } | |
1265 } | |
1266 | |
1267 GesturesProp* GesturesPropFunctionsWrapper::CreateInt(void* device_data, | |
1268 const char* name, | |
1269 int* value, | |
1270 size_t count, | |
1271 const int* init) { | |
1272 return CreateProperty<int, GesturesIntProp>( | |
1273 device_data, name, value, count, init); | |
1274 } | |
1275 | |
1276 GesturesProp* GesturesPropFunctionsWrapper::CreateShort(void* device_data, | |
1277 const char* name, | |
1278 short* value, | |
1279 size_t count, | |
1280 const short* init) { | |
1281 return CreateProperty<short, GesturesShortProp>( | |
1282 device_data, name, value, count, init); | |
1283 } | |
1284 | |
1285 GesturesProp* GesturesPropFunctionsWrapper::CreateBool( | |
1286 void* device_data, | |
1287 const char* name, | |
1288 GesturesPropBool* value, | |
1289 size_t count, | |
1290 const GesturesPropBool* init) { | |
1291 return CreateProperty<GesturesPropBool, GesturesBoolProp>( | |
1292 device_data, name, value, count, init); | |
1293 } | |
1294 | |
1295 GesturesProp* GesturesPropFunctionsWrapper::CreateReal(void* device_data, | |
1296 const char* name, | |
1297 double* value, | |
1298 size_t count, | |
1299 const double* init) { | |
1300 return CreateProperty<double, GesturesDoubleProp>( | |
1301 device_data, name, value, count, init); | |
1302 } | |
1303 | |
1304 GesturesProp* GesturesPropFunctionsWrapper::CreateString(void* device_data, | |
1305 const char* name, | |
1306 const char** value, | |
1307 const char* init) { | |
1308 GesturesProp* default_property = NULL; | |
1309 if (!PreCreateProperty(device_data, name, &default_property)) | |
1310 return NULL; | |
1311 GesturesProp* property = | |
1312 new GesturesStringProp(name, value, init, default_property); | |
1313 | |
1314 PostCreateProperty(device_data, name, property); | |
1315 return property; | |
1316 } | |
1317 | |
1318 void GesturesPropFunctionsWrapper::RegisterHandlers( | |
1319 void* device_data, | |
1320 GesturesProp* property, | |
1321 void* handler_data, | |
1322 GesturesPropGetHandler get, | |
1323 GesturesPropSetHandler set) { | |
1324 // Sanity checks | |
1325 if (!device_data || !property) | |
1326 return; | |
1327 | |
1328 property->SetHandlers(get, set, handler_data); | |
1329 } | |
1330 | |
1331 void GesturesPropFunctionsWrapper::Free(void* device_data, | |
1332 GesturesProp* property) { | |
1333 if (!property) | |
1334 return; | |
1335 GesturePropertyProvider* provider = GetPropertyProvider(device_data); | |
1336 | |
1337 // No need to manually delete the prop pointer as it is implicitly handled | |
1338 // with scoped ptr. | |
1339 GPROP_LOG(3) << "Freeing Property: \"" << property->name() << "\""; | |
1340 provider->DeleteProperty(GetDeviceId(device_data), property->name()); | |
1341 } | |
1342 | |
1343 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties( | |
1344 void* device_data, | |
1345 GestureDeviceProperties* properties) { | |
1346 if (!device_data) | |
1347 return false; | |
1348 GesturePropertyProvider::DevicePtr device = GetDevicePointer(device_data); | |
1349 | |
1350 /* Create Device Properties */ | |
1351 | |
1352 // Read Only properties. | |
1353 CreateString( | |
1354 device_data, "Device Node", NULL, GetDeviceNodePath(device).c_str()); | |
1355 short vid = static_cast<short>(device->info.id.vendor); | |
1356 CreateShort(device_data, "Device Vendor ID", NULL, 1, &vid); | |
1357 short pid = static_cast<short>(device->info.id.product); | |
1358 CreateShort(device_data, "Device Product ID", NULL, 1, &pid); | |
1359 | |
1360 // Useable trackpad area. If not configured in .conf file, | |
1361 // use x/y valuator min/max as reported by kernel driver. | |
1362 CreateIntSingle(device_data, | |
1363 "Active Area Left", | |
1364 &properties->area_left, | |
1365 Event_Get_Left(device)); | |
1366 CreateIntSingle(device_data, | |
1367 "Active Area Right", | |
1368 &properties->area_right, | |
1369 Event_Get_Right(device)); | |
1370 CreateIntSingle(device_data, | |
1371 "Active Area Top", | |
1372 &properties->area_top, | |
1373 Event_Get_Top(device)); | |
1374 CreateIntSingle(device_data, | |
1375 "Active Area Bottom", | |
1376 &properties->area_bottom, | |
1377 Event_Get_Bottom(device)); | |
1378 | |
1379 // Trackpad resolution (pixels/mm). If not configured in .conf file, | |
1380 // use x/y resolution as reported by kernel driver. | |
1381 CreateIntSingle(device_data, | |
1382 "Vertical Resolution", | |
1383 &properties->res_y, | |
1384 Event_Get_Res_Y(device)); | |
1385 CreateIntSingle(device_data, | |
1386 "Horizontal Resolution", | |
1387 &properties->res_x, | |
1388 Event_Get_Res_X(device)); | |
1389 | |
1390 // Trackpad orientation minimum/maximum. If not configured in .conf file, | |
1391 // use min/max as reported by kernel driver. | |
1392 CreateIntSingle(device_data, | |
1393 "Orientation Minimum", | |
1394 &properties->orientation_minimum, | |
1395 Event_Get_Orientation_Minimum(device)); | |
1396 CreateIntSingle(device_data, | |
1397 "Orientation Maximum", | |
1398 &properties->orientation_maximum, | |
1399 Event_Get_Orientation_Maximum(device)); | |
1400 | |
1401 // Log dump property. Will call Event_Dump_Debug_Log when its value is being | |
1402 // set. | |
1403 GesturesProp* dump_debug_log_prop = CreateBoolSingle( | |
1404 device_data, "Dump Debug Log", &properties->dump_debug_log, false); | |
1405 RegisterHandlers( | |
1406 device_data, dump_debug_log_prop, device, NULL, Event_Dump_Debug_Log); | |
1407 | |
1408 // Whether to do the gesture recognition or just passing the multi-touch data | |
1409 // to upper layers. | |
1410 CreateBoolSingle(device_data, | |
1411 "Raw Touch Passthrough", | |
1412 &properties->raw_passthrough, | |
1413 false); | |
1414 return true; | |
1415 } | |
1416 | |
1417 void GesturesPropFunctionsWrapper::UnregisterDevice(void* device_data) { | |
1418 GesturePropertyProvider* provider = GetPropertyProvider(device_data); | |
1419 provider->UnregisterDevice(GetDeviceId(device_data)); | |
1420 } | |
1421 | |
1422 template <typename T, class PROPTYPE> | |
1423 GesturesProp* GesturesPropFunctionsWrapper::CreateProperty(void* device_data, | |
1424 const char* name, | |
1425 T* value, | |
1426 size_t count, | |
1427 const T* init) { | |
1428 // Create the property. Use the default property value if possible. | |
1429 GesturesProp* default_property = NULL; | |
1430 if (!PreCreateProperty(device_data, name, &default_property)) | |
1431 return NULL; | |
1432 GesturesProp* property = | |
1433 new PROPTYPE(name, count, value, init, default_property); | |
1434 | |
1435 // Start tracking the property in the provider. | |
1436 PostCreateProperty(device_data, name, property); | |
1437 return property; | |
1438 } | |
1439 | |
1440 bool GesturesPropFunctionsWrapper::PreCreateProperty( | |
1441 void* device_data, | |
1442 const char* name, | |
1443 GesturesProp** default_property) { | |
1444 GesturePropertyProvider* provider = GetPropertyProvider(device_data); | |
1445 GesturePropertyProvider::DeviceId device_id = GetDeviceId(device_data); | |
1446 | |
1447 // Register the device in the property provider if not yet. | |
1448 provider->RegisterDevice(device_id, GetDevicePointer(device_data)); | |
1449 | |
1450 // First, see if the GesturesProp already exists. | |
1451 GPROP_LOG(3) << "Creating Property: \"" << name << "\""; | |
1452 GesturesProp* property = provider->FindProperty(device_id, name); | |
1453 | |
1454 // If so, delete it as we can't reuse the data structure (newly-created | |
1455 // property may have different data type and count, which are fixed upon | |
1456 // creation via the template mechanism). | |
1457 if (property) { | |
1458 LOG(WARNING) << "Gesture property \"" << name | |
1459 << "\" re-created. This shouldn't happen at the normal usage."; | |
1460 Free(device_data, property); | |
1461 } | |
1462 | |
1463 // Return the found default property from conf files (could be NULL). | |
1464 *default_property = provider->GetDefaultProperty(device_id, name); | |
1465 return true; | |
1466 } | |
1467 | |
1468 void GesturesPropFunctionsWrapper::PostCreateProperty(void* device_data, | |
1469 const char* name, | |
1470 GesturesProp* property) { | |
1471 // Add the property to the gesture property provider. The gesture property | |
1472 // provider will own it from now on. | |
1473 GesturePropertyProvider* provider = GetPropertyProvider(device_data); | |
1474 provider->AddProperty(GetDeviceId(device_data), name, property); | |
1475 | |
1476 // Log the creation. | |
1477 GPROP_LOG(INFO_SEVERITY) << "Created active prop: " << *property; | |
1478 } | |
1479 | |
1480 GesturesProp* GesturesPropFunctionsWrapper::CreateIntSingle(void* device_data, | |
1481 const char* name, | |
1482 int* value, | |
1483 int init) { | |
1484 return CreateInt(device_data, name, value, 1, &init); | |
1485 } | |
1486 | |
1487 GesturesProp* GesturesPropFunctionsWrapper::CreateBoolSingle( | |
1488 void* device_data, | |
1489 const char* name, | |
1490 GesturesPropBool* value, | |
1491 GesturesPropBool init) { | |
1492 return CreateBool(device_data, name, value, 1, &init); | |
1493 } | |
1494 | |
1495 GesturePropertyProvider* GesturesPropFunctionsWrapper::GetPropertyProvider( | |
1496 void* device_data) { | |
1497 return static_cast<GestureInterpreterLibevdevCros*>(device_data) | |
1498 ->property_provider(); | |
1499 } | |
1500 | |
1501 GesturePropertyProvider::DevicePtr | |
1502 GesturesPropFunctionsWrapper::GetDevicePointer(void* device_data) { | |
1503 return static_cast<GestureInterpreterLibevdevCros*>(device_data)->evdev(); | |
1504 } | |
1505 | |
1506 GesturePropertyProvider::DeviceId GesturesPropFunctionsWrapper::GetDeviceId( | |
1507 void* device_data) { | |
1508 return static_cast<GestureInterpreterLibevdevCros*>(device_data)->id(); | |
1509 } | |
1510 | |
1511 /* Global GesturesPropProvider | |
1512 * | |
1513 * Used by PropRegistry in GestureInterpreter to forward property value | |
1514 * creations from there. | |
1515 * */ | |
1516 const GesturesPropProvider kGesturePropProvider = { | |
1517 GesturesPropFunctionsWrapper::CreateInt, | |
1518 GesturesPropFunctionsWrapper::CreateShort, | |
1519 GesturesPropFunctionsWrapper::CreateBool, | |
1520 GesturesPropFunctionsWrapper::CreateString, | |
1521 GesturesPropFunctionsWrapper::CreateReal, | |
1522 GesturesPropFunctionsWrapper::RegisterHandlers, | |
1523 GesturesPropFunctionsWrapper::Free}; | |
1524 | |
1525 } // namespace ui | |
OLD | NEW |