Loading include/input/PropertyMap.h +7 −0 Original line number Diff line number Diff line Loading @@ -18,7 +18,10 @@ #include <android-base/result.h> #include <utils/Tokenizer.h> #include <string> #include <unordered_map> #include <unordered_set> namespace android { Loading Loading @@ -57,6 +60,9 @@ public: */ void addProperty(const std::string& key, const std::string& value); /* Returns a set of all property keys starting with the given prefix. */ std::unordered_set<std::string> getKeysWithPrefix(const std::string& prefix) const; /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) Loading @@ -65,6 +71,7 @@ public: bool tryGetProperty(const std::string& key, bool& outValue) const; bool tryGetProperty(const std::string& key, int32_t& outValue) const; bool tryGetProperty(const std::string& key, float& outValue) const; bool tryGetProperty(const std::string& key, double& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); Loading libs/input/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,7 @@ cc_library { cc_defaults { name: "libinput_fuzz_defaults", cpp_std: "c++20", host_supported: true, shared_libs: [ "libutils", Loading libs/input/PropertyMap.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ #define LOG_TAG "PropertyMap" #include <cstdlib> #include <input/PropertyMap.h> #include <log/log.h> Loading Loading @@ -44,6 +46,16 @@ void PropertyMap::addProperty(const std::string& key, const std::string& value) mProperties.emplace(key, value); } std::unordered_set<std::string> PropertyMap::getKeysWithPrefix(const std::string& prefix) const { std::unordered_set<std::string> keys; for (const auto& [key, _] : mProperties) { if (key.starts_with(prefix)) { keys.insert(key); } } return keys; } bool PropertyMap::hasProperty(const std::string& key) const { return mProperties.find(key) != mProperties.end(); } Loading Loading @@ -102,6 +114,23 @@ bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const return true; } bool PropertyMap::tryGetProperty(const std::string& key, double& outValue) const { std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; double value = strtod(stringValue.c_str(), &end); if (*end != '\0') { ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(), stringValue.c_str()); return false; } outValue = value; return true; } void PropertyMap::addAll(const PropertyMap* map) { for (const auto& [key, value] : map->mProperties) { mProperties.emplace(key, value); Loading services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <optional> #include <android/input.h> #include <ftl/enum.h> #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> Loading Loading @@ -216,6 +217,11 @@ void TouchpadInputMapper::dump(std::string& dump) { std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { if (!changes) { // First time configuration mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration()); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { std::optional<int32_t> displayId = mPointerController->getDisplayId(); ui::Rotation orientation = ui::ROTATION_0; Loading services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp +76 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,29 @@ std::string PropertyProvider::dump() const { return dump; } void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) { // For compatibility with the configuration file syntax, gesture property names in IDC files are // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property. const std::string gesturePropPrefix = "gestureProp."; for (const std::string key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) { std::string propertyName = key.substr(gesturePropPrefix.length()); for (size_t i = 0; i < propertyName.length(); i++) { if (propertyName[i] == '_') { propertyName[i] = ' '; } } auto it = mProperties.find(propertyName); if (it != mProperties.end()) { it->second.trySetFromIdcProperty(idcProperties, key); } else { ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.", propertyName.c_str()); } } } GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc, size_t count, const int* init) { const auto [it, inserted] = Loading Loading @@ -211,6 +234,59 @@ void GesturesProp::setRealValues(const std::vector<double>& values) { setValues(std::get<double*>(mDataPointer), values); } namespace { // Helper to std::visit with lambdas. template <typename... V> struct Visitor : V... {}; // explicit deduction guide (not needed as of C++20) template <typename... V> Visitor(V...) -> Visitor<V...>; } // namespace void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties, const std::string& propertyName) { if (mCount != 1) { ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.", mName.c_str()); return; } bool parsedSuccessfully = false; Visitor setVisitor{ [&](int*) { int32_t value; parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); if (parsedSuccessfully) { setIntValues({value}); } }, [&](GesturesPropBool*) { bool value; parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); if (parsedSuccessfully) { setBoolValues({value}); } }, [&](double*) { double value; parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); if (parsedSuccessfully) { setRealValues({value}); } }, [&](const char**) { ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.", mName.c_str()); }, }; std::visit(setVisitor, mDataPointer); ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" could set due to a type mismatch.", mName.c_str()); return; } template <typename T, typename U> const std::vector<T> GesturesProp::getValues(U* dataPointer) const { if (mGetter != nullptr) { Loading Loading
include/input/PropertyMap.h +7 −0 Original line number Diff line number Diff line Loading @@ -18,7 +18,10 @@ #include <android-base/result.h> #include <utils/Tokenizer.h> #include <string> #include <unordered_map> #include <unordered_set> namespace android { Loading Loading @@ -57,6 +60,9 @@ public: */ void addProperty(const std::string& key, const std::string& value); /* Returns a set of all property keys starting with the given prefix. */ std::unordered_set<std::string> getKeysWithPrefix(const std::string& prefix) const; /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) Loading @@ -65,6 +71,7 @@ public: bool tryGetProperty(const std::string& key, bool& outValue) const; bool tryGetProperty(const std::string& key, int32_t& outValue) const; bool tryGetProperty(const std::string& key, float& outValue) const; bool tryGetProperty(const std::string& key, double& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); Loading
libs/input/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,7 @@ cc_library { cc_defaults { name: "libinput_fuzz_defaults", cpp_std: "c++20", host_supported: true, shared_libs: [ "libutils", Loading
libs/input/PropertyMap.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ #define LOG_TAG "PropertyMap" #include <cstdlib> #include <input/PropertyMap.h> #include <log/log.h> Loading Loading @@ -44,6 +46,16 @@ void PropertyMap::addProperty(const std::string& key, const std::string& value) mProperties.emplace(key, value); } std::unordered_set<std::string> PropertyMap::getKeysWithPrefix(const std::string& prefix) const { std::unordered_set<std::string> keys; for (const auto& [key, _] : mProperties) { if (key.starts_with(prefix)) { keys.insert(key); } } return keys; } bool PropertyMap::hasProperty(const std::string& key) const { return mProperties.find(key) != mProperties.end(); } Loading Loading @@ -102,6 +114,23 @@ bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const return true; } bool PropertyMap::tryGetProperty(const std::string& key, double& outValue) const { std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; double value = strtod(stringValue.c_str(), &end); if (*end != '\0') { ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(), stringValue.c_str()); return false; } outValue = value; return true; } void PropertyMap::addAll(const PropertyMap* map) { for (const auto& [key, value] : map->mProperties) { mProperties.emplace(key, value); Loading
services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <optional> #include <android/input.h> #include <ftl/enum.h> #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> Loading Loading @@ -216,6 +217,11 @@ void TouchpadInputMapper::dump(std::string& dump) { std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { if (!changes) { // First time configuration mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration()); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { std::optional<int32_t> displayId = mPointerController->getDisplayId(); ui::Rotation orientation = ui::ROTATION_0; Loading
services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp +76 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,29 @@ std::string PropertyProvider::dump() const { return dump; } void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) { // For compatibility with the configuration file syntax, gesture property names in IDC files are // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property. const std::string gesturePropPrefix = "gestureProp."; for (const std::string key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) { std::string propertyName = key.substr(gesturePropPrefix.length()); for (size_t i = 0; i < propertyName.length(); i++) { if (propertyName[i] == '_') { propertyName[i] = ' '; } } auto it = mProperties.find(propertyName); if (it != mProperties.end()) { it->second.trySetFromIdcProperty(idcProperties, key); } else { ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.", propertyName.c_str()); } } } GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc, size_t count, const int* init) { const auto [it, inserted] = Loading Loading @@ -211,6 +234,59 @@ void GesturesProp::setRealValues(const std::vector<double>& values) { setValues(std::get<double*>(mDataPointer), values); } namespace { // Helper to std::visit with lambdas. template <typename... V> struct Visitor : V... {}; // explicit deduction guide (not needed as of C++20) template <typename... V> Visitor(V...) -> Visitor<V...>; } // namespace void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties, const std::string& propertyName) { if (mCount != 1) { ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.", mName.c_str()); return; } bool parsedSuccessfully = false; Visitor setVisitor{ [&](int*) { int32_t value; parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); if (parsedSuccessfully) { setIntValues({value}); } }, [&](GesturesPropBool*) { bool value; parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); if (parsedSuccessfully) { setBoolValues({value}); } }, [&](double*) { double value; parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value); if (parsedSuccessfully) { setRealValues({value}); } }, [&](const char**) { ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.", mName.c_str()); }, }; std::visit(setVisitor, mDataPointer); ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" could set due to a type mismatch.", mName.c_str()); return; } template <typename T, typename U> const std::vector<T> GesturesProp::getValues(U* dataPointer) const { if (mGetter != nullptr) { Loading