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