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

Side by Side Diff: ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc

Issue 545063006: ozone: evdev: Add gesture property provider (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add INFO_SEVERITY to log property activities. Useful for debugging before a property value setting … Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
6
7 #include <gestures/gestures.h>
8 #include <libevdev/libevdev.h>
9
10 #include <fnmatch.h>
11
12 #include <algorithm>
13 #include <iostream>
14 #include <set>
15
16 #include "base/files/file_enumerator.h"
17 #include "base/files/file_util.h"
18 #include "base/logging.h"
19 #include "base/memory/singleton.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/string_util.h"
25 #include "base/strings/stringize_macros.h"
26 #include "base/strings/stringprintf.h"
27
28 // Macro for registering match criteria derived classes.
29 #define REGISTER_MATCH_CRITERIA(NAME) \
30 match_criteria_map_[#NAME] = \
31 &ui::GesturePropertyProvider::AllocateMatchCriteria<NAME>
32
33 // Macro for GesturesProp data pointer deallocators.
34 #define REGISTER_GPROP_DEALLOCATOR(NAME, TYPE) \
35 InsertDeallocator<TYPE>(&result, ui::GesturePropertyProvider::NAME, is_array)
36
37 // Severity level for general info logging purpose.
38 #define INFO_SEVERITY INFO
39
40 /* Implementation of GesturesProp declared in gestures.h
41 *
42 * libgestures requires that this be in the top level namespace.
43 * */
44 struct GesturesProp {
45 GesturesProp()
46 : type(ui::GesturePropertyProvider::PT_INT),
47 count(1),
48 is_allocated(false),
49 is_managed_externally(true),
50 handler_data(NULL),
51 get(NULL),
52 set(NULL) {
53 val.v = NULL;
54 }
55 // Free the data pointer. Should never be called if the GesturesProp is
56 // created from the gesture lib side.
57 void Free() {
58 if (count > 1)
59 (*data_pointer_deallocator_map_[type])(val);
60 else
61 (*data_array_pointer_deallocator_map_[type])(val);
62 }
63
64 // For logging purpose.
65 friend std::ostream& operator<<(std::ostream& os, const GesturesProp& prop);
66
67 // Property name, type and number of elements.
68 std::string name;
69 ui::GesturePropertyProvider::PropertyType type;
70 size_t count;
71
72 // Data pointer.
73 union Data {
74 void* v;
75 int* i;
76 short* h;
77 GesturesPropBool* b;
78 std::string* s;
79 double* r;
80 } val;
81
82 // If the flag is on, it means the memory that the data pointer points to is
83 // allocated here. We will need to free the memory by ourselves when the
84 // GesturesProp is destroyed (GesturesPropFunctionsWrapper::Free is called).
85 bool is_allocated;
86
87 // If the flag is off, it means the GesturesProp is created by passing a NULL
88 // data pointer to the creator functions. We will need to free the memory by
89 // ourselves when the GesturePropertyProvider is destroyed because no other
90 // people will be able to do it. For GesturesProp created with non-NULL
91 // pointers, external users are responsible of handling its data memory (via
92 // the GesturesPropProvider APIs).
93 //
94 // Note that the flag is different from is_allocated because the string
95 // properties are always allocated here whether it is created with NULL or
96 // not. In short, if this flag is false, then is_allocated must be true.
97 bool is_managed_externally;
98
99 // Handler function pointers and the data to be passed to them when the
100 // property is accessed.
101 void* handler_data;
102 GesturesPropGetHandler get;
103 GesturesPropSetHandler set;
104 private:
105 // Trick for appropriately deallocating the data memory based on its type.
106 typedef std::map<ui::GesturePropertyProvider::PropertyType,
107 void (*)(GesturesProp::Data&)> DeallocatorMap;
108 template <typename T>
109 static void DataPointerDeallocator(Data& data) {
110 delete reinterpret_cast<T>(data.v);
111 }
112 template <typename T>
113 static void DataArrayPointerDeallocator(Data& data) {
114 delete[] reinterpret_cast<T>(data.v);
115 }
116 template <typename T>
117 static void InsertDeallocator(DeallocatorMap* deallocator_map,
118 ui::GesturePropertyProvider::PropertyType type,
119 const bool is_array) {
120 if (is_array) {
121 deallocator_map->insert(
122 std::make_pair(type, &DataArrayPointerDeallocator<T*>));
123 } else {
124 deallocator_map->insert(
125 std::make_pair(type, &DataPointerDeallocator<T*>));
126 }
127 }
128
129 // Populate deallocators in the deallocator map.
130 static DeallocatorMap CreateDataPointerDeallocatorMap(const bool is_array) {
131 DeallocatorMap result;
132 REGISTER_GPROP_DEALLOCATOR(PT_INT, int);
133 REGISTER_GPROP_DEALLOCATOR(PT_SHORT, short);
134 REGISTER_GPROP_DEALLOCATOR(PT_BOOL, GesturesPropBool);
135 REGISTER_GPROP_DEALLOCATOR(PT_STRING, std::string);
136 REGISTER_GPROP_DEALLOCATOR(PT_REAL, double);
137 return result;
138 }
139
140 // These deallocator maps store deallocators for different data types.
141 static DeallocatorMap data_pointer_deallocator_map_;
142 static DeallocatorMap data_array_pointer_deallocator_map_;
143 };
144
145 // Trick for initializing static map members.
146 GesturesProp::DeallocatorMap GesturesProp::data_pointer_deallocator_map_(
147 GesturesProp::CreateDataPointerDeallocatorMap(false));
148 GesturesProp::DeallocatorMap GesturesProp::data_array_pointer_deallocator_map_(
149 GesturesProp::CreateDataPointerDeallocatorMap(true));
150
151 // Property type logging function.
152 std::ostream& operator<<(std::ostream& out,
153 const ui::GesturePropertyProvider::PropertyType type) {
154 std::string s;
155 #define TYPE_CASE(TYPE) \
156 case (ui::GesturePropertyProvider::TYPE): \
157 s = #TYPE; \
158 break;
159 switch (type) {
160 TYPE_CASE(PT_INT);
161 TYPE_CASE(PT_SHORT);
162 TYPE_CASE(PT_BOOL);
163 TYPE_CASE(PT_STRING);
164 TYPE_CASE(PT_REAL);
165 default:
166 s = "Unknown type";
167 break;
168 }
169 #undef TYPE_CASE
170 return out << s;
171 }
172
173 // GesturesProp logging function.
174 std::ostream& operator<<(std::ostream& os, const GesturesProp& prop) {
175 os << "\"" << prop.name << "\", " << prop.type << ", " << prop.count << ", ("
176 << prop.is_allocated << ", " << prop.is_managed_externally << "), (";
177 bool known_prop_type = true;
178 for (size_t i = 0; (i < prop.count) && known_prop_type; i++) {
179 switch (prop.type) {
180 case ui::GesturePropertyProvider::PT_INT:
181 os << prop.val.i[i];
182 break;
183 case ui::GesturePropertyProvider::PT_SHORT:
184 os << prop.val.h[i];
185 break;
186 case ui::GesturePropertyProvider::PT_BOOL:
187 // Prevent the value being printed as characters.
188 os << static_cast<int>(prop.val.b[i]);
189 break;
190 case ui::GesturePropertyProvider::PT_STRING:
191 os << prop.val.s[i];
192 break;
193 case ui::GesturePropertyProvider::PT_REAL:
194 os << prop.val.r[i];
195 break;
196 default:
197 LOG(ERROR) << "Unknown gesture property type: " << prop.type;
198 known_prop_type = false;
199 break;
200 }
201 os << ", ";
202 }
203 os << ")";
204 return os;
205 }
206
207 namespace ui {
208
209 // The path that we will look for conf files.
210 const char kConfigurationFilePath[] = "/etc/gesture";
211
212 // We support only match types that have already been used. One should change
213 // this if we start using new types in the future. Note that most unsupported
214 // match types are either useless in CrOS or inapplicable to the non-X
215 // environment.
216 const char* kSupportedMatchTypes[] = {"MatchProduct",
217 "MatchDevicePath",
218 "MatchUSBID",
219 "MatchIsPointer",
220 "MatchIsTouchpad",
221 "MatchIsTouchscreen"};
222 const char* kUnsupportedMatchTypes[] = {"MatchVendor",
223 "MatchOS",
224 "MatchPnPID",
225 "MatchDriver",
226 "MatchTag",
227 "MatchLayout",
228 "MatchIsKeyboard",
229 "MatchIsJoystick",
230 "MatchIsTablet"};
231
232 // Special keywords for boolean values.
233 const char* kTrue[] = {"on", "true", "yes"};
234 const char* kFalse[] = {"off", "false", "no"};
235
236 // Trick to get the device path from a file descriptor.
237 std::string GetDeviceNodePath(void* dev) {
238 std::string proc_symlink =
239 "/proc/self/fd/" + base::IntToString(static_cast<Evdev*>(dev)->fd);
240 base::FilePath path;
241 if (!base::ReadSymbolicLink(base::FilePath(proc_symlink), &path))
242 return std::string();
243 return path.value();
244 }
245
246 GesturePropertyProvider* GesturePropertyProvider::GetInstance() {
247 return Singleton<GesturePropertyProvider>::get();
spang 2014/09/18 18:06:15 Instead of making it a singleton, please create th
248 }
249
250 GesturePropertyProvider::GesturePropertyProvider() : device_id_counter_(0) {
251 RegisterMatchCriterias();
252 LoadDeviceConfigurations();
253 }
254
255 GesturePropertyProvider::~GesturePropertyProvider() {
256 // Note that we don't need to free most GesturesProp data pointers - they are
257 // managed externally through the GesturesPropProvider APIs. However, some
258 // props are created by directly calling the APIs with NULL pointers so they
259 // still need to be handled here.
260 DevicePropertyMap::iterator it = properties_maps_.begin();
261 for (; it != properties_maps_.end(); ++it) {
262 PropertyMap::iterator ip = it->second->begin();
263 for (; ip != it->second->end(); ++ip)
264 if (!ip->second->is_managed_externally)
265 ip->second->Free();
266 delete it->second;
267 }
268
269 // We do need to free the data pointers for props in configurations_ as they
270 // are maintained by ourselves. The props in default_properties_maps_ are all
271 // referenced from configurations_ so they are OK.
272 for (size_t i = 0; i < configurations_.size(); i++) {
273 for (size_t j = 0; j < configurations_[i].criterias.size(); j++)
274 delete configurations_[i].criterias[j];
275 for (size_t j = 0; j < configurations_[i].properties.size(); j++)
276 configurations_[i].properties[j].Free();
277 }
278 DevicePropertyMap::iterator ip = default_properties_maps_.begin();
279 for (; ip != default_properties_maps_.end(); ++ip)
280 delete ip->second;
281 }
282
283 void GesturePropertyProvider::RegisterMatchCriterias() {
284 // TODO(sheckylin): Add a check here to make sure all match criterias in
285 // kSupportedMatchTypes is registered here. Otherwise, let the derived
286 // classess register themselves instead.
287 REGISTER_MATCH_CRITERIA(MatchProduct);
288 REGISTER_MATCH_CRITERIA(MatchDevicePath);
289 REGISTER_MATCH_CRITERIA(MatchUSBID);
290 REGISTER_MATCH_CRITERIA(MatchIsPointer);
291 REGISTER_MATCH_CRITERIA(MatchIsTouchpad);
292 REGISTER_MATCH_CRITERIA(MatchIsTouchscreen);
293 }
294
295 void GesturePropertyProvider::GetDeviceIndices(
296 const DeviceType type,
297 std::vector<DeviceId>* device_ids) {
298 device_ids->clear();
299 DeviceIdMap::iterator it = device_ids_map_.begin();
300 for (; it != device_ids_map_.end(); ++it) {
301 // Check if the device matches the type.
302 it->first;
303 device_ids->push_back(it->second);
304 }
305 }
306
307 GesturePropertyProvider::DeviceId GesturePropertyProvider::GetDeviceId(
308 DevicePtr dev,
309 const bool do_create) {
310 DeviceIdMap::iterator it = device_ids_map_.find(dev);
311 if (it != device_ids_map_.end())
312 return it->second;
313 if (!do_create)
314 return -1;
315
316 // Insert a new one if not exists.
317 // TODO(sheckylin): Replace this id generation scheme with a better one.
318 // The current way may result in memory leaks.
319 DeviceId id = device_id_counter_;
320 device_ids_map_[dev] = id;
321 properties_maps_[id] = new PropertyMap;
322 device_id_counter_ = (device_id_counter_ + 1) % kMaxDeviceNum;
323
324 // Apply default prop values for the device.
325 SetupDefaultProperties(id, dev);
326 return id;
327 }
328
329 void GesturePropertyProvider::GetProperty(const DeviceId device_id,
330 const std::string& name,
331 DeviceType* type,
332 PropertyValuePtr* val,
333 size_t* count) {
334 // Implement PropertyGet in cmt.
335 NOTIMPLEMENTED();
336 }
337
338 void GesturePropertyProvider::SetProperty(const DeviceId device_id,
339 const std::string& name,
340 const DeviceType type,
341 const PropertyValuePtr val,
342 const size_t count) {
343 // Implement PropertySet in cmt.
344 NOTIMPLEMENTED();
345 }
346
347 GesturePropertyProvider::MatchCriteria::MatchCriteria(const std::string& arg) {
348 // TODO(sheckylin): Should we trim all tokens here?
349 Tokenize(arg, "|", &args_);
350 }
351
352 GesturePropertyProvider::MatchProduct::MatchProduct(const std::string& arg)
353 : MatchCriteria(arg) {
354 }
355
356 bool GesturePropertyProvider::MatchProduct::Match(DevicePtr device) {
357 if (args_.empty())
358 return true;
359 std::string name(device->info.name);
360 for (size_t i = 0; i < args_.size(); i++)
361 if (name.find(args_[i]) != std::string::npos)
362 return true;
363 return false;
364 }
365
366 GesturePropertyProvider::MatchDevicePath::MatchDevicePath(
367 const std::string& arg)
368 : MatchCriteria(arg) {
369 }
370
371 bool GesturePropertyProvider::MatchDevicePath::Match(DevicePtr device) {
372 if (args_.empty())
373 return true;
374
375 // Check if the device path matches any pattern.
376 std::string path = GetDeviceNodePath(device);
377 if (path.empty())
378 return false;
379 for (size_t i = 0; i < args_.size(); i++)
380 if (fnmatch(args_[i].c_str(), path.c_str(), FNM_NOESCAPE) == 0)
381 return true;
382 return false;
383 }
384
385 GesturePropertyProvider::MatchUSBID::MatchUSBID(const std::string& arg)
386 : MatchCriteria(arg) {
387 // Check each pattern and split valid ones into vids and pids.
388 for (size_t i = 0; i < args_.size(); i++) {
389 if (!IsValidPattern(args_[i]))
390 continue;
391 std::vector<std::string> tokens;
392 base::SplitString(args_[i], ':', &tokens);
393 vid_patterns_.push_back(base::StringToLowerASCII(tokens[0]));
394 pid_patterns_.push_back(base::StringToLowerASCII(tokens[1]));
395 }
396 }
397
398 bool GesturePropertyProvider::MatchUSBID::Match(DevicePtr device) {
399 if (vid_patterns_.empty())
400 return true;
401 std::string vid = base::StringPrintf("%04x", device->info.id.vendor);
402 std::string pid = base::StringPrintf("%04x", device->info.id.product);
403 for (size_t i = 0; i < vid_patterns_.size(); i++) {
404 if (fnmatch(vid_patterns_[i].c_str(), vid.c_str(), FNM_NOESCAPE) == 0 &&
405 fnmatch(pid_patterns_[i].c_str(), pid.c_str(), FNM_NOESCAPE) == 0) {
406 return true;
407 }
408 }
409 return false;
410 }
411
412 bool GesturePropertyProvider::MatchUSBID::IsValidPattern(
413 const std::string& pattern) {
414 // Each USB id should be in the lsusb format, i.e., xxxx:xxxx. We choose to do
415 // a lazy check here: if the pattern contains wrong characters not in the hex
416 // number range, it won't be matched anyway.
417 int number_of_colons = 0;
418 size_t pos_of_colon = 0;
419 for (size_t i = 0; i < pattern.size(); i++)
420 if (pattern[i] == ':')
421 ++number_of_colons, pos_of_colon = i;
422 return (number_of_colons == 1) && (pos_of_colon != 0) &&
423 (pos_of_colon != pattern.size() - 1);
424 }
425
426 GesturePropertyProvider::MatchDeviceType::MatchDeviceType(
427 const std::string& arg)
428 : MatchCriteria(arg), value_(true), is_valid_(false) {
429 // Default value of a match criteria is true.
430 if (args_.empty())
431 args_.push_back("on");
432
433 // We care only about the first argument.
434 int value = ParseBooleanKeyword(args_[0]);
435 if (value) {
436 is_valid_ = true;
437 value_ = value > 0;
438 }
439 }
440
441 GesturePropertyProvider::MatchIsPointer::MatchIsPointer(const std::string& arg)
442 : MatchDeviceType(arg) {
443 }
444
445 bool GesturePropertyProvider::MatchIsPointer::Match(DevicePtr device) {
446 if (!is_valid_)
447 return true;
448 return (value_ == (device->info.evdev_class == EvdevClassMouse ||
449 device->info.evdev_class == EvdevClassMultitouchMouse));
450 }
451
452 GesturePropertyProvider::MatchIsTouchpad::MatchIsTouchpad(
453 const std::string& arg)
454 : MatchDeviceType(arg) {
455 }
456
457 bool GesturePropertyProvider::MatchIsTouchpad::Match(DevicePtr device) {
458 if (!is_valid_)
459 return true;
460 return (value_ == (device->info.evdev_class == EvdevClassTouchpad));
461 }
462
463 GesturePropertyProvider::MatchIsTouchscreen::MatchIsTouchscreen(
464 const std::string& arg)
465 : MatchDeviceType(arg) {
466 }
467
468 bool GesturePropertyProvider::MatchIsTouchscreen::Match(DevicePtr device) {
469 if (!is_valid_)
470 return true;
471 return (value_ == (device->info.evdev_class == EvdevClassTouchscreen));
472 }
473
474 bool GesturePropertyProvider::ConfigurationSection::Match(DevicePtr device) {
475 for (size_t i = 0; i < criterias.size(); ++i)
476 if (!criterias[i]->Match(device))
477 return false;
478 return true;
479 }
480
481 void GesturePropertyProvider::AddProperty(const DeviceId device_id,
482 const std::string& name,
483 GesturesProp* prop) {
484 // The look-up should never fail because ideally a property can only be
485 // created with GesturesPropCreate* functions from the gesture lib side.
486 // Therefore, we simply return on failure.
487 DevicePropertyMap::iterator it = properties_maps_.find(device_id);
488 if (it != properties_maps_.end())
489 it->second->insert(std::make_pair(name, prop));
490 }
491
492 void GesturePropertyProvider::DeleteProperty(const DeviceId device_id,
493 const std::string& name) {
494 DevicePropertyMap::iterator it = properties_maps_.find(device_id);
495 if (it != properties_maps_.end())
496 it->second->erase(name);
497 }
498
499 GesturesProp* GesturePropertyProvider::FindProperty(const DeviceId device_id,
500 const std::string& name) {
501 return FindProperty(properties_maps_, device_id, name);
502 }
503
504 GesturesProp* GesturePropertyProvider::FindProperty(
505 const DevicePropertyMap& device_property_map,
506 const DeviceId device_id,
507 const std::string& name) {
508 DevicePropertyMap::const_iterator ia = device_property_map.find(device_id);
509 if (ia == properties_maps_.end())
510 return NULL;
511 PropertyMap::const_iterator ib = ia->second->find(name);
512 if (ib == ia->second->end())
513 return NULL;
514 return ib->second;
515 }
516
517 GesturesProp* GesturePropertyProvider::GetDefaultProperty(
518 const DeviceId device_id,
519 const std::string& name) {
520 return FindProperty(default_properties_maps_, device_id, name);
521 }
522
523 void GesturePropertyProvider::LoadDeviceConfigurations() {
524 // Enumerate conf files and sort them lexicographically.
525 std::set<base::FilePath> files;
526 base::FileEnumerator file_enum(base::FilePath(kConfigurationFilePath),
527 false,
528 base::FileEnumerator::FILES,
529 "*.conf");
530 for (base::FilePath path = file_enum.Next(); !path.empty();
531 path = file_enum.Next()) {
532 files.insert(path);
533 }
534 LOG(INFO_SEVERITY) << files.size() << " conf files were found";
535
536 // Parse conf files one-by-one.
537 for (std::set<base::FilePath>::iterator file_iter = files.begin();
538 file_iter != files.end();
539 ++file_iter) {
540 LOG(INFO_SEVERITY) << "Parsing conf file: " << (*file_iter).value();
541 std::string content;
542 if (!base::ReadFileToString(*file_iter, &content)) {
543 LOG(ERROR) << "Can't loading gestures conf file: "
544 << (*file_iter).value();
545 continue;
546 }
547 ParseXorgConfFile(content);
548 }
549 }
550
551 void GesturePropertyProvider::ParseXorgConfFile(const std::string& content) {
552 // To simplify the parsing work, we made some assumption about the conf file
553 // format which doesn't exist in the original xorg-conf spec. Most important
554 // ones are:
555 // 1. All keywords and names are now case-sensitive. Also, underscores are not
556 // ignored.
557 // 2. Each entry takes up one and exactly one line in the file.
558 // 3. No negation of the option value even if the option name is prefixed with
559 // "No" as it may cause problems for option names that does start with "No"
560 // (e.g., "Non-linearity").
561
562 // Break the content into sections, lines and then pieces.
563 // Sections are delimited by the "EndSection" keyword.
564 // Lines are delimited by "\n".
565 // Pieces are delimited by all white-spaces.
566 std::vector<std::string> sections;
567 base::SplitStringUsingSubstr(content, "EndSection", &sections);
568 for (size_t i = 0; i < sections.size(); ++i) {
569 // Create a new configuration section.
570 configurations_.push_back(ConfigurationSection());
571 ConfigurationSection& config = configurations_.back();
572
573 // Break the section into lines.
574 base::StringTokenizer lines(sections[i], "\n");
575 bool is_input_class_section = true;
576 bool has_checked_section_type = false;
577 while (is_input_class_section && lines.GetNext()) {
578 // Parse the line w.r.t. the xorg-conf format.
579 std::string line(lines.token());
580
581 // Skip empty lines.
582 if (line.empty())
583 continue;
584
585 // Treat all whitespaces as delimiters.
586 base::StringTokenizer pieces(line, base::kWhitespaceASCII);
587 pieces.set_quote_chars("\"");
588 bool is_parsing = false;
589 bool has_error = false;
590 bool next_is_section_type = false;
591 bool next_is_option_name = false;
592 bool next_is_option_value = false;
593 bool next_is_match_criteria = false;
594 bool next_is_identifier = false;
595 std::string match_type, option_name;
596 while (pieces.GetNext()) {
597 std::string piece(pieces.token());
598
599 // Skip empty pieces.
600 if (piece.empty())
601 continue;
602
603 // See if we are currently parsing an entry or are still looking for
604 // one.
605 if (is_parsing) {
606 // Stop parsing the current line if the format is wrong.
607 if (piece.size() <= 2 || piece[0] != '\"' ||
608 piece[piece.size() - 1] != '\"') {
609 LOG(ERROR) << "Error parsing line: " << lines.token();
610 has_error = true;
611 if (next_is_section_type)
612 is_input_class_section = false;
613 break;
614 }
615
616 // Parse the arguments. Note that we don't break even if a whitespace
617 // string is passed. It will just be handled in various ways based on
618 // the entry type.
619 std::string arg;
620 base::TrimWhitespaceASCII(
621 piece.substr(1, piece.size() - 2), base::TRIM_ALL, &arg);
622 if (next_is_section_type) {
623 // We only care about InputClass sections.
624 if (arg != "InputClass") {
625 has_error = true;
626 is_input_class_section = false;
627 } else {
628 LOG(INFO_SEVERITY) << "New InputClass section found";
629 has_checked_section_type = true;
630 }
631 break;
632 } else if (next_is_identifier) {
633 LOG(INFO_SEVERITY) << "Identifier: " << arg;
634 config.identifier = arg;
635 next_is_identifier = false;
636 break;
637 } else if (next_is_option_name) {
638 // TODO(sheckylin): Support option "Ignore".
639 option_name = arg;
640 next_is_option_value = true;
641 next_is_option_name = false;
642 } else if (next_is_option_value) {
643 GesturesProp prop;
644 if(CreateDefaultProperty(option_name, arg, &prop))
645 config.properties.push_back(prop);
646 next_is_option_value = false;
647 break;
648 } else if (next_is_match_criteria) {
649 // Skip all match types that are not supported.
650 if (IsMatchTypeSupported(match_type)) {
651 MatchCriteria *criteria = CreateMatchCriteria(match_type, arg);
652 if (criteria)
653 config.criterias.push_back(criteria);
654 }
655 next_is_match_criteria = false;
656 break;
657 }
658 } else {
659 // If the section type hasn't been decided yet, look for it.
660 // Otherwise, look for valid entries according to the spec.
661 if (has_checked_section_type) {
662 if (piece == "Driver") {
663 // TODO(sheckylin): Support "Driver" so that we can force a device
664 // not to use the gesture lib.
665 NOTIMPLEMENTED();
666 break;
667 } else if (piece == "Identifier") {
668 is_parsing = true;
669 next_is_identifier = true;
670 continue;
671 } else if (piece == "Option") {
672 is_parsing = true;
673 next_is_option_name = true;
674 continue;
675 } else if (piece.size() > 5 && piece.compare(0, 5, "Match") == 0) {
676 match_type = piece;
677 is_parsing = true;
678 next_is_match_criteria = true;
679 continue;
680 }
681 } else if (piece == "Section") {
682 is_parsing = true;
683 next_is_section_type = true;
684 continue;
685 }
686
687 // If none of the above is found, check if the current piece starts a
688 // comment.
689 if (piece.empty() || piece[0] != '#') {
690 LOG(ERROR) << "Error parsing line: " << lines.token();
691 has_error = true;
692 }
693 break;
694 }
695 }
696
697 // The value of a boolean option is skipped (default is true).
698 if (!has_error && (next_is_option_value || next_is_match_criteria)) {
699 if (next_is_option_value) {
700 GesturesProp prop;
701 if (CreateDefaultProperty(option_name, "on", &prop))
702 config.properties.push_back(prop);
703 } else if (IsMatchTypeSupported(match_type) &&
704 IsDeviceMatchType(match_type)) {
705 MatchCriteria* criteria = CreateMatchCriteria(match_type, "on");
706 if (criteria)
707 config.criterias.push_back(criteria);
708 }
709 }
710 }
711
712 // Remove useless config sections.
713 if (!is_input_class_section ||
714 (config.criterias.empty() && config.properties.empty())) {
715 configurations_.pop_back();
716 }
717 }
718 }
719
720 bool GesturePropertyProvider::IsMatchTypeSupported(
721 const std::string& match_type) {
722 for (size_t i = 0; i < arraysize(kSupportedMatchTypes); i++)
723 if (match_type == kSupportedMatchTypes[i])
724 return true;
725 for (size_t i = 0; i < arraysize(kUnsupportedMatchTypes); i++) {
726 if (match_type == kUnsupportedMatchTypes[i]) {
727 LOG(ERROR) << "Unsupported gestures input class match type: "
728 << match_type;
729 return false;
730 }
731 }
732 return false;
733 }
734
735 bool GesturePropertyProvider::IsDeviceMatchType(
736 const std::string& match_type) {
737 return StartsWithASCII(match_type, "MatchIs", true);
738 }
739
740 GesturePropertyProvider::MatchCriteria*
741 GesturePropertyProvider::CreateMatchCriteria(const std::string& match_type,
742 const std::string& arg) {
743 LOG(INFO_SEVERITY) << "Creating match criteria: (" << match_type << ", "
744 << arg << ")";
745 return (this->*match_criteria_map_[match_type])(arg);
746 }
747
748 bool GesturePropertyProvider::CreateDefaultProperty(const std::string& name,
749 const std::string& value,
750 GesturesProp* prop) {
751 // Our parsing rule:
752 // 1. No hex or oct number is accepted.
753 // 2. All numbers will be stored as double.
754 // 3. Array elements can be separated by both white-spaces or commas.
755 // 4. A token is treated as numeric either if it is one of the special
756 // keywords for boolean values (on, true, yes, off, false, no) or if
757 // base::StringToDouble succeeds.
758 // 5. The property is treated as numeric if and only if all of its elements
759 // (if any) are numerics. Otherwise, it will be treated as a string.
760 // 6. A string property will be trimmed before storing its value.
761 LOG(INFO_SEVERITY) << "Creating default property: (" << name << ", " << value
762 << ")";
763
764 // Parse elements one-by-one.
765 std::string delimiters(base::kWhitespaceASCII);
766 delimiters.append(",");
767 base::StringTokenizer tokens(value, delimiters);
768 bool is_all_numeric = true;
769 std::vector<double> numbers;
770 while (tokens.GetNext()) {
771 // Skip empty tokens.
772 std::string token(tokens.token());
773 if (token.empty())
774 continue;
775
776 // Check if it is a boolean keyword.
777 int bool_result = ParseBooleanKeyword(token);
778 if (bool_result) {
779 numbers.push_back(bool_result > 0);
780 continue;
781 }
782
783 // Check if it is a number.
784 double real_result;
785 bool success = base::StringToDouble(token, &real_result);
786 if (!success) {
787 is_all_numeric = false;
788 break;
789 }
790 numbers.push_back(real_result);
791 }
792
793 // Setup GesturesProp data.
794 prop->name = name;
795 // Arrays need to contain at least one number and may contain numbers only.
796 if (is_all_numeric && numbers.size()) {
797 prop->type = PT_REAL;
798 prop->count = numbers.size();
799 prop->val.r = new double[numbers.size()];
800 std::copy(numbers.begin(), numbers.end(), prop->val.r);
801 } else {
802 prop->type = PT_STRING;
803 prop->count = 1;
804 std::string trimmed;
805 base::TrimWhitespaceASCII(value, base::TRIM_ALL, &trimmed);
806 prop->val.s = new std::string(trimmed);
807 }
808
809 LOG(INFO_SEVERITY) << "Prop: " << *prop;
810 // The function will always succeed for now but it may change later if we
811 // specify some name or args as invalid.
812 return true;
813 }
814
815 int GesturePropertyProvider::ParseBooleanKeyword(const std::string& value) {
816 for (size_t i = 0; i < arraysize(kTrue); i++)
817 if (LowerCaseEqualsASCII(value, kTrue[i]))
818 return 1;
819 for (size_t i = 0; i < arraysize(kFalse); i++)
820 if (LowerCaseEqualsASCII(value, kFalse[i]))
821 return -1;
822 return 0;
823 }
824
825 void GesturePropertyProvider::SetupDefaultProperties(
826 const DeviceId device_id,
827 DevicePtr dev) {
828 LOG(INFO_SEVERITY) << "Setting up default properties for (" << dev << ", "
829 << device_id << ", " << dev->info.name << ")";
830 PropertyMap* prop_map = new PropertyMap;
831 default_properties_maps_[device_id] = prop_map;
832
833 // Go through all parsed sections.
834 for (size_t i = 0; i < configurations_.size(); i++) {
835 if (configurations_[i].Match(dev)) {
836 LOG(INFO_SEVERITY) << "Conf section \"" << configurations_[i].identifier
837 << "\" is matched";
838 for (size_t j = 0; j < configurations_[i].properties.size(); j++) {
839 GesturesProp& prop = configurations_[i].properties[j];
840 // We can't use insert here because a property may be set for several
841 // times along the way.
842 (*prop_map)[prop.name] = &prop;
843 }
844 }
845 }
846 }
847
848 template <typename T>
849 GesturesProp* GesturesPropFunctionsWrapper::Create(
850 void* dev,
851 const char* name,
852 GesturePropertyProvider::PropertyType type,
853 T* val,
854 size_t count) {
855 // Create a new PropertyMap for the device if not exists already.
856 GesturePropertyProvider::DeviceId device_id =
857 GesturePropertyProvider::GetInstance()->GetDeviceId(dev, true);
858
859 /* Insert property and setup property values */
860
861 // First, see if the GesturesProp already exists.
862 DVLOG(3) << "Creating Property: \"" << name << "\"";
863 GesturesProp* prop =
864 GesturePropertyProvider::GetInstance()->FindProperty(device_id, name);
865 if (!prop) {
866 prop = new GesturesProp();
867 GesturePropertyProvider::GetInstance()->AddProperty(device_id, name, prop);
868 } else if (prop->is_allocated) {
869 // Free the data pointer if it was allocated here. This shouldn't happen in
870 // normal use cases (that a read only property being declared again).
871 // However, we want to prevent any possible memory leak if it does happen.
872 prop->Free();
873 }
874
875 // Set the values.
876 prop->name = name;
877 prop->type = type;
878 prop->count = count;
879
880 // Allocate memory for the data if a NULL pointer is provided.
881 if (!val) {
882 if (count > 1)
883 prop->val.v = new T[count];
884 else
885 prop->val.v = new T;
886 prop->is_allocated = true;
887 } else {
888 prop->val.v = val;
889 }
890 return prop;
891 }
892
893 template <typename T, GesturePropertyProvider::PropertyType type>
894 GesturesProp* GesturesPropFunctionsWrapper::CreateProperty(void* dev,
895 const char* name,
896 T* val,
897 size_t count,
898 const T* init) {
899 GesturesProp* result = Create(dev, name, type, val, count);
900 if (!val)
901 result->is_managed_externally = false;
902
903 // We currently assumed that we won't specify any array property in the
904 // configuration files. The code needs to be updated if the assumption becomes
905 // invalid in the future.
906 if (count == 1) {
907 GesturesProp* default_prop =
908 GesturePropertyProvider::GetInstance()->GetDefaultProperty(
909 GesturePropertyProvider::GetInstance()->GetDeviceId(dev), name);
910 if (!default_prop ||
911 default_prop->type == GesturePropertyProvider::PT_STRING) {
912 *(reinterpret_cast<T*>(result->val.v)) = *init;
913 } else {
914 LOG(INFO_SEVERITY) << "Default property found. Using its value ...";
915 // TODO(sheckylin): Handle value out-of-range (e.g., double to int).
916 *(reinterpret_cast<T*>(result->val.v)) =
917 static_cast<T>(*(default_prop->val.r));
918 }
919 }
920
921 LOG(INFO_SEVERITY) << "Created active prop: " << *result;
922 return result;
923 }
924
925 GesturesProp* GesturesPropFunctionsWrapper::CreateInt(void* dev,
926 const char* name,
927 int* val,
928 size_t count,
929 const int* init) {
930 return CreateProperty<int, GesturePropertyProvider::PT_INT>(
931 dev, name, val, count, init);
932 }
933
934 GesturesProp* GesturesPropFunctionsWrapper::CreateShort(void* dev,
935 const char* name,
936 short* val,
937 size_t count,
938 const short* init) {
939 return CreateProperty<short, GesturePropertyProvider::PT_SHORT>(
940 dev, name, val, count, init);
941 }
942
943 GesturesProp* GesturesPropFunctionsWrapper::CreateBool(
944 void* dev,
945 const char* name,
946 GesturesPropBool* val,
947 size_t count,
948 const GesturesPropBool* init) {
949 return CreateProperty<GesturesPropBool, GesturePropertyProvider::PT_BOOL>(
950 dev, name, val, count, init);
951 }
952
953 GesturesProp* GesturesPropFunctionsWrapper::CreateReal(void* dev,
954 const char* name,
955 double* val,
956 size_t count,
957 const double* init) {
958 return CreateProperty<double, GesturePropertyProvider::PT_REAL>(
959 dev, name, val, count, init);
960 }
961
962 GesturesProp* GesturesPropFunctionsWrapper::CreateString(void* dev,
963 const char* name,
964 const char** val,
965 const char* init) {
966 // StringProperty's memory is always allocated on this side instead of
967 // externally in the gesture lib as the original one will be destroyed right
968 // after the constructor call (check the design of StringProperty). To do
969 // this, we call the Create function with NULL pointer so that it always
970 // allocates.
971 GesturesProp* result = Create(dev,
972 name,
973 GesturePropertyProvider::PT_STRING,
974 static_cast<std::string*>(NULL),
975 1);
976 if (!val)
977 result->is_managed_externally = false;
978
979 GesturesProp* default_prop =
980 GesturePropertyProvider::GetInstance()->GetDefaultProperty(
981 GesturePropertyProvider::GetInstance()->GetDeviceId(dev), name);
982
983 // Setup its value just like the other data types.
984 if (!default_prop ||
985 default_prop->type != GesturePropertyProvider::PT_STRING) {
986 *(result->val.s) = init;
987 } else {
988 LOG(INFO_SEVERITY) << "Default property found. Using its value ...";
989 *(result->val.s) = *(default_prop->val.s);
990 }
991
992 // If the provided pointer is not NULL, replace its content
993 // (val_ of StringProperty) with the address of our allocated string.
994 // Note that we don't have to do this for the other data types as they will
995 // use the original data pointer if possible and it is unnecessary to do so
996 // if the pointer is NULL.
997 if (val)
998 *(val) = result->val.s->c_str();
999
1000 LOG(INFO_SEVERITY) << "Created active prop: " << *result;
1001 return result;
1002 }
1003
1004 void GesturesPropFunctionsWrapper::RegisterHandlers(
1005 void* priv,
1006 GesturesProp* prop,
1007 void* handler_data,
1008 GesturesPropGetHandler get,
1009 GesturesPropSetHandler set) {
1010 // Sanity checks
1011 if (!priv || !prop)
1012 return;
1013
1014 prop->handler_data = handler_data;
1015 prop->get = get;
1016 prop->set = set;
1017 }
1018
1019 void GesturesPropFunctionsWrapper::Free(void* priv, GesturesProp* prop) {
1020 if (!prop)
1021 return;
1022
1023 GesturePropertyProvider::DeviceId device_id =
1024 GesturePropertyProvider::GetInstance()->GetDeviceId(priv);
1025 if (device_id < 0)
1026 return;
1027
1028 DVLOG(3) << "Freeing Property: \"" << prop->name << "\"";
1029 GesturePropertyProvider::GetInstance()->DeleteProperty(device_id, prop->name);
1030 if (prop->is_allocated)
1031 prop->Free();
1032 delete prop;
1033 }
1034
1035 GesturesProp* GesturesPropFunctionsWrapper::CreateIntSingle(
1036 void* dev,
1037 const char* name,
1038 int* val,
1039 int init) {
1040 return CreateInt(dev, name, val, 1, &init);
1041 }
1042
1043 GesturesProp* GesturesPropFunctionsWrapper::CreateBoolSingle(
1044 void* dev,
1045 const char* name,
1046 GesturesPropBool* val,
1047 GesturesPropBool init) {
1048 return CreateBool(dev, name, val, 1, &init);
1049 }
1050
1051 bool GesturesPropFunctionsWrapper::InitializeDeviceProperties(
1052 void* device, GesturePropertyProvider::DeviceProperty* props) {
1053 if (!device)
1054 return false;
1055 GesturePropertyProvider::DevicePtr dev =
1056 static_cast<GesturePropertyProvider::DevicePtr>(device);
1057
1058 /* Create Device Properties */
1059
1060 // Read Only properties.
1061 CreateString(dev, "Device Node", NULL, GetDeviceNodePath(dev).c_str());
1062 CreateShort(dev,
1063 "Device Vendor ID",
1064 NULL,
1065 1,
1066 reinterpret_cast<short*>(&(dev->info.id.vendor)));
1067 CreateShort(dev,
1068 "Device Product ID",
1069 NULL,
1070 1,
1071 reinterpret_cast<short*>(&(dev->info.id.product)));
1072
1073 // Useable trackpad area. If not configured in .conf file,
1074 // use x/y valuator min/max as reported by kernel driver.
1075 CreateIntSingle(
1076 dev, "Active Area Left", &props->area_left, Event_Get_Left(dev));
1077 CreateIntSingle(
1078 dev, "Active Area Right", &props->area_right, Event_Get_Right(dev));
1079 CreateIntSingle(dev, "Active Area Top", &props->area_top, Event_Get_Top(dev));
1080 CreateIntSingle(
1081 dev, "Active Area Bottom", &props->area_bottom, Event_Get_Bottom(dev));
1082
1083 // Trackpad resolution (pixels/mm). If not configured in .conf file,
1084 // use x/y resolution as reported by kernel driver.
1085 CreateIntSingle(
1086 dev, "Vertical Resolution", &props->res_y, Event_Get_Res_Y(dev));
1087 CreateIntSingle(
1088 dev, "Horizontal Resolution", &props->res_x, Event_Get_Res_X(dev));
1089
1090 // Trackpad orientation minimum/maximum. If not configured in .conf file,
1091 // use min/max as reported by kernel driver.
1092 CreateIntSingle(dev,
1093 "Orientation Minimum",
1094 &props->orientation_minimum,
1095 Event_Get_Orientation_Minimum(dev));
1096 CreateIntSingle(dev,
1097 "Orientation Maximum",
1098 &props->orientation_maximum,
1099 Event_Get_Orientation_Maximum(dev));
1100
1101 // Log dump property. Will call Event_Dump_Debug_Log when its value is being
1102 // set.
1103 GesturesProp* dump_debug_log_prop =
1104 CreateBoolSingle(dev, "Dump Debug Log", &props->dump_debug_log, false);
1105 RegisterHandlers(dev, dump_debug_log_prop, dev, NULL, Event_Dump_Debug_Log);
1106
1107 // Whether to do the gesture recognition or just passing the multi-touch data
1108 // to upper layers.
1109 CreateBoolSingle(
1110 dev, "Raw Touch Passthrough", &props->raw_passthrough, false);
1111 return true;
1112 }
1113
1114 /* Global GesturesPropProvider
1115 *
1116 * Used by PropRegistry in GestureInterpreter to forward property value
1117 * creations from there.
1118 * */
1119 const GesturesPropProvider kGesturePropProvider = {
1120 GesturesPropFunctionsWrapper::CreateInt,
1121 GesturesPropFunctionsWrapper::CreateShort,
1122 GesturesPropFunctionsWrapper::CreateBool,
1123 GesturesPropFunctionsWrapper::CreateString,
1124 GesturesPropFunctionsWrapper::CreateReal,
1125 GesturesPropFunctionsWrapper::RegisterHandlers,
1126 GesturesPropFunctionsWrapper::Free};
1127
1128 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698