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