From 62095a3e37ccc292a3570a22957602a11f4979f9 Mon Sep 17 00:00:00 2001 From: pixl Date: Tue, 11 Jan 2022 18:01:14 -0500 Subject: [PATCH 1/4] Require C++20 --- src/logid/CMakeLists.txt | 3 ++- src/logid/util/mutex_queue.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 45a9fd0..3fe8150 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.10) project(logid) -set(CMAKE_CXX_STANDARD 17) +# C++20 is only needed for string literal template parameters +set(CMAKE_CXX_STANDARD 20) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../CMake") diff --git a/src/logid/util/mutex_queue.h b/src/logid/util/mutex_queue.h index 9efc927..95e6f8c 100644 --- a/src/logid/util/mutex_queue.h +++ b/src/logid/util/mutex_queue.h @@ -26,7 +26,7 @@ template class mutex_queue { public: - mutex_queue() = default; + mutex_queue() = default; bool empty() { std::lock_guard lock(_mutex); From fbc3a1a4722b5dd5af73b38049ebef9bacae8ffb Mon Sep 17 00:00:00 2001 From: pixl Date: Tue, 11 Jan 2022 18:02:40 -0500 Subject: [PATCH 2/4] Added refined config struct templates --- src/logid/config/group.h | 206 ++++++++++++++++++++ src/logid/config/map.h | 46 +++++ src/logid/config/types.h | 398 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 650 insertions(+) create mode 100644 src/logid/config/group.h create mode 100644 src/logid/config/map.h create mode 100644 src/logid/config/types.h diff --git a/src/logid/config/group.h b/src/logid/config/group.h new file mode 100644 index 0000000..9179b16 --- /dev/null +++ b/src/logid/config/group.h @@ -0,0 +1,206 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef LOGID_CONFIG_GROUP_H +#define LOGID_CONFIG_GROUP_H + +#include +#include +#include +#include +#include "../util/log.h" + +namespace logid::config { + template + void set(libconfig::Setting& parent, + const std::string& name, + const T& t); + + template + void set(libconfig::Setting& parent, const T& t); + + template + T get(const libconfig::Setting& parent, const std::string& name); + + template + void append(libconfig::Setting& list, const T& t); + + namespace { + template + struct group_io { }; + + template + struct group_io { + static void get( + [[maybe_unused]] const libconfig::Setting& s, + [[maybe_unused]] T* t, + [[maybe_unused]] const std::vector& names, + [[maybe_unused]] const std::size_t index) { } + static void set( + [[maybe_unused]] libconfig::Setting& s, + [[maybe_unused]] const T* t, + [[maybe_unused]] const std::vector& names, + [[maybe_unused]] const std::size_t index) { } + }; + + template + struct group_io { + static void get( + const libconfig::Setting& s, T* t, + const std::vector& names, + const std::size_t index, A T::* arg, M T::*... rest) { + auto& x = t->*(arg); + A old {x}; + try { + x = config::get(s, names[index]); + group_io::get(s, t, names, index+1, rest...); + } catch(libconfig::SettingTypeException& e) { + x = old; + throw; + } catch(libconfig::SettingException& e) { + x = old; + throw libconfig::SettingTypeException(s); + } + } + + static void set( + libconfig::Setting& s, const T* t, + const std::vector& names, + const std::size_t index, A T::* arg, M T::*... rest) { + config::set(s, names[index], t->*(arg)); + group_io::set(s, t, names, index+1, rest...); + } + }; + } + + template + struct signed_group; + + struct group { + private: + const std::vector _names; + const std::function&)> _getter; + const std::function&)> _setter; + + template + friend struct signed_group; + protected: + template + group(const std::array& names, + M T::*... args) : + _names (names.begin(), names.end()), + _getter ([args...](const libconfig::Setting& s, group* g, + const std::vector& names) { + T* t = dynamic_cast(g); + group_io::get(s, t, names, 0, args...); + }), + _setter ([args...](libconfig::Setting& s, const group* g, + const std::vector& names) { + const T* t = dynamic_cast(g);; + group_io::set(s, t, names, 0, args...); + }) { + static_assert(std::is_base_of::value); + } + + group() : _getter ([](const libconfig::Setting&, group*, + const std::vector&) { }), + _setter ([](libconfig::Setting&, const group*, + const std::vector&) { }) { } + + public: + group(const group& o) = default; + group(group&& o) noexcept = default; + group& operator=(const group&) { + return *this; + } + group& operator=(group&&) noexcept { + return *this; + } + + virtual ~group() = default; + + virtual void save(libconfig::Setting& setting) const { + _setter(setting, this, _names); + } + + virtual void load(const libconfig::Setting& setting) { + _getter(setting, this, _names); + } + }; + + namespace { + template + struct normalize_signature { + static const T& make(const T& ret) { return ret; } + }; + + template <> + struct normalize_signature { + static std::string make(const std::string& data) { + std::string ret = data; + std::transform(ret.begin(), ret.end(), + ret.begin(), ::tolower); + return ret; + } + }; + } + + template + struct signed_group : public group { + private: + const std::string _sig_field; + const Sign _signature; + protected: + signed_group(std::string sign_name, const Sign& sign_data) : + group(), _sig_field (std::move(sign_name)), + _signature (normalize_signature::make(sign_data)) { } + + template + signed_group( + std::string sign_name, const Sign& sign_data, + const std::array& names, + M T::*... args) : group(names, args...), + _sig_field (std::move(sign_name)), + _signature (normalize_signature::make(sign_data)) { } + public: + signed_group(const signed_group& o) = default; + signed_group(signed_group&& o) noexcept = default; + signed_group& operator=(const signed_group&) { + return *this; + } + signed_group& operator=(signed_group&&) noexcept { + return *this; + } + + void save(libconfig::Setting& setting) const override { + set(setting, _signature, _sig_field); + _setter(setting, this, _names); + } + + void load(const libconfig::Setting& setting) override { + if(normalize_signature::make(get(setting, _sig_field)) + != _signature) + throw libconfig::SettingTypeException(setting); + _getter(setting, this, _names); + } + }; + +} + +#endif //LOGID_CONFIG_GROUP_H diff --git a/src/logid/config/map.h b/src/logid/config/map.h new file mode 100644 index 0000000..8543bc3 --- /dev/null +++ b/src/logid/config/map.h @@ -0,0 +1,46 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef LOGID_CONFIG_MAP_H +#define LOGID_CONFIG_MAP_H + +#include "group.h" +#include +#include +#include + +namespace logid::config { + template + struct string_literal { + constexpr string_literal(const char (&str)[N]) { + std::copy_n(str, N, value); + } + + char value[N]; + }; + + // Warning: map must be a variant of groups or a group + template + class map : public std::map { + public: + template + map(Args... args) : + std::map(std::forward(args)...) { } + }; +} + +#endif //LOGID_CONFIG_MAP_H diff --git a/src/logid/config/types.h b/src/logid/config/types.h new file mode 100644 index 0000000..a8a8393 --- /dev/null +++ b/src/logid/config/types.h @@ -0,0 +1,398 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef LOGID_CONFIG_PRIMITIVE_H +#define LOGID_CONFIG_PRIMITIVE_H + +#include +#include +#include +#include +#include "group.h" +#include "map.h" +#include "../util/log.h" + +/// TODO: A single element failing should not cause the container to be invalid. + +namespace logid::config { + namespace { + template + struct config_io { + static_assert(std::is_base_of::value); + + static T get(const libconfig::Setting& parent, + const std::string& name) { + T t {}; + t.load(parent.lookup(name)); + return t; + } + + static T get(const libconfig::Setting& setting) { + T t {}; + t.load(setting); + return t; + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + if(!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeGroup); + } else if(parent.lookup(name).getType() + != libconfig::Setting::TypeGroup) { + + } + t.save(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, const T& t) { + t.save(setting); + } + + static void append(libconfig::Setting& list, const T& t) { + auto& x = list.add(libconfig::Setting::TypeGroup); + set(x, t); + } + }; + + template + struct primitive_io { + static T get(const libconfig::Setting& parent, + const std::string& name) { + return parent.lookup(name); + } + + static T get(const libconfig::Setting& setting) { + return setting; + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + if(!parent.exists(name)) + parent.add(name, TypeEnum); + set(parent.lookup(name), t); + } + + static void set(libconfig::Setting& setting, const T& t) { + setting = t; + } + + static void append(libconfig::Setting& list, const T& t) { + auto& x = list.add(TypeEnum); + set(x, t); + } + }; + + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + template <> + struct config_io : public primitive_io { }; + + template + struct config_io> { + private: + template + static std::variant try_each( + const libconfig::Setting& setting) { + try { + return config_io::get(setting); + } catch(libconfig::SettingTypeException& e) { + throw; + } + } + + template + static std::variant try_each( + const libconfig::Setting& setting) { + try { + return config_io::get(setting); + } catch(libconfig::SettingException& e) { + return try_each(setting); + } + } + public: + static std::variant get(const libconfig::Setting& setting) { + return try_each(setting); + } + + static std::variant get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::variant& t) { + std::visit([&setting](auto&& arg){ + config::set(setting, arg); + }, t); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::variant& t) { + std::visit([&parent, &name](auto&& arg){ + config::set(parent, name, arg); + }, t); + } + + static void append(libconfig::Setting& list, + const std::variant& t) { + std::visit([&list](auto&& arg){ + config::append(list, arg); + }, t); + } + }; + + template + struct config_io> { + static std::vector get(const libconfig::Setting& setting) { + const auto size = setting.getLength(); + std::vector t(size); + for(int i = 0; i < size; ++i) + t[i] = config_io::get(setting[i]); + return t; + } + + static std::vector get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::vector& t) { + const auto orig_size = setting.getLength(); + for(int i = 0; i < orig_size; ++i) + config_io::set(setting[i], t[i]); + for(int i = orig_size; i < t.size(); ++i) + config_io::append(setting, t[i]); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::vector& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeArray); + } else if(!parent.lookup(name).isArray()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeArray); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const std::vector& t) { + auto& s = list.add(libconfig::Setting::TypeArray); + set(s, t); + } + }; + + template + struct config_io> { + static map get(const libconfig::Setting& setting) { + const auto size = setting.getLength(); + map t; + for(int i = 0; i < size; ++i) { + auto& s = setting[i]; + t.emplace(config_io::get(s.lookup(KeyName.value)), + config_io::get(s)); + } + return t; + } + + static map get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const map& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(auto& x : t) { + auto& s = setting.add(libconfig::Setting::TypeGroup); + config_io::set(s, x.second); + config_io::set(s, KeyName.value, x.first); + } + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const map& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isArray()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeList); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const map& t) { + auto& s = list.add(libconfig::Setting::TypeList); + set(s, t); + } + }; + + template + struct config_io>> { + static std::vector> get( + const libconfig::Setting& setting) { + const auto size = setting.getLength(); + std::vector> t(size); + for(int i = 0; i < size; ++i) + t[i] = config_io>::get(setting[i]); + return t; + } + + static std::vector> get( + const libconfig::Setting& parent, const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::vector>& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(int i = 0; i < t.size(); ++i) + config_io>::append(setting, t[i]); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::vector>& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isList()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeList); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const std::variant>& t) { + auto& s = list.add(libconfig::Setting::TypeList); + set(s, t); + } + }; + + template + struct config_io> { + static std::optional get(const libconfig::Setting& parent, + const std::string& name) { + try { + return config_io::get(parent.lookup(name)); + } catch(libconfig::SettingException& e) { + return {}; + } + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::optional& t) { + if (t.has_value()) + config_io::set(parent, name, t.value()); + } + }; + + // Optionals may not appear as part of a list or array + template + struct config_io, Rest...>> { + static_assert(!sizeof(std::optional), "Invalid type"); + }; + + template + struct config_io>> { + static_assert(!sizeof(std::optional), "Invalid type"); + }; + + template + struct config_io>> { + static_assert(!sizeof(std::optional), "Invalid type"); + }; + } + + template + void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + config_io::set(parent, name, t); + } + + template + void set(libconfig::Setting& setting, const T& t) { + config_io::set(setting, t); + } + + + template + void append(libconfig::Setting& list, const T& t) { + config_io::set(list, t); + } + + template + T get(const libconfig::Setting& setting) { + return config_io::get(setting); + } + + template + T get(const libconfig::Setting& parent, const std::string& name) { + return config_io::get(parent, name); + } +} + +#endif //LOGID_CONFIG_PRIMITIVE_H From c421affe2596afaac2c0e2959f1ff7507eeb8638 Mon Sep 17 00:00:00 2001 From: pixl Date: Tue, 11 Jan 2022 20:33:26 -0500 Subject: [PATCH 3/4] Add config schema --- src/logid/config/schema.h | 181 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/logid/config/schema.h diff --git a/src/logid/config/schema.h b/src/logid/config/schema.h new file mode 100644 index 0000000..cbf45a7 --- /dev/null +++ b/src/logid/config/schema.h @@ -0,0 +1,181 @@ +/* + * Copyright 2022 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef LOGID_CONFIG_SCHEMA_H +#define LOGID_CONFIG_SCHEMA_H + +#include "types.h" + +namespace logid::config { + struct NoAction : public signed_group { + NoAction() : signed_group("type", "None") { } + }; + + struct KeypressAction : public signed_group { + std::variant> keys; + KeypressAction() : signed_group( + "type", "Keypress", + {"keys"}, &KeypressAction::keys) { } + }; + + struct ToggleSmartShift : public signed_group { + ToggleSmartShift() : + signed_group("type", "ToggleSmartShift") { } + }; + + struct ToggleHiresScroll : public signed_group { + ToggleHiresScroll() : + signed_group("type", "ToggleHiresScroll") { } + }; + + struct CycleDPI : public signed_group { + std::vector dpis; + std::optional sensor; + CycleDPI() : signed_group( + "type", "CycleDPI", + {"dpis", "sensor"}, + &CycleDPI::dpis, + &CycleDPI::sensor) { } + }; + + struct ChangeDPI : public signed_group { + int inc; + std::optional sensor; + ChangeDPI() : signed_group( + "type", "ChangeDPI", + {"inc", "sensor"}, + &ChangeDPI::inc, + &ChangeDPI::sensor) { } + }; + + struct ChangeHost : public signed_group { + std::variant host; + ChangeHost() : signed_group( + "type", "ChangeHost", + {"host"}, &ChangeHost::host) { } + }; + + struct Gesture; + + struct GestureAction : public signed_group { + std::optional> _gestures; + + GestureAction() : signed_group( + "type", "Gestures") { } + }; + + typedef std::variant< + NoAction, + KeypressAction, + ToggleSmartShift, + ToggleHiresScroll, + CycleDPI, + ChangeDPI, + ChangeHost + > BasicAction; + + typedef std::variant< + NoAction, + KeypressAction, + ToggleSmartShift, + ToggleHiresScroll, + CycleDPI, + ChangeDPI, + ChangeHost, + GestureAction + > Action; + + struct Gesture : public group { + std::optional threshold; + std::optional mode; + std::optional axis; + std::optional axis_multiplier; + Action action; + + Gesture() : group( + {"threshold", "mode", "axis", "axis_multiplier"}, + &Gesture::threshold, + &Gesture::mode, + &Gesture::axis, + &Gesture::axis_multiplier + ) { } + }; + + struct Button : public group { + std::optional action; + Button() : group({"action"}, + &Button::action) { } + }; + + struct Smartshift : public group { + std::optional on; + std::optional threshold; + Smartshift() : group({"on", "threshold"}, + &Smartshift::on, &Smartshift::threshold) { } + }; + + + struct Hiresscroll : public group { + std::optional hires; + std::optional invert; + std::optional target; + Hiresscroll() : group({"hires", "invert", "target"}, + &Hiresscroll::hires, + &Hiresscroll::invert, + &Hiresscroll::target) { } + }; + + using DPI = std::variant>; + + + struct Profile : public group { + std::optional dpi; + std::optional smartshift; + std::optional> hiresscroll; + std::optional> buttons; + + Profile() : group({"dpi", "smartshift", "hiresscroll", "buttons"}, + &Profile::dpi, + &Profile::smartshift, + &Profile::hiresscroll, + &Profile::buttons) { } + }; + + struct Device : public group { + std::string default_profile; + map profiles; + + Device() : group({"default_profile", "profiles"}, + &Device::default_profile, + &Device::profiles) { } + }; + + struct Config : public group { + std::optional, "name">> devices; + std::optional> ignore; + std::optional io_timeout; + std::optional workers; + Config() : group({"devices", "ignore", "io_timeout", "workers"}, + &Config::devices, + &Config::ignore, + &Config::io_timeout, + &Config::workers) { } + }; +} + +#endif //LOGID_CONFIG_SCHEMA_H From 9b94fad0a6b840bb58a7470fe4f813e334389b29 Mon Sep 17 00:00:00 2001 From: pixl Date: Thu, 20 Jan 2022 01:29:18 -0500 Subject: [PATCH 4/4] Use new config interface --- src/ipcgull | 2 +- src/logid/Configuration.cpp | 167 +++---------- src/logid/Configuration.h | 33 +-- src/logid/Device.cpp | 152 +++--------- src/logid/Device.h | 28 +-- src/logid/DeviceManager.cpp | 15 +- src/logid/Receiver.cpp | 6 +- src/logid/actions/Action.cpp | 79 +++--- src/logid/actions/Action.h | 14 +- src/logid/actions/ChangeDPI.cpp | 52 +--- src/logid/actions/ChangeDPI.h | 15 +- src/logid/actions/ChangeHostAction.cpp | 85 ++----- src/logid/actions/ChangeHostAction.h | 14 +- src/logid/actions/CycleDPI.cpp | 82 +------ src/logid/actions/CycleDPI.h | 19 +- src/logid/actions/GestureAction.cpp | 197 ++++----------- src/logid/actions/GestureAction.h | 16 +- src/logid/actions/KeypressAction.cpp | 88 +++---- src/logid/actions/KeypressAction.h | 14 +- src/logid/actions/NullAction.h | 2 + src/logid/actions/ToggleHiresScroll.h | 3 + src/logid/actions/ToggleSmartShift.h | 3 + src/logid/actions/gesture/AxisGesture.cpp | 119 +++------ src/logid/actions/gesture/AxisGesture.h | 19 +- src/logid/actions/gesture/Gesture.cpp | 102 ++------ src/logid/actions/gesture/Gesture.h | 15 +- src/logid/actions/gesture/IntervalGesture.cpp | 64 ++--- src/logid/actions/gesture/IntervalGesture.h | 14 +- src/logid/actions/gesture/NullGesture.cpp | 11 +- src/logid/actions/gesture/NullGesture.h | 5 +- src/logid/actions/gesture/ReleaseGesture.cpp | 18 +- src/logid/actions/gesture/ReleaseGesture.h | 5 +- .../actions/gesture/ThresholdGesture.cpp | 24 +- src/logid/actions/gesture/ThresholdGesture.h | 5 +- src/logid/backend/dj/Receiver.cpp | 2 +- src/logid/backend/dj/Receiver.h | 2 +- src/logid/backend/dj/ReceiverMonitor.cpp | 2 +- src/logid/backend/dj/ReceiverMonitor.h | 2 +- src/logid/backend/hidpp/Device.cpp | 2 +- src/logid/backend/hidpp/Device.h | 2 +- src/logid/backend/hidpp10/Device.cpp | 2 +- src/logid/backend/hidpp10/Device.h | 2 +- src/logid/backend/hidpp20/Device.cpp | 3 +- src/logid/backend/hidpp20/Device.h | 3 +- src/logid/backend/raw/RawDevice.cpp | 5 +- src/logid/backend/raw/RawDevice.h | 2 +- src/logid/config/group.h | 8 +- src/logid/config/schema.h | 201 +++++++++++---- src/logid/config/types.h | 210 +++++++++------- src/logid/features/DPI.cpp | 68 ++---- src/logid/features/DPI.h | 13 +- src/logid/features/DeviceFeature.h | 9 - src/logid/features/DeviceStatus.cpp | 2 +- src/logid/features/HiresScroll.cpp | 228 ++++++------------ src/logid/features/HiresScroll.h | 29 +-- src/logid/features/RemapButton.cpp | 104 +++----- src/logid/features/RemapButton.h | 14 +- src/logid/features/SmartShift.cpp | 45 ++-- src/logid/features/SmartShift.h | 11 +- src/logid/features/ThumbWheel.cpp | 225 ++++++----------- src/logid/features/ThumbWheel.h | 38 +-- 61 files changed, 952 insertions(+), 1769 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index ac4cd8f..2255923 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit ac4cd8f52eb6d632e885c2b1ed3eb4b310897800 +Subproject commit 22559236d8c6e30aac640f79b8d4983467ba5cc8 diff --git a/src/logid/Configuration.cpp b/src/logid/Configuration.cpp index a5fad09..b87df91 100644 --- a/src/logid/Configuration.cpp +++ b/src/logid/Configuration.cpp @@ -25,154 +25,41 @@ using namespace logid; using namespace libconfig; -using namespace std::chrono; +using namespace logid::config; -Configuration::Configuration(const std::string& config_file) +Configuration::Configuration(const std::string& config_file) : + _config_file (config_file) { try { - _config.readFile(config_file.c_str()); + _config.readFile(_config_file); } catch(const FileIOException &e) { - logPrintf(ERROR, "I/O Error while reading %s: %s", config_file.c_str(), - e.what()); - throw e; + logPrintf(ERROR, "I/O Error while reading %s: %s", _config_file.c_str(), + e.what()); + throw; } catch(const ParseException &e) { logPrintf(ERROR, "Parse error in %s, line %d: %s", e.getFile(), - e.getLine(), e.getError()); - throw e; + e.getLine(), e.getError()); + throw; } - const Setting &root = _config.getRoot(); + Config::operator=(get(_config.getRoot())); + if(!devices.has_value()) + devices = decltype(config::Config::devices)(); +} + +void Configuration::save() +{ + config::set(_config.getRoot(), *this); try { - auto& worker_count = root["workers"]; - if(worker_count.getType() == Setting::TypeInt) { - _worker_threads = worker_count; - if(_worker_threads < 0) - logPrintf(WARN, "Line %d: workers cannot be negative.", - worker_count.getSourceLine()); - } else { - logPrintf(WARN, "Line %d: workers must be an integer.", - worker_count.getSourceLine()); - } - } catch(const SettingNotFoundException& e) { - // Ignore + _config.writeFile(_config_file); + } catch(const FileIOException &e) { + logPrintf(ERROR, "I/O Error while writing %s: %s", + _config_file.c_str(), e.what()); + throw; + } catch(const std::exception& e) { + logPrintf(ERROR, "Error while writing %s: %s", + _config_file.c_str(), e.what()); + throw; } - - try { - auto& timeout = root["io_timeout"]; - if(timeout.isNumber()) { - if(timeout.getType() == Setting::TypeFloat) - _io_timeout = duration_cast( - duration(timeout)); - else - _io_timeout = milliseconds((int)timeout); - } else - logPrintf(WARN, "Line %d: io_timeout must be a number.", - timeout.getSourceLine()); - } catch(const SettingNotFoundException& e) { - // Ignore - } - - try { - auto& devices = root["devices"]; - - for(int i = 0; i < devices.getLength(); i++) { - const Setting& device = devices[i]; - std::string name; - try { - if(!device.lookupValue("name", name)) { - logPrintf(WARN, "Line %d: 'name' must be a string, skipping" - " device.", device["name"].getSourceLine()); - continue; - } - } catch(SettingNotFoundException &e) { - logPrintf(WARN, "Line %d: Missing name field, skipping device." - , device.getSourceLine()); - continue; - } - _device_paths.insert({name, device.getPath()}); - } - } - catch(const SettingNotFoundException &e) { - logPrintf(WARN, "No devices listed in config file."); - } - - try { - auto& ignore = root.lookup("ignore"); - if(ignore.getType() == libconfig::Setting::TypeInt) { - _ignore_list.insert((int)ignore); - } else if(ignore.isList() || ignore.isArray()) { - int ignore_count = ignore.getLength(); - for(int i = 0; i < ignore_count; i++) { - if(ignore[i].getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: ignore must refer to device PIDs", - ignore[i].getSourceLine()); - if(ignore.isArray()) - break; - } else - _ignore_list.insert((int)ignore[i]); - } - } - } catch(const SettingNotFoundException& e) { - // May be called blacklist - try { - auto& ignore = root.lookup("blacklist"); - if(ignore.getType() == libconfig::Setting::TypeInt) { - _ignore_list.insert((int)ignore); - } else if(ignore.isList() || ignore.isArray()) { - int ignore_count = ignore.getLength(); - for(int i = 0; i < ignore_count; i++) { - if(ignore[i].getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: blacklist must refer to " - "device PIDs", - ignore[i].getSourceLine()); - if(ignore.isArray()) - break; - } else - _ignore_list.insert((int)ignore[i]); - } - } - } catch(const SettingNotFoundException& e) { - // Ignore - } - } -} - -libconfig::Setting& Configuration::getSetting(const std::string& path) -{ - return _config.lookup(path); -} - -std::string Configuration::getDevice(const std::string& name) -{ - auto it = _device_paths.find(name); - if(it == _device_paths.end()) - throw DeviceNotFound(name); - else - return it->second; -} - -bool Configuration::isIgnored(uint16_t pid) const -{ - return _ignore_list.find(pid) != _ignore_list.end(); -} - -Configuration::DeviceNotFound::DeviceNotFound(std::string name) : - _name (std::move(name)) -{ -} - -const char * Configuration::DeviceNotFound::what() const noexcept -{ - return _name.c_str(); -} - -int Configuration::workerCount() const -{ - return _worker_threads; -} - -std::chrono::milliseconds Configuration::ioTimeout() const -{ - return _io_timeout; -} +} \ No newline at end of file diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h index 8e63248..213d654 100644 --- a/src/logid/Configuration.h +++ b/src/logid/Configuration.h @@ -25,36 +25,27 @@ #include #include -#define LOGID_DEFAULT_IO_TIMEOUT std::chrono::milliseconds(400) -#define LOGID_DEFAULT_WORKER_COUNT 4 +#include "config/schema.h" namespace logid { - class Configuration + namespace defaults { + static constexpr double io_timeout = 500; + static constexpr int gesture_threshold = 50; + static constexpr int worker_count = 4; + } + + class Configuration : public config::Config { public: explicit Configuration(const std::string& config_file); Configuration() = default; - libconfig::Setting& getSetting(const std::string& path); - std::string getDevice(const std::string& name); - bool isIgnored(uint16_t pid) const; - class DeviceNotFound : public std::exception - { - public: - explicit DeviceNotFound(std::string name); - const char* what() const noexcept override; - private: - std::string _name; - }; - - std::chrono::milliseconds ioTimeout() const; - int workerCount() const; + // Reloading is not safe, references will be invalidated + //void reload(); + void save(); private: - std::map _device_paths; - std::set _ignore_list; - std::chrono::milliseconds _io_timeout = LOGID_DEFAULT_IO_TIMEOUT; - int _worker_threads = LOGID_DEFAULT_WORKER_COUNT; + std::string _config_file; libconfig::Config _config; }; diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index d93f3c8..2163e24 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -98,9 +98,10 @@ std::shared_ptr Device::make( Device::Device(std::string path, backend::hidpp::DeviceIndex index, std::shared_ptr manager) : _hidpp20 (path, index, - manager->config()->ioTimeout(), manager->workQueue()), + manager->config()->io_timeout.value_or(defaults::io_timeout), + manager->workQueue()), _path (std::move(path)), _index (index), - _config (manager->config(), this), + _config (_getConfig(manager, _hidpp20.name())), _receiver (nullptr), _manager (manager), _nickname (manager), @@ -115,7 +116,7 @@ Device::Device(std::shared_ptr raw_device, std::shared_ptr manager) : _hidpp20(raw_device, index), _path (raw_device->hidrawPath()), _index (index), - _config (manager->config(), this), + _config (_getConfig(manager, _hidpp20.name())), _receiver (nullptr), _manager (manager), _nickname (manager), @@ -129,7 +130,7 @@ Device::Device(Receiver* receiver, hidpp::DeviceIndex index, std::shared_ptr manager) : _hidpp20 (receiver->rawReceiver(), index), _path (receiver->path()), _index (index), - _config (manager->config(), this), + _config (_getConfig(manager, _hidpp20.name())), _receiver (receiver), _manager (manager), _nickname (manager), @@ -144,6 +145,10 @@ void Device::_init() logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(), hidpp20().devicePath().c_str(), _index); + _profile = _config.profiles.find(_config.default_profile); + if(_profile == _config.profiles.end()) + _profile = _config.profiles.insert({_config.default_profile, {}}).first; + _addFeature("dpi"); _addFeature("smartshift"); _addFeature("hiresscroll"); @@ -239,9 +244,18 @@ std::shared_ptr Device::ipcNode() const return _ipc_node; } -Device::Config& Device::config() +/*config::Device& Device::config() { return _config; +}*/ + +config::Profile& Device::activeProfile() +{ + return _profile->second; +} +const config::Profile& Device::activeProfile() const +{ + return _profile->second; } hidpp20::Device& Device::hidpp20() @@ -285,118 +299,28 @@ void Device::DeviceIPC::notifyStatus() const emit_signal("StatusChanged", (bool)(_device._awake)); } -Device::Config::Config(const std::shared_ptr& config, Device* - device) : _device (device), _config (config) +config::Device& Device::_getConfig( + const std::shared_ptr& manager, + const std::string& name) { - try { - _root_setting = config->getDevice(device->name()); - } catch(Configuration::DeviceNotFound& e) { - logPrintf(INFO, "Device %s not configured, using default config.", - device->name().c_str()); - return; + static std::mutex config_mutex; + std::lock_guard lock(config_mutex); + auto& devices = manager->config()->devices; + if(!devices.has_value()) + devices = decltype(config::Config::devices)(); + auto& device = devices.value()[name]; + if(std::holds_alternative(device)) { + config::Device d; + d.profiles["default"] = std::get(device); + d.default_profile = "default"; + device = std::move(d); } - try { - auto& profiles = _config->getSetting(_root_setting + "/profiles"); - int profile_index = 0; - if(!profiles.isList()) { - logPrintf(WARN, "Line %d: profiles must be a list, defaulting to" - "old-style config", profiles.getSourceLine()); - } - - try { - auto& default_profile = _config->getSetting(_root_setting + - "/default_profile"); - if(default_profile.getType() == libconfig::Setting::TypeString) { - _profile_name = (const char*)default_profile; - } else if(default_profile.isNumber()) { - profile_index = default_profile; - } else { - logPrintf(WARN, "Line %d: default_profile must be a string or" - " integer, defaulting to first profile", - default_profile.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(INFO, "Line %d: default_profile missing, defaulting to " - "first profile", profiles.getSourceLine()); - } - - if(profiles.getLength() <= profile_index) { - if(profiles.getLength() == 0) { - logPrintf(WARN, "Line %d: No profiles defined", - profiles.getSourceLine()); - } else { - logPrintf(WARN, "Line %d: default_profile does not exist, " - "defaulting to first", - profiles.getSourceLine()); - profile_index = 0; - } - } - - for(int i = 0; i < profiles.getLength(); i++) { - const auto& profile = profiles[i]; - std::string name; - if(!profile.isGroup()) { - logPrintf(WARN, "Line %d: Profile must be a group, " - "skipping", profile.getSourceLine()); - continue; - } - - try { - const auto& name_setting = profile.lookup("name"); - if(name_setting.getType() != - libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: Profile names must be " - "strings, using name \"%d\"", - name_setting.getSourceLine(), i); - name = std::to_string(i); - } else { - name = (const char *) name_setting; - } - - if(_profiles.find(name) != _profiles.end()) { - logPrintf(WARN, "Line %d: Profile with the same name " - "already exists, skipping.", - name_setting.getSourceLine()); - continue; - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(INFO, "Line %d: Profile is unnamed, using name " - "\"%d\"", profile.getSourceLine(), i); - } - - if(i == profile_index && _profile_name.empty()) - _profile_root = profile.getPath(); - _profiles[name] = profile.getPath(); - } - - if(_profiles.empty()) { - _profile_name = "0"; - } - - if(_profile_root.empty()) - _profile_root = _profiles[_profile_name]; - } catch(libconfig::SettingNotFoundException& e) { - // No profiles, default to root - _profile_root = _root_setting; + auto& conf = std::get(device); + if(conf.profiles.empty()) { + conf.profiles["default"] = std::get(device); + conf.default_profile = "default"; } -} -libconfig::Setting& Device::Config::getSetting(const std::string& path) -{ - if(_profile_root.empty()) - throw libconfig::SettingNotFoundException((_root_setting + '/' + - path).c_str()); - return _config->getSetting(_profile_root + '/' + path); -} - -const std::map & Device::Config::getProfiles() const -{ - return _profiles; -} - -void Device::Config::setProfile(const std::string &name) -{ - _profile_name = name; - _profile_root = _profiles[name]; + return conf; } diff --git a/src/logid/Device.h b/src/logid/Device.h index 21b1e15..0c143d9 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -59,7 +59,9 @@ namespace logid std::string name(); uint16_t pid(); - Config& config(); + //config::Device& config(); + config::Profile& activeProfile(); + const config::Profile& activeProfile() const; backend::hidpp20::Device& hidpp20(); static std::shared_ptr make( @@ -108,6 +110,10 @@ namespace logid Device(Receiver* receiver, backend::hidpp::DeviceIndex index, std::shared_ptr manager); + static config::Device& _getConfig( + const std::shared_ptr& manager, + const std::string& name); + void _init(); /* Adds a feature without calling an error if unsupported */ @@ -120,29 +126,13 @@ namespace logid } } - class Config - { - public: - Config(const std::shared_ptr& config, Device* - device); - libconfig::Setting& getSetting(const std::string& path); - const std::map& getProfiles() const; - void setProfile(const std::string& name); - private: - Device* _device; - std::string _root_setting; - std::string _profile_root; - std::string _profile_name; - std::map _profiles; - std::shared_ptr _config; - }; - backend::hidpp20::Device _hidpp20; std::string _path; backend::hidpp::DeviceIndex _index; std::map> _features; - Config _config; + config::Device& _config; + std::map::iterator _profile; Receiver* _receiver; const std::weak_ptr _manager; diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index a1b7978..854df9d 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -44,7 +44,7 @@ namespace logid { DeviceManager::DeviceManager(std::shared_ptr config, std::shared_ptr virtual_input, std::shared_ptr server) : - backend::raw::DeviceMonitor(config->workerCount()), + backend::raw::DeviceMonitor(config->workers.value_or(defaults::worker_count)), _server (std::move(server)), _config (std::move(config)), _virtual_input (std::move(virtual_input)), _root_node (ipcgull::node::make_root("")), @@ -95,8 +95,11 @@ void DeviceManager::addDevice(std::string path) // Check if device is ignored before continuing { - raw::RawDevice raw_dev(path, config()->ioTimeout(), workQueue()); - if(config()->isIgnored(raw_dev.productId())) { + raw::RawDevice raw_dev( + path,config()->io_timeout.value_or(defaults::io_timeout), + workQueue()); + if(config()->ignore.has_value() && + config()->ignore.value().contains(raw_dev.productId())) { logPrintf(DEBUG, "%s: Device 0x%04x ignored.", path.c_str(), raw_dev.productId()); return; @@ -104,8 +107,10 @@ void DeviceManager::addDevice(std::string path) } try { - hidpp::Device device(path, hidpp::DefaultDevice, - config()->ioTimeout(), workQueue()); + hidpp::Device device( + path, hidpp::DefaultDevice, + config()->io_timeout.value_or(defaults::io_timeout), + workQueue()); isReceiver = device.version() == std::make_tuple(1, 0); } catch(hidpp10::Error &e) { if(e.code() != hidpp10::Error::UnknownDevice) diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index e4e487e..cc1edaf 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -65,7 +65,8 @@ std::shared_ptr Receiver::make( Receiver::Receiver(const std::string& path, const std::shared_ptr& manager) : dj::ReceiverMonitor(path, - manager->config()->ioTimeout(), + manager->config()->io_timeout.value_or( + defaults::io_timeout), manager->workQueue()), _path (path), _manager (manager), _nickname (manager), _ipc_node (manager->receiversNode()->make_child(_nickname)), @@ -99,7 +100,8 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) try { // Check if device is ignored before continuing - if(manager->config()->isIgnored(event.pid)) { + if(manager->config()->ignore.value_or( + std::set()).contains(event.pid)) { logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.", _path.c_str(), event.index, event.pid); return; diff --git a/src/logid/actions/Action.cpp b/src/logid/actions/Action.cpp index ecac552..b93a28e 100644 --- a/src/logid/actions/Action.cpp +++ b/src/logid/actions/Action.cpp @@ -18,7 +18,6 @@ #include #include "Action.h" -#include "../util/log.h" #include "KeypressAction.h" #include "ToggleSmartShift.h" #include "ToggleHiresScroll.h" @@ -31,49 +30,39 @@ using namespace logid; using namespace logid::actions; -std::shared_ptr Action::makeAction(Device *device, libconfig::Setting - &setting) +template +struct action_type { + typedef typename T::action type; +}; + +template +struct action_type : action_type { }; + +template +struct action_type : action_type { }; + +template +std::shared_ptr _makeAction(Device* device, + T action) { + return std::make_shared::type>(device, action); +} + +std::shared_ptr Action::makeAction(Device *device, + config::BasicAction& action) { - if(!setting.isGroup()) { - logPrintf(WARN, "Line %d: Action is not a group, ignoring.", - setting.getSourceLine()); - throw InvalidAction(); - } + std::shared_ptr ret; + std::visit([&device, &ret](auto&& x) { + ret = _makeAction(device, x); + }, action); + return ret; +} - try { - auto& action_type = setting.lookup("type"); - - if(action_type.getType() != libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: Action type must be a string", - action_type.getSourceLine()); - throw InvalidAction(); - } - - std::string type = action_type; - std::transform(type.begin(), type.end(), type.begin(), ::tolower); - - if(type == "keypress") - return std::make_shared(device, setting); - else if(type == "togglesmartshift") - return std::make_shared(device); - else if(type == "togglehiresscroll") - return std::make_shared(device); - else if(type == "gestures") - return std::make_shared(device, setting); - else if(type == "cycledpi") - return std::make_shared(device, setting); - else if(type == "changedpi") - return std::make_shared(device, setting); - else if(type == "none") - return std::make_shared(device); - else if(type == "changehost") - return std::make_shared(device, setting); - else - throw InvalidAction(type); - - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: Action type is missing, ignoring.", - setting.getSourceLine()); - throw InvalidAction(); - } -} \ No newline at end of file +std::shared_ptr Action::makeAction(Device *device, + config::Action& action) +{ + std::shared_ptr ret; + std::visit([&device, &ret](auto&& x) { + ret = _makeAction(device, x); + }, action); + return ret; +} diff --git a/src/logid/actions/Action.h b/src/logid/actions/Action.h index 46024ee..34393d8 100644 --- a/src/logid/actions/Action.h +++ b/src/logid/actions/Action.h @@ -21,6 +21,7 @@ #include #include #include +#include "../config/schema.h" namespace logid { class Device; @@ -46,7 +47,10 @@ namespace actions { { public: static std::shared_ptr makeAction(Device* device, - libconfig::Setting& setting); + config::BasicAction& action); + + static std::shared_ptr makeAction(Device* device, + config::Action& action); virtual void press() = 0; virtual void release() = 0; @@ -65,14 +69,6 @@ namespace actions { virtual ~Action() = default; - class Config - { - protected: - explicit Config(Device* device) : _device (device) - { - } - Device* _device; - }; protected: explicit Action(Device* device) : _device (device), _pressed (false) { diff --git a/src/logid/actions/ChangeDPI.cpp b/src/logid/actions/ChangeDPI.cpp index 3929fbc..7eee2c9 100644 --- a/src/logid/actions/ChangeDPI.cpp +++ b/src/logid/actions/ChangeDPI.cpp @@ -24,8 +24,8 @@ using namespace logid::actions; -ChangeDPI::ChangeDPI(Device *device, libconfig::Setting &setting) : - Action(device), _config(device, setting) +ChangeDPI::ChangeDPI(Device *device, config::ChangeDPI& config) : + Action(device), _config (config) { _dpi = _device->getFeature("dpi"); if(!_dpi) @@ -42,15 +42,16 @@ void ChangeDPI::press() task::spawn(_device->workQueue(), [this]{ try { - uint16_t last_dpi = _dpi->getDPI(_config.sensor()); - _dpi->setDPI(last_dpi + _config.interval(), _config.sensor()); + uint16_t last_dpi = _dpi->getDPI(_config.sensor.value_or(0)); + _dpi->setDPI(last_dpi + _config.inc, + _config.sensor.value_or(0)); } catch (backend::hidpp20::Error& e) { if(e.code() == backend::hidpp20::Error::InvalidArgument) logPrintf(WARN, "%s:%d: Could not get/set DPI for sensor " "%d", _device->hidpp20().devicePath().c_str(), _device->hidpp20().deviceIndex(), - _config.sensor()); + _config.sensor.value_or(0)); else throw e; } @@ -67,44 +68,3 @@ uint8_t ChangeDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } - -ChangeDPI::Config::Config(Device *device, libconfig::Setting &config) : - Action::Config(device), _interval (0), _sensor (0) -{ - if(!config.isGroup()) { - logPrintf(WARN, "Line %d: action must be an object, skipping.", - config.getSourceLine()); - return; - } - - try { - auto& inc = config.lookup("inc"); - if(inc.getType() != libconfig::Setting::TypeInt) - logPrintf(WARN, "Line %d: inc must be an integer", - inc.getSourceLine()); - _interval = (int)inc; - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: inc is a required field, skipping.", - config.getSourceLine()); - } - - try { - auto& sensor = config.lookup("sensor"); - if(sensor.getType() != libconfig::Setting::TypeInt) - logPrintf(WARN, "Line %d: sensor must be an integer", - sensor.getSourceLine()); - _sensor = (int)sensor; - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } -} - -uint16_t ChangeDPI::Config::interval() const -{ - return _interval; -} - -uint8_t ChangeDPI::Config::sensor() const -{ - return _sensor; -} \ No newline at end of file diff --git a/src/logid/actions/ChangeDPI.h b/src/logid/actions/ChangeDPI.h index 4d9e04f..f5d33e8 100644 --- a/src/logid/actions/ChangeDPI.h +++ b/src/logid/actions/ChangeDPI.h @@ -27,26 +27,15 @@ namespace logid { class ChangeDPI : public Action { public: - explicit ChangeDPI(Device* device, libconfig::Setting& setting); + explicit ChangeDPI(Device* device, config::ChangeDPI& setting); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - uint16_t interval() const; - uint8_t sensor() const; - private: - uint16_t _interval; - uint8_t _sensor; - }; - protected: - Config _config; + config::ChangeDPI& _config; std::shared_ptr _dpi; }; }} diff --git a/src/logid/actions/ChangeHostAction.cpp b/src/logid/actions/ChangeHostAction.cpp index 84c3375..0b87507 100644 --- a/src/logid/actions/ChangeHostAction.cpp +++ b/src/logid/actions/ChangeHostAction.cpp @@ -24,9 +24,14 @@ using namespace logid::actions; using namespace logid::backend; -ChangeHostAction::ChangeHostAction(Device *device, libconfig::Setting& -config) : Action(device), _config (device, config) +ChangeHostAction::ChangeHostAction(Device *device, config::ChangeHost& config) + : Action(device), _config (config) { + if(std::holds_alternative(_config.host)) { + auto& host = std::get(_config.host); + std::transform(host.begin(), host.end(), + host.begin(), ::tolower); + } try { _change_host = std::make_shared(&device->hidpp20()); } catch (hidpp20::UnsupportedFeature& e) { @@ -47,9 +52,21 @@ void ChangeHostAction::release() task::spawn(_device->workQueue(), [this] { auto host_info = _change_host->getHostInfo(); - auto next_host = _config.nextHost(host_info); + int next_host; + if(std::holds_alternative(_config.host)) { + const auto& host = std::get(_config.host); + if(host == "next") + next_host = host_info.currentHost + 1; + else if(host == "prev" || host == "previous") + next_host = host_info.currentHost - 1; + else + next_host = host_info.currentHost; + } else { + next_host = std::get(_config.host)-1; + } + next_host %= host_info.hostCount; if(next_host != host_info.currentHost) - _change_host->setHost(next_host); + _change_host->setHost(next_host-1); }); } } @@ -58,63 +75,3 @@ uint8_t ChangeHostAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -ChangeHostAction::Config::Config(Device *device, libconfig::Setting& config) - : Action::Config(device) -{ - try { - auto& host = config.lookup("host"); - if(host.getType() == libconfig::Setting::TypeInt) { - _offset = false; - _host = host; - _host--; // hosts are one-indexed in config - - if(_host < 0) { - logPrintf(WARN, "Line %d: host must be positive.", - host.getSourceLine()); - _offset = true; - _host = 0; - } - - } else if(host.getType() == libconfig::Setting::TypeString) { - _offset = true; - std::string hostmode = host; - std::transform(hostmode.begin(), hostmode.end(), - hostmode.begin(), ::tolower); - - if(hostmode == "next") - _host = 1; - else if(hostmode == "prev" || hostmode == "previous") - _host = -1; - else { - logPrintf(WARN, "Line %d: host must equal an integer, 'next'," - "or 'prev'.", host.getSourceLine()); - _host = 0; - } - } else { - logPrintf(WARN, "Line %d: host must equal an integer, 'next'," - "or 'prev'.", host.getSourceLine()); - _offset = true; - _host = 0; - } - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: host is a required field, skipping.", - config.getSourceLine()); - _offset = true; - _host = 0; - } -} - -uint8_t ChangeHostAction::Config::nextHost(hidpp20::ChangeHost::HostInfo info) -{ - if(_offset) { - return (info.currentHost + _host) % info.hostCount; - } else { - if(_host >= info.hostCount || _host < 0) { - logPrintf(WARN, "No such host %d, defaulting to current.", - _host+1); - return info.currentHost; - } else - return _host; - } -} \ No newline at end of file diff --git a/src/logid/actions/ChangeHostAction.h b/src/logid/actions/ChangeHostAction.h index 4466a62..6c293d9 100644 --- a/src/logid/actions/ChangeHostAction.h +++ b/src/logid/actions/ChangeHostAction.h @@ -28,26 +28,16 @@ namespace actions class ChangeHostAction : public Action { public: - ChangeHostAction(Device* device, libconfig::Setting& config); + ChangeHostAction(Device* device, config::ChangeHost& config); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - uint8_t nextHost(backend::hidpp20::ChangeHost::HostInfo info); - private: - bool _offset; - int _host; - }; - protected: std::shared_ptr _change_host; - Config _config; + config::ChangeHost& _config; }; }} diff --git a/src/logid/actions/CycleDPI.cpp b/src/logid/actions/CycleDPI.cpp index a5b33c7..499e29d 100644 --- a/src/logid/actions/CycleDPI.cpp +++ b/src/logid/actions/CycleDPI.cpp @@ -25,8 +25,8 @@ using namespace logid::actions; using namespace libconfig; -CycleDPI::CycleDPI(Device* device, libconfig::Setting& setting) : - Action (device), _config (device, setting) +CycleDPI::CycleDPI(Device* device, config::CycleDPI& config) : + Action (device), _config (config), _current_dpi (_config.dpis.begin()) { _dpi = _device->getFeature("dpi"); if(!_dpi) @@ -39,18 +39,21 @@ CycleDPI::CycleDPI(Device* device, libconfig::Setting& setting) : void CycleDPI::press() { _pressed = true; - if(_dpi && !_config.empty()) { + if(_dpi && !_config.dpis.empty()) { task::spawn(_device->workQueue(), [this](){ - uint16_t dpi = _config.nextDPI(); + std::lock_guard lock(_dpi_lock); + ++_current_dpi; + if(_current_dpi == _config.dpis.end()) + _current_dpi = _config.dpis.begin(); try { - _dpi->setDPI(dpi, _config.sensor()); + _dpi->setDPI(*_current_dpi, _config.sensor.value_or(0)); } catch (backend::hidpp20::Error& e) { if(e.code() == backend::hidpp20::Error::InvalidArgument) logPrintf(WARN, "%s:%d: Could not set DPI to %d for " "sensor %d", _device->hidpp20().devicePath().c_str(), - _device->hidpp20().deviceIndex(), dpi, - _config.sensor()); + _device->hidpp20().deviceIndex(), *_current_dpi, + _config.sensor.value_or(0)); else throw e; } @@ -67,68 +70,3 @@ uint8_t CycleDPI::reprogFlags() const { return backend::hidpp20::ReprogControls::TemporaryDiverted; } - -CycleDPI::Config::Config(Device *device, libconfig::Setting &config) : - Action::Config(device), _current_index (0), _sensor (0) -{ - if(!config.isGroup()) { - logPrintf(WARN, "Line %d: action must be an object, skipping.", - config.getSourceLine()); - return; - } - - try { - auto& sensor = config.lookup("sensor"); - if(sensor.getType() != Setting::TypeInt) - logPrintf(WARN, "Line %d: sensor must be an integer", - sensor.getSourceLine()); - _sensor = (int)sensor; - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } - - try { - auto& dpis = config.lookup("dpis"); - if(!dpis.isList() && !dpis.isArray()) { - logPrintf(WARN, "Line %d: dpis must be a list or array, skipping.", - dpis.getSourceLine()); - return; - } - - int dpi_count = dpis.getLength(); - for(int i = 0; i < dpi_count; i++) { - if(dpis[i].getType() != Setting::TypeInt) { - logPrintf(WARN, "Line %d: dpis must be integers, skipping.", - dpis[i].getSourceLine()); - if(dpis.isList()) - continue; - else - break; - } - - _dpis.push_back((int)(dpis[i])); - } - - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: dpis is a required field, skipping.", - config.getSourceLine()); - } -} - -uint16_t CycleDPI::Config::nextDPI() -{ - uint16_t dpi = _dpis[_current_index++]; - if(_current_index >= _dpis.size()) - _current_index = 0; - return dpi; -} - -bool CycleDPI::Config::empty() const -{ - return _dpis.empty(); -} - -uint8_t CycleDPI::Config::sensor() const -{ - return _sensor; -} \ No newline at end of file diff --git a/src/logid/actions/CycleDPI.h b/src/logid/actions/CycleDPI.h index b6a5017..6f9d482 100644 --- a/src/logid/actions/CycleDPI.h +++ b/src/logid/actions/CycleDPI.h @@ -27,29 +27,18 @@ namespace actions { class CycleDPI : public Action { public: - explicit CycleDPI(Device* device, libconfig::Setting& setting); + explicit CycleDPI(Device* device, config::CycleDPI& setting); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - uint16_t nextDPI(); - bool empty() const; - uint8_t sensor() const; - private: - std::size_t _current_index; - std::vector _dpis; - uint8_t _sensor; - }; - protected: - Config _config; + std::mutex _dpi_lock; + config::CycleDPI& _config; std::shared_ptr _dpi; + std::list::const_iterator _current_dpi; }; }} diff --git a/src/logid/actions/GestureAction.cpp b/src/logid/actions/GestureAction.cpp index f364a32..e85fc46 100644 --- a/src/logid/actions/GestureAction.cpp +++ b/src/logid/actions/GestureAction.cpp @@ -54,16 +54,28 @@ GestureAction::Direction GestureAction::toDirection(int16_t x, int16_t y) return x <= -y ? Up : Right; } -GestureAction::GestureAction(Device* dev, libconfig::Setting& config) : - Action (dev), _config (dev, config) +GestureAction::GestureAction(Device* dev, config::GestureAction& config) : + Action (dev), _config (config) { + if(_config.gestures.has_value()) { + auto& gestures = _config.gestures.value(); + for(auto& x : gestures) { + try { + auto direction = toDirection(x.first); + _gestures.emplace(direction, + Gesture::makeGesture(dev, x.second)); + } catch(std::invalid_argument& e) { + logPrintf(WARN, "%s is not a direction", x.first.c_str()); + } + } + } } void GestureAction::press() { _pressed = true; _x = 0, _y = 0; - for(auto& gesture : _config.gestures()) + for(auto& gesture : _gestures) gesture.second->press(); } @@ -73,13 +85,13 @@ void GestureAction::release() bool threshold_met = false; auto d = toDirection(_x, _y); - auto primary_gesture = _config.gestures().find(d); - if(primary_gesture != _config.gestures().end()) { + auto primary_gesture = _gestures.find(d); + if(primary_gesture != _gestures.end()) { threshold_met = primary_gesture->second->metThreshold(); primary_gesture->second->release(true); } - for(auto& gesture : _config.gestures()) { + for(auto& gesture : _gestures) { if(gesture.first == d) continue; if(!threshold_met) { @@ -96,10 +108,13 @@ void GestureAction::release() } if(!threshold_met) { - if(_config.noneAction()) { - _config.noneAction()->press(); - _config.noneAction()->release(); - } + try { + auto none = _gestures.at(None); + if(none) { + none->press(); + none->release(); + } + } catch(std::out_of_range& e) { } } } @@ -109,60 +124,60 @@ void GestureAction::move(int16_t x, int16_t y) if(abs(x) > 0) { if(_x < 0 && new_x >= 0) { // Left -> Origin/Right - auto left = _config.gestures().find(Left); - if(left != _config.gestures().end()) + auto left = _gestures.find(Left); + if(left != _gestures.end() && left->second) left->second->move(_x); if(new_x) { // Ignore to origin - auto right = _config.gestures().find(Right); - if(right != _config.gestures().end()) + auto right = _gestures.find(Right); + if(right != _gestures.end() && right->second) right->second->move(new_x); } } else if(_x > 0 && new_x <= 0) { // Right -> Origin/Left - auto right = _config.gestures().find(Right); - if(right != _config.gestures().end()) + auto right = _gestures.find(Right); + if(right != _gestures.end() && right->second) right->second->move(-_x); if(new_x) { // Ignore to origin - auto left = _config.gestures().find(Left); - if(left != _config.gestures().end()) + auto left = _gestures.find(Left); + if(left != _gestures.end() && left->second) left->second->move(-new_x); } } else if(new_x < 0) { // Origin/Left to Left - auto left = _config.gestures().find(Left); - if(left != _config.gestures().end()) + auto left = _gestures.find(Left); + if(left != _gestures.end() && left->second) left->second->move(-x); } else if(new_x > 0) { // Origin/Right to Right - auto right = _config.gestures().find(Right); - if(right != _config.gestures().end()) + auto right = _gestures.find(Right); + if(right != _gestures.end() && right->second) right->second->move(x); } } if(abs(y) > 0) { if(_y > 0 && new_y <= 0) { // Up -> Origin/Down - auto up = _config.gestures().find(Up); - if(up != _config.gestures().end()) + auto up = _gestures.find(Up); + if(up != _gestures.end() && up->second) up->second->move(_y); if(new_y) { // Ignore to origin - auto down = _config.gestures().find(Down); - if(down != _config.gestures().end()) + auto down = _gestures.find(Down); + if(down != _gestures.end() && down->second) down->second->move(new_y); } } else if(_y < 0 && new_y >= 0) { // Down -> Origin/Up - auto down = _config.gestures().find(Down); - if(down != _config.gestures().end()) + auto down = _gestures.find(Down); + if(down != _gestures.end() && down->second) down->second->move(-_y); if(new_y) { // Ignore to origin - auto up = _config.gestures().find(Up); - if(up != _config.gestures().end()) + auto up = _gestures.find(Up); + if(up != _gestures.end() && up->second) up->second->move(-new_y); } } else if(new_y < 0) { // Origin/Up to Up - auto up = _config.gestures().find(Up); - if(up != _config.gestures().end()) + auto up = _gestures.find(Up); + if(up != _gestures.end() && up->second) up->second->move(-y); } else if(new_y > 0) {// Origin/Down to Down - auto down = _config.gestures().find(Down); - if(down != _config.gestures().end()) + auto down = _gestures.find(Down); + if(down != _gestures.end() && down->second) down->second->move(y); } } @@ -175,117 +190,3 @@ uint8_t GestureAction::reprogFlags() const return (hidpp20::ReprogControls::TemporaryDiverted | hidpp20::ReprogControls::RawXYDiverted); } - -GestureAction::Config::Config(Device* device, libconfig::Setting &root) : - Action::Config(device) -{ - try { - auto& gestures = root.lookup("gestures"); - - if(!gestures.isList()) { - logPrintf(WARN, "Line %d: gestures must be a list, ignoring.", - gestures.getSourceLine()); - return; - } - - int gesture_count = gestures.getLength(); - - for(int i = 0; i < gesture_count; i++) { - if(!gestures[i].isGroup()) { - logPrintf(WARN, "Line %d: gesture must be a group, skipping.", - gestures[i].getSourceLine()); - continue; - } - - Direction d; - try { - auto& direction = gestures[i].lookup("direction"); - if(direction.getType() != libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: direction must be a string, " - "skipping.", direction.getSourceLine()); - continue; - } - - try { - d = toDirection(direction); - } catch(std::invalid_argument& e) { - logPrintf(WARN, "Line %d: Invalid direction %s", - direction.getSourceLine(), (const char*)direction); - continue; - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: direction is a required field, " - "skipping.", gestures[i].getSourceLine()); - continue; - } - - if(_gestures.find(d) != _gestures.end() || (d == None && _none_action)) { - logPrintf(WARN, "Line %d: Gesture is already defined for " - "this direction, duplicate ignored.", - gestures[i].getSourceLine()); - continue; - } - - if(d == None) { - try { - auto& mode = gestures[i].lookup("mode"); - if(mode.getType() == libconfig::Setting::TypeString) { - std::string mode_str = mode; - std::transform(mode_str.begin(), mode_str.end(), - mode_str.begin(), ::tolower); - if(mode_str == "nopress") // No action - continue; - else if(mode_str != "onrelease") - logPrintf(WARN, "Line %d: Only NoPress and " - "OnRelease are supported for the " - "None direction, defaulting to " - "OnRelease.", mode.getSourceLine()); - } else { - logPrintf(WARN, "Line %d: mode must be a string, " - "defaulting to OnRelease", - mode.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - // Default to OnRelease - } - - try { - _none_action = Action::makeAction(_device, - gestures[i].lookup("action")); - } catch (InvalidAction& e) { - logPrintf(WARN, "Line %d: %s is not a valid action, " - "skipping.", gestures[i].lookup("action") - .getSourceLine(), e.what()); - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: action is a required field, " - "skipping.", gestures[i].getSourceLine(), - e.what()); - } - continue; - } - - try { - _gestures.emplace(d, Gesture::makeGesture(_device, - gestures[i])); - } catch(InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid gesture: %s", - gestures[i].getSourceLine(), e.what()); - } - } - - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: gestures is a required field, ignoring.", - root.getSourceLine()); - } -} - -std::map>& - GestureAction::Config::gestures() -{ - return _gestures; -} - -std::shared_ptr GestureAction::Config::noneAction() -{ - return _none_action; -} \ No newline at end of file diff --git a/src/logid/actions/GestureAction.h b/src/logid/actions/GestureAction.h index 3928f75..1dff30b 100644 --- a/src/logid/actions/GestureAction.h +++ b/src/logid/actions/GestureAction.h @@ -39,7 +39,7 @@ namespace actions { static Direction toDirection(std::string direction); static Direction toDirection(int16_t x, int16_t y); - GestureAction(Device* dev, libconfig::Setting& config); + GestureAction(Device* dev, config::GestureAction& config); virtual void press(); virtual void release(); @@ -47,20 +47,10 @@ namespace actions { virtual uint8_t reprogFlags() const; - class Config : public Action::Config - { - public: - Config(Device* device, libconfig::Setting& root); - std::map>& gestures(); - std::shared_ptr noneAction(); - protected: - std::map> _gestures; - std::shared_ptr _none_action; - }; - protected: int16_t _x, _y; - Config _config; + std::map> _gestures; + config::GestureAction& _config; }; }} diff --git a/src/logid/actions/KeypressAction.cpp b/src/logid/actions/KeypressAction.cpp index caa004c..c55317f 100644 --- a/src/logid/actions/KeypressAction.cpp +++ b/src/logid/actions/KeypressAction.cpp @@ -24,22 +24,57 @@ using namespace logid::actions; using namespace logid::backend; -KeypressAction::KeypressAction(Device *device, libconfig::Setting& config) : - Action(device), _config (device, config) +KeypressAction::KeypressAction(Device *device, config::KeypressAction& config) : + Action(device), _config (config) { + if(std::holds_alternative(_config.keys)) { + const auto& key = std::get(_config.keys); + try { + auto code = _device->virtualInput()->toKeyCode(key); + _device->virtualInput()->registerKey(code); + _keys.emplace_back(code); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid keycode %s, skipping.", key.c_str()); + } + } else if(std::holds_alternative(_config.keys)) { + const auto& key = std::get(_config.keys); + _device->virtualInput()->registerKey(key); + _keys.emplace_back(key); + } else if(std::holds_alternative>>(_config.keys)) { + const auto& keys = std::get>>( + _config.keys); + for(const auto& key : keys) { + if(std::holds_alternative(_config.keys)) { + const auto& key_str = std::get(key); + try { + auto code = _device->virtualInput()->toKeyCode(key_str); + _device->virtualInput()->registerKey(code); + _keys.emplace_back(code); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid keycode %s, skipping.", + key_str.c_str()); + } + } else if(std::holds_alternative(_config.keys)) { + auto& code = std::get(_config.keys); + _device->virtualInput()->registerKey(code); + _keys.emplace_back(code); + } + } + } } void KeypressAction::press() { _pressed = true; - for(auto& key : _config.keys()) + for(auto& key : _keys) _device->virtualInput()->pressKey(key); } void KeypressAction::release() { _pressed = false; - for(auto& key : _config.keys()) + for(auto& key : _keys) _device->virtualInput()->releaseKey(key); } @@ -47,48 +82,3 @@ uint8_t KeypressAction::reprogFlags() const { return hidpp20::ReprogControls::TemporaryDiverted; } - -KeypressAction::Config::Config(Device* device, libconfig::Setting& config) : - Action::Config(device) -{ - if(!config.isGroup()) { - logPrintf(WARN, "Line %d: action must be an object, skipping.", - config.getSourceLine()); - return; - } - - try { - auto &keys = config.lookup("keys"); - if(keys.isArray() || keys.isList()) { - int key_count = keys.getLength(); - for(int i = 0; i < key_count; i++) { - auto& key = keys[i]; - if(key.isNumber()) { - _keys.push_back(key); - _device->virtualInput()->registerKey(key); - } else if(key.getType() == libconfig::Setting::TypeString) { - try { - _keys.push_back( - _device->virtualInput()->toKeyCode(key)); - _device->virtualInput()->registerKey( - _device->virtualInput()->toKeyCode(key)); - } catch(InputDevice::InvalidEventCode& e) { - logPrintf(WARN, "Line %d: Invalid keycode %s, skipping." - , key.getSourceLine(), key.c_str()); - } - } else { - logPrintf(WARN, "Line %d: keycode must be string or int", - key.getSourceLine(), key.c_str()); - } - } - } - } catch (libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: keys is a required field, skipping.", - config.getSourceLine()); - } -} - -std::vector& KeypressAction::Config::keys() -{ - return _keys; -} \ No newline at end of file diff --git a/src/logid/actions/KeypressAction.h b/src/logid/actions/KeypressAction.h index 4385faf..5ac09d6 100644 --- a/src/logid/actions/KeypressAction.h +++ b/src/logid/actions/KeypressAction.h @@ -27,23 +27,15 @@ namespace actions { class KeypressAction : public Action { public: - KeypressAction(Device* dev, libconfig::Setting& config); + KeypressAction(Device* dev, config::KeypressAction& config); virtual void press(); virtual void release(); virtual uint8_t reprogFlags() const; - - class Config : public Action::Config - { - public: - explicit Config(Device* device, libconfig::Setting& root); - std::vector& keys(); - protected: - std::vector _keys; - }; protected: - Config _config; + config::KeypressAction& _config; + std::list _keys; }; }} diff --git a/src/logid/actions/NullAction.h b/src/logid/actions/NullAction.h index 2d2d0ef..24f169b 100644 --- a/src/logid/actions/NullAction.h +++ b/src/logid/actions/NullAction.h @@ -27,6 +27,8 @@ namespace actions { public: explicit NullAction(Device* device); + NullAction(Device* device, [[maybe_unused]] config::NoAction& config) : + NullAction(device) { } virtual void press(); virtual void release(); diff --git a/src/logid/actions/ToggleHiresScroll.h b/src/logid/actions/ToggleHiresScroll.h index bd60f71..52c41c6 100644 --- a/src/logid/actions/ToggleHiresScroll.h +++ b/src/logid/actions/ToggleHiresScroll.h @@ -28,6 +28,9 @@ namespace actions { public: explicit ToggleHiresScroll(Device* dev); + ToggleHiresScroll(Device* device, + [[maybe_unused]] config::ToggleHiresScroll& action) : + ToggleHiresScroll(device) { } virtual void press(); virtual void release(); diff --git a/src/logid/actions/ToggleSmartShift.h b/src/logid/actions/ToggleSmartShift.h index 7884f48..90c0025 100644 --- a/src/logid/actions/ToggleSmartShift.h +++ b/src/logid/actions/ToggleSmartShift.h @@ -28,6 +28,9 @@ namespace actions { { public: explicit ToggleSmartShift(Device* dev); + ToggleSmartShift(Device* device, + [[maybe_unused]] config::ToggleSmartShift& action) : + ToggleSmartShift(device) { } virtual void press(); virtual void release(); diff --git a/src/logid/actions/gesture/AxisGesture.cpp b/src/logid/actions/gesture/AxisGesture.cpp index 2da114d..19d8b00 100644 --- a/src/logid/actions/gesture/AxisGesture.cpp +++ b/src/logid/actions/gesture/AxisGesture.cpp @@ -23,14 +23,28 @@ using namespace logid::actions; -AxisGesture::AxisGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +AxisGesture::AxisGesture(Device *device, config::AxisGesture& config) : + Gesture (device), _multiplier (1), _config (config) { + if(std::holds_alternative(_config.axis)) { + _input_axis = std::get(_config.axis); + } else { + const auto& axis = std::get(_config.axis); + try { + _axis = _device->virtualInput()->toAxisCode(axis); + _device->virtualInput()->registerAxis(_axis); + } catch(InputDevice::InvalidEventCode& e) { + logPrintf(WARN, "Invalid axis %s."); + throw InvalidGesture(); + } + } + _device->virtualInput()->registerAxis(_input_axis); } void AxisGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? + _config.threshold.value_or(defaults::gesture_threshold) : 0; _axis_remainder = 0; _hires_remainder = 0; } @@ -43,19 +57,23 @@ void AxisGesture::release(bool primary) void AxisGesture::move(int16_t axis) { + const auto threshold = _config.threshold.value_or( + defaults::gesture_threshold); int16_t new_axis = _axis+axis; - int low_res_axis = InputDevice::getLowResAxis(_config.axis()); + int low_res_axis = InputDevice::getLowResAxis(axis); int hires_remainder = _hires_remainder; - if(new_axis > _config.threshold()) { + if(new_axis > threshold) { double move = axis; - if(_axis < _config.threshold()) - move = new_axis - _config.threshold(); - bool negative_multiplier = _config.multiplier() < 0; + if(_axis < threshold) + move = new_axis - threshold; + bool negative_multiplier = _config.axis_multiplier.value_or(1) < 0; if(negative_multiplier) - move *= -_config.multiplier(); + move *= -_config.axis_multiplier.value_or(1); else - move *= _config.multiplier(); + move *= _config.axis_multiplier.value_or(1); + // Handle hi-res multiplier + move *= _multiplier; double move_floor = floor(move); _axis_remainder = move - move_floor; @@ -70,7 +88,7 @@ void AxisGesture::move(int16_t axis) if(low_res_axis != -1) { int lowres_movement = 0, hires_movement = move_floor; - _device->virtualInput()->moveAxis(_config.axis(), hires_movement); + _device->virtualInput()->moveAxis(_input_axis, hires_movement); hires_remainder += hires_movement; if(abs(hires_remainder) >= 60) { lowres_movement = hires_remainder/120; @@ -82,7 +100,7 @@ void AxisGesture::move(int16_t axis) _hires_remainder = hires_remainder; } else { - _device->virtualInput()->moveAxis(_config.axis(), move_floor); + _device->virtualInput()->moveAxis(_input_axis, move_floor); } } _axis = new_axis; @@ -90,72 +108,7 @@ void AxisGesture::move(int16_t axis) bool AxisGesture::metThreshold() const { - return _axis >= _config.threshold(); -} - -void AxisGesture::setHiresMultiplier(double multiplier) -{ - _config.setHiresMultiplier(multiplier); -} - -AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) : - Gesture::Config(device, setting, false) -{ - try { - auto& axis = setting.lookup("axis"); - if(axis.isNumber()) { - _axis = axis; - _device->virtualInput()->registerAxis(_axis); - } else if(axis.getType() == libconfig::Setting::TypeString) { - try { - _axis = _device->virtualInput()->toAxisCode(axis); - _device->virtualInput()->registerAxis(_axis); - } catch(InputDevice::InvalidEventCode& e) { - logPrintf(WARN, "Line %d: Invalid axis %s, skipping." - , axis.getSourceLine(), axis.c_str()); - } - } else { - logPrintf(WARN, "Line %d: axis must be string or int, skipping.", - axis.getSourceLine(), axis.c_str()); - throw InvalidGesture(); - } - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: axis is a required field, skippimg.", - setting.getSourceLine()); - throw InvalidGesture(); - } - - try { - auto& multiplier = setting.lookup("axis_multiplier"); - if(multiplier.isNumber()) { - if(multiplier.getType() == libconfig::Setting::TypeFloat) - _multiplier = multiplier; - else - _multiplier = (int)multiplier; - } else { - logPrintf(WARN, "Line %d: axis_multiplier must be a number, " - "setting to default (1).", - multiplier.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } - - int low_res_axis = InputDevice::getLowResAxis(_axis); - if(low_res_axis != -1) { - _multiplier *= 120; - _device->virtualInput()->registerAxis(low_res_axis); - } -} - -unsigned int AxisGesture::Config::axis() const -{ - return _axis; -} - -double AxisGesture::Config::multiplier() const -{ - return _multiplier; + return _axis >= _config.threshold.value_or(defaults::gesture_threshold); } bool AxisGesture::wheelCompatibility() const @@ -163,15 +116,9 @@ bool AxisGesture::wheelCompatibility() const return true; } -void AxisGesture::Config::setHiresMultiplier(double multiplier) +void AxisGesture::setHiresMultiplier(double multiplier) { - if(_hires_multiplier == multiplier || multiplier == 0) - return; - if(InputDevice::getLowResAxis(_axis) != -1) { - _multiplier *= _hires_multiplier; - _multiplier /= multiplier; + _multiplier = multiplier; } - - _hires_multiplier = multiplier; } diff --git a/src/logid/actions/gesture/AxisGesture.h b/src/logid/actions/gesture/AxisGesture.h index 5352f9f..eaf42e6 100644 --- a/src/logid/actions/gesture/AxisGesture.h +++ b/src/logid/actions/gesture/AxisGesture.h @@ -26,7 +26,7 @@ namespace logid { class AxisGesture : public Gesture { public: - AxisGesture(Device* device, libconfig::Setting& root); + AxisGesture(Device* device, config::AxisGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -37,24 +37,13 @@ namespace logid { void setHiresMultiplier(double multiplier); - class Config : public Gesture::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - unsigned int axis() const; - double multiplier() const; - void setHiresMultiplier(double multiplier); - private: - unsigned int _axis; - double _multiplier = 1; - double _hires_multiplier = 1; - }; - protected: int16_t _axis; double _axis_remainder; int _hires_remainder; - Config _config; + uint _input_axis; + double _multiplier; + config::AxisGesture& _config; }; }} diff --git a/src/logid/actions/gesture/Gesture.cpp b/src/logid/actions/gesture/Gesture.cpp index eb3bcfe..55982ef 100644 --- a/src/logid/actions/gesture/Gesture.cpp +++ b/src/logid/actions/gesture/Gesture.cpp @@ -18,104 +18,42 @@ #include #include "Gesture.h" -#include "../../util/log.h" #include "ReleaseGesture.h" #include "ThresholdGesture.h" -#include "../../backend/hidpp20/features/ReprogControls.h" #include "IntervalGesture.h" #include "AxisGesture.h" #include "NullGesture.h" +using namespace logid; using namespace logid::actions; Gesture::Gesture(Device *device) : _device (device) { } -Gesture::Config::Config(Device* device, libconfig::Setting& root, - bool action_required) : _device (device) -{ - if(action_required) { - try { - _action = Action::makeAction(_device, - root.lookup("action")); - } catch (libconfig::SettingNotFoundException &e) { - throw InvalidGesture("action is missing"); - } +template +struct gesture_type { + typedef typename T::gesture type; +}; - if(_action->reprogFlags() & backend::hidpp20::ReprogControls::RawXYDiverted) - throw InvalidGesture("gesture cannot require RawXY"); - } +template +struct gesture_type : gesture_type { }; - _threshold = LOGID_GESTURE_DEFAULT_THRESHOLD; - try { - auto& threshold = root.lookup("threshold"); - if(threshold.getType() == libconfig::Setting::TypeInt) { - _threshold = (int)threshold; - if(_threshold <= 0) { - _threshold = LOGID_GESTURE_DEFAULT_THRESHOLD; - logPrintf(WARN, "Line %d: threshold must be positive, setting " - "to default (%d)", threshold.getSourceLine(), - _threshold); - } - } else - logPrintf(WARN, "Line %d: threshold must be an integer, setting " - "to default (%d).", threshold.getSourceLine()); - } catch(libconfig::SettingNotFoundException& e) { - // Ignore - } +template +struct gesture_type : gesture_type { }; + +template +std::shared_ptr _makeGesture(Device* device, + T gesture) { + return std::make_shared::type>(device, gesture); } std::shared_ptr Gesture::makeGesture(Device *device, - libconfig::Setting &setting) + config::Gesture& gesture) { - if(!setting.isGroup()) { - logPrintf(WARN, "Line %d: Gesture is not a group, ignoring.", - setting.getSourceLine()); - throw InvalidGesture(); - } - - try { - auto& gesture_mode = setting.lookup("mode"); - - if(gesture_mode.getType() != libconfig::Setting::TypeString) { - logPrintf(WARN, "Line %d: Gesture mode must be a string," - "defaulting to OnRelease.", - gesture_mode.getSourceLine()); - return std::make_shared(device, setting); - } - - std::string type = gesture_mode; - std::transform(type.begin(), type.end(), type.begin(), ::tolower); - - if(type == "onrelease") - return std::make_shared(device, setting); - else if(type == "onthreshold") - return std::make_shared(device, setting); - else if(type == "oninterval" || type == "onfewpixels") - return std::make_shared(device, setting); - else if(type == "axis") - return std::make_shared(device, setting); - else if(type == "nopress") - return std::make_shared(device, setting); - else { - logPrintf(WARN, "Line %d: Unknown gesture mode %s, defaulting to " - "OnRelease.", gesture_mode.getSourceLine(), - (const char*)gesture_mode); - return std::make_shared(device, setting); - } - - } catch(libconfig::SettingNotFoundException& e) { - return std::make_shared(device, setting); - } + std::shared_ptr ret; + std::visit([&device, &ret](auto&& x) { + ret = _makeGesture(device, x); + }, gesture); + return ret; } - -int16_t Gesture::Config::threshold() const -{ - return _threshold; -} - -std::shared_ptr Gesture::Config::action() -{ - return _action; -} \ No newline at end of file diff --git a/src/logid/actions/gesture/Gesture.h b/src/logid/actions/gesture/Gesture.h index dcb84ea..58c39d5 100644 --- a/src/logid/actions/gesture/Gesture.h +++ b/src/logid/actions/gesture/Gesture.h @@ -51,21 +51,8 @@ namespace actions virtual ~Gesture() = default; - class Config - { - public: - Config(Device* device, libconfig::Setting& root, - bool action_required=true); - virtual int16_t threshold() const; - virtual std::shared_ptr action(); - protected: - Device* _device; - std::shared_ptr _action; - int16_t _threshold; - }; - static std::shared_ptr makeGesture(Device* device, - libconfig::Setting& setting); + config::Gesture& gesture); protected: explicit Gesture(Device* device); diff --git a/src/logid/actions/gesture/IntervalGesture.cpp b/src/logid/actions/gesture/IntervalGesture.cpp index a3d8438..6f9988a 100644 --- a/src/logid/actions/gesture/IntervalGesture.cpp +++ b/src/logid/actions/gesture/IntervalGesture.cpp @@ -17,17 +17,26 @@ */ #include "IntervalGesture.h" #include "../../util/log.h" +#include "../../Configuration.h" using namespace logid::actions; -IntervalGesture::IntervalGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +IntervalGesture::IntervalGesture(Device *device, config::IntervalGesture& config) : + Gesture (device), _config (config) { + if(config.action) { + try { + _action = Action::makeAction(device, config.action.value()); + } catch(InvalidAction& e) { + logPrintf(WARN, "Mapping gesture to invalid action"); + } + } } void IntervalGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? + _config.threshold.value_or(defaults::gesture_threshold) : 0; _interval_pass_count = 0; } @@ -39,15 +48,19 @@ void IntervalGesture::release(bool primary) void IntervalGesture::move(int16_t axis) { + const auto threshold = + _config.threshold.value_or(defaults::gesture_threshold); _axis += axis; - if(_axis < _config.threshold()) + if(_axis < threshold) return; - int16_t new_interval_count = (_axis - _config.threshold())/ - _config.interval(); + int16_t new_interval_count = (_axis - threshold)/ + _config.interval; if(new_interval_count > _interval_pass_count) { - _config.action()->press(); - _config.action()->release(); + if(_action) { + _action->press(); + _action->release(); + } } _interval_pass_count = new_interval_count; } @@ -59,38 +72,5 @@ bool IntervalGesture::wheelCompatibility() const bool IntervalGesture::metThreshold() const { - return _axis >= _config.threshold(); + return _axis >= _config.threshold.value_or(defaults::gesture_threshold);; } - -IntervalGesture::Config::Config(Device *device, libconfig::Setting &setting) : - Gesture::Config(device, setting) -{ - try { - auto& interval = setting.lookup("interval"); - if(interval.getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: interval must be an integer, skipping.", - interval.getSourceLine()); - throw InvalidGesture(); - } - _interval = (int)interval; - } catch(libconfig::SettingNotFoundException& e) { - try { - // pixels is an alias for interval - auto& interval = setting.lookup("pixels"); - if(interval.getType() != libconfig::Setting::TypeInt) { - logPrintf(WARN, "Line %d: pixels must be an integer, skipping.", - interval.getSourceLine()); - throw InvalidGesture(); - } - _interval = (int)interval; - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: interval is a required field, skipping.", - setting.getSourceLine()); - } - } -} - -int16_t IntervalGesture::Config::interval() const -{ - return _interval; -} \ No newline at end of file diff --git a/src/logid/actions/gesture/IntervalGesture.h b/src/logid/actions/gesture/IntervalGesture.h index 268822d..cb68cd2 100644 --- a/src/logid/actions/gesture/IntervalGesture.h +++ b/src/logid/actions/gesture/IntervalGesture.h @@ -26,7 +26,7 @@ namespace actions class IntervalGesture : public Gesture { public: - IntervalGesture(Device* device, libconfig::Setting& root); + IntervalGesture(Device* device, config::IntervalGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -35,19 +35,11 @@ namespace actions virtual bool wheelCompatibility() const; virtual bool metThreshold() const; - class Config : public Gesture::Config - { - public: - Config(Device* device, libconfig::Setting& setting); - int16_t interval() const; - private: - int16_t _interval; - }; - protected: int16_t _axis; int16_t _interval_pass_count; - Config _config; + std::shared_ptr _action; + config::IntervalGesture& _config; }; }} diff --git a/src/logid/actions/gesture/NullGesture.cpp b/src/logid/actions/gesture/NullGesture.cpp index dbb7e57..515746f 100644 --- a/src/logid/actions/gesture/NullGesture.cpp +++ b/src/logid/actions/gesture/NullGesture.cpp @@ -16,17 +16,20 @@ * */ #include "NullGesture.h" +#include "../../Configuration.h" using namespace logid::actions; -NullGesture::NullGesture(Device *device, libconfig::Setting& setting) : - Gesture (device), _config (device, setting, false) +NullGesture::NullGesture(Device *device, + config::NoGesture& config) : + Gesture (device), _config (config) { } void NullGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? _config.threshold.value_or( + defaults::gesture_threshold) : 0; } void NullGesture::release(bool primary) @@ -47,5 +50,5 @@ bool NullGesture::wheelCompatibility() const bool NullGesture::metThreshold() const { - return _axis > _config.threshold(); + return _axis > _config.threshold.value_or(defaults::gesture_threshold); } \ No newline at end of file diff --git a/src/logid/actions/gesture/NullGesture.h b/src/logid/actions/gesture/NullGesture.h index 6b0f980..89b0158 100644 --- a/src/logid/actions/gesture/NullGesture.h +++ b/src/logid/actions/gesture/NullGesture.h @@ -26,7 +26,8 @@ namespace actions class NullGesture : public Gesture { public: - NullGesture(Device* device, libconfig::Setting& setting); + NullGesture(Device* device, + config::NoGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -36,7 +37,7 @@ namespace actions virtual bool metThreshold() const; protected: int16_t _axis; - Gesture::Config _config; + config::NoGesture& _config; }; }} diff --git a/src/logid/actions/gesture/ReleaseGesture.cpp b/src/logid/actions/gesture/ReleaseGesture.cpp index 613412b..e09989b 100644 --- a/src/logid/actions/gesture/ReleaseGesture.cpp +++ b/src/logid/actions/gesture/ReleaseGesture.cpp @@ -16,24 +16,30 @@ * */ #include "ReleaseGesture.h" +#include "../../Configuration.h" using namespace logid::actions; -ReleaseGesture::ReleaseGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +ReleaseGesture::ReleaseGesture(Device *device, config::ReleaseGesture& config) : + Gesture (device), _config (config) { + if(_config.action.has_value()) + _action = Action::makeAction(device, _config.action.value()); } void ReleaseGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? _config.threshold.value_or( + defaults::gesture_threshold) : 0; } void ReleaseGesture::release(bool primary) { if(metThreshold() && primary) { - _config.action()->press(); - _config.action()->release(); + if(_action) { + _action->press(); + _action->release(); + } } } @@ -49,5 +55,5 @@ bool ReleaseGesture::wheelCompatibility() const bool ReleaseGesture::metThreshold() const { - return _axis >= _config.threshold(); + return _axis >= _config.threshold.value_or(defaults::gesture_threshold); } \ No newline at end of file diff --git a/src/logid/actions/gesture/ReleaseGesture.h b/src/logid/actions/gesture/ReleaseGesture.h index 59cc528..24166a7 100644 --- a/src/logid/actions/gesture/ReleaseGesture.h +++ b/src/logid/actions/gesture/ReleaseGesture.h @@ -26,7 +26,7 @@ namespace actions class ReleaseGesture : public Gesture { public: - ReleaseGesture(Device* device, libconfig::Setting& root); + ReleaseGesture(Device* device, config::ReleaseGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -37,7 +37,8 @@ namespace actions protected: int16_t _axis; - Gesture::Config _config; + std::shared_ptr _action; + config::ReleaseGesture& _config; }; }} diff --git a/src/logid/actions/gesture/ThresholdGesture.cpp b/src/logid/actions/gesture/ThresholdGesture.cpp index 5e1ebd9..ccae5a9 100644 --- a/src/logid/actions/gesture/ThresholdGesture.cpp +++ b/src/logid/actions/gesture/ThresholdGesture.cpp @@ -16,17 +16,27 @@ * */ #include "ThresholdGesture.h" +#include "../../Configuration.h" using namespace logid::actions; -ThresholdGesture::ThresholdGesture(Device *device, libconfig::Setting &root) : - Gesture (device), _config (device, root) +ThresholdGesture::ThresholdGesture(Device *device, + config::ThresholdGesture& config) : + Gesture (device), _config (config) { + if(config.action) { + try { + _action = Action::makeAction(device, config.action.value()); + } catch(InvalidAction& e) { + logPrintf(WARN, "Mapping gesture to invalid action"); + } + } } void ThresholdGesture::press(bool init_threshold) { - _axis = init_threshold ? _config.threshold() : 0; + _axis = init_threshold ? + _config.threshold.value_or(defaults::gesture_threshold) : 0; this->_executed = false; } @@ -42,15 +52,17 @@ void ThresholdGesture::move(int16_t axis) _axis += axis; if(!this->_executed && metThreshold()) { - _config.action()->press(); - _config.action()->release(); + if(_action) { + _action->press(); + _action->release(); + } this->_executed = true; } } bool ThresholdGesture::metThreshold() const { - return _axis >= _config.threshold(); + return _axis >= _config.threshold.value_or(defaults::gesture_threshold); } bool ThresholdGesture::wheelCompatibility() const diff --git a/src/logid/actions/gesture/ThresholdGesture.h b/src/logid/actions/gesture/ThresholdGesture.h index 0a38b96..501117d 100644 --- a/src/logid/actions/gesture/ThresholdGesture.h +++ b/src/logid/actions/gesture/ThresholdGesture.h @@ -26,7 +26,7 @@ namespace actions class ThresholdGesture : public Gesture { public: - ThresholdGesture(Device* device, libconfig::Setting& root); + ThresholdGesture(Device* device, config::ThresholdGesture& config); virtual void press(bool init_threshold=false); virtual void release(bool primary=false); @@ -38,7 +38,8 @@ namespace actions protected: int16_t _axis; - Gesture::Config _config; + std::shared_ptr _action; + config::ThresholdGesture& _config; private: bool _executed = false; diff --git a/src/logid/backend/dj/Receiver.cpp b/src/logid/backend/dj/Receiver.cpp index 2f3e4d7..f0909e5 100644 --- a/src/logid/backend/dj/Receiver.cpp +++ b/src/logid/backend/dj/Receiver.cpp @@ -45,7 +45,7 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept } Receiver::Receiver(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : _raw_device (std::make_shared( std::move(path), io_timeout, wq)), diff --git a/src/logid/backend/dj/Receiver.h b/src/logid/backend/dj/Receiver.h index f0e4a21..270a4eb 100644 --- a/src/logid/backend/dj/Receiver.h +++ b/src/logid/backend/dj/Receiver.h @@ -53,7 +53,7 @@ namespace dj { public: Receiver(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); enum DjEvents : uint8_t diff --git a/src/logid/backend/dj/ReceiverMonitor.cpp b/src/logid/backend/dj/ReceiverMonitor.cpp index f847a75..ae51314 100644 --- a/src/logid/backend/dj/ReceiverMonitor.cpp +++ b/src/logid/backend/dj/ReceiverMonitor.cpp @@ -27,7 +27,7 @@ using namespace logid::backend::dj; ReceiverMonitor::ReceiverMonitor( std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : _workqueue (wq), _receiver (std::make_shared(std::move(path), io_timeout, wq)) diff --git a/src/logid/backend/dj/ReceiverMonitor.h b/src/logid/backend/dj/ReceiverMonitor.h index 6c88627..1349bf8 100644 --- a/src/logid/backend/dj/ReceiverMonitor.h +++ b/src/logid/backend/dj/ReceiverMonitor.h @@ -33,7 +33,7 @@ namespace dj { public: ReceiverMonitor(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); virtual ~ReceiverMonitor(); diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 0b853c1..a4d727c 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -50,7 +50,7 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept } Device::Device(const std::string& path, DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq): _raw_device (std::make_shared(path, io_timeout, wq)), _receiver (nullptr), _path (path), _index (index) diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 666ad45..1dea588 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -62,7 +62,7 @@ namespace hidpp }; Device(const std::string& path, DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); Device(std::shared_ptr raw_device, DeviceIndex index); diff --git a/src/logid/backend/hidpp10/Device.cpp b/src/logid/backend/hidpp10/Device.cpp index ab5f990..8f6e54e 100644 --- a/src/logid/backend/hidpp10/Device.cpp +++ b/src/logid/backend/hidpp10/Device.cpp @@ -25,7 +25,7 @@ using namespace logid::backend; using namespace logid::backend::hidpp10; Device::Device(const std::string &path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : hidpp::Device(path, index, io_timeout, wq) { diff --git a/src/logid/backend/hidpp10/Device.h b/src/logid/backend/hidpp10/Device.h index b6d92b5..b61e054 100644 --- a/src/logid/backend/hidpp10/Device.h +++ b/src/logid/backend/hidpp10/Device.h @@ -29,7 +29,7 @@ namespace hidpp10 { public: Device(const std::string& path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); Device(std::shared_ptr raw_dev, hidpp::DeviceIndex index); diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index 278f119..ed93b70 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -24,8 +24,7 @@ using namespace logid::backend::hidpp20; Device::Device(std::string path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, - const std::shared_ptr& wq) : + double io_timeout, const std::shared_ptr& wq) : hidpp::Device(path, index, io_timeout, wq) { assert(std::get<0>(version()) >= 2); diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h index f593758..482abe8 100644 --- a/src/logid/backend/hidpp20/Device.h +++ b/src/logid/backend/hidpp20/Device.h @@ -29,8 +29,7 @@ namespace hidpp20 { { public: Device(std::string path, hidpp::DeviceIndex index, - const std::chrono::milliseconds& io_timeout, - const std::shared_ptr& wq); + double io_timeout, const std::shared_ptr& wq); Device(std::shared_ptr raw_device, hidpp::DeviceIndex index); Device(std::shared_ptr receiver, hidpp::DeviceIndex index); diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 95e6995..dd2103e 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -65,11 +65,12 @@ bool RawDevice::supportedReport(uint8_t id, uint8_t length) } RawDevice::RawDevice(std::string path, - const milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq) : _path (std::move(path)), _continue_listen (false), _continue_respond (false), - _io_timeout (io_timeout), + _io_timeout (duration_cast( + duration(io_timeout))), _workqueue (wq) { int ret; diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index 7935a0c..2619e90 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -42,7 +42,7 @@ namespace raw static bool supportedReport(uint8_t id, uint8_t length); explicit RawDevice(std::string path, - const std::chrono::milliseconds& io_timeout, + double io_timeout, const std::shared_ptr& wq); ~RawDevice(); std::string hidrawPath() const; diff --git a/src/logid/config/group.h b/src/logid/config/group.h index 9179b16..9c419ed 100644 --- a/src/logid/config/group.h +++ b/src/logid/config/group.h @@ -135,11 +135,11 @@ namespace logid::config { virtual ~group() = default; - virtual void save(libconfig::Setting& setting) const { + virtual void _save(libconfig::Setting& setting) const { _setter(setting, this, _names); } - virtual void load(const libconfig::Setting& setting) { + virtual void _load(const libconfig::Setting& setting) { _getter(setting, this, _names); } }; @@ -188,12 +188,12 @@ namespace logid::config { return *this; } - void save(libconfig::Setting& setting) const override { + void _save(libconfig::Setting& setting) const override { set(setting, _signature, _sig_field); _setter(setting, this, _names); } - void load(const libconfig::Setting& setting) override { + void _load(const libconfig::Setting& setting) override { if(normalize_signature::make(get(setting, _sig_field)) != _signature) throw libconfig::SettingTypeException(setting); diff --git a/src/logid/config/schema.h b/src/logid/config/schema.h index cbf45a7..ecffbf3 100644 --- a/src/logid/config/schema.h +++ b/src/logid/config/schema.h @@ -20,30 +20,54 @@ #include "types.h" +namespace logid::actions { + class ChangeDPI; + class ChangeHostAction; + class CycleDPI; + class GestureAction; + class KeypressAction; + class NullAction; + class ToggleHiresScroll; + class ToggleSmartShift; + + class AxisGesture; + class IntervalGesture; + class NullGesture; + class ReleaseGesture; + class ThresholdGesture; +} + namespace logid::config { + struct NoAction : public signed_group { + typedef actions::NullAction action; NoAction() : signed_group("type", "None") { } }; struct KeypressAction : public signed_group { - std::variant> keys; + typedef actions::KeypressAction action; + std::variant>> keys; KeypressAction() : signed_group( "type", "Keypress", {"keys"}, &KeypressAction::keys) { } }; struct ToggleSmartShift : public signed_group { + typedef actions::ToggleSmartShift action; ToggleSmartShift() : signed_group("type", "ToggleSmartShift") { } }; struct ToggleHiresScroll : public signed_group { + typedef actions::ToggleHiresScroll action; ToggleHiresScroll() : signed_group("type", "ToggleHiresScroll") { } }; struct CycleDPI : public signed_group { - std::vector dpis; + typedef actions::CycleDPI action; + std::list dpis; std::optional sensor; CycleDPI() : signed_group( "type", "CycleDPI", @@ -53,6 +77,7 @@ namespace logid::config { }; struct ChangeDPI : public signed_group { + typedef actions::ChangeDPI action; int inc; std::optional sensor; ChangeDPI() : signed_group( @@ -63,21 +88,13 @@ namespace logid::config { }; struct ChangeHost : public signed_group { + typedef actions::ChangeHostAction action; std::variant host; ChangeHost() : signed_group( "type", "ChangeHost", {"host"}, &ChangeHost::host) { } }; - struct Gesture; - - struct GestureAction : public signed_group { - std::optional> _gestures; - - GestureAction() : signed_group( - "type", "Gestures") { } - }; - typedef std::variant< NoAction, KeypressAction, @@ -88,6 +105,89 @@ namespace logid::config { ChangeHost > BasicAction; + struct AxisGesture : public signed_group { + typedef actions::AxisGesture gesture; + std::optional threshold; + std::variant axis; + std::optional axis_multiplier; + + AxisGesture() : signed_group("mode", "Axis", + {"threshold", "axis", "axis_multiplier"}, + &AxisGesture::threshold, + &AxisGesture::axis, + &AxisGesture::axis_multiplier) { } + }; + + struct IntervalGesture : public signed_group { + typedef actions::IntervalGesture gesture; + std::optional threshold; + std::optional action; + int interval; + protected: + IntervalGesture(const std::string& name) : signed_group( + "mode", name, + {"threshold", "action", "interval"}, + &IntervalGesture::threshold, + &IntervalGesture::action, + &IntervalGesture::interval) { } + public: + IntervalGesture() : IntervalGesture("OnInterval") { } + }; + + struct FewPixelsGesture : public IntervalGesture { + FewPixelsGesture() : IntervalGesture("OnFewPixels") { } + }; + + struct ReleaseGesture : public signed_group { + typedef actions::ReleaseGesture gesture; + std::optional threshold; + std::optional action; + + ReleaseGesture() : signed_group("mode", "OnRelease", + {"threshold", "action"}, + &ReleaseGesture::threshold, + &ReleaseGesture::action) { } + }; + + struct ThresholdGesture : public signed_group { + typedef actions::ThresholdGesture gesture; + std::optional threshold; + std::optional action; + + ThresholdGesture() : signed_group("mode", "OnThreshold", + {"threshold", "action"}, + &ThresholdGesture::threshold, + &ThresholdGesture::action) { } + }; + + struct NoGesture : public signed_group { + typedef actions::NullGesture gesture; + std::optional threshold; + NoGesture() : signed_group("mode", "NoPress", + {"threshold"}, + &NoGesture::threshold) { } + }; + + typedef std::variant< + NoGesture, + AxisGesture, + IntervalGesture, + FewPixelsGesture, + ReleaseGesture, + ThresholdGesture + > Gesture; + + + struct GestureAction : public signed_group { + typedef actions::GestureAction action; + std::optional> gestures; + + GestureAction() : signed_group( + "type", "Gestures", + {"gestures"}, + &GestureAction::gestures) { } + }; + typedef std::variant< NoAction, KeypressAction, @@ -99,60 +199,67 @@ namespace logid::config { GestureAction > Action; - struct Gesture : public group { - std::optional threshold; - std::optional mode; - std::optional axis; - std::optional axis_multiplier; - Action action; - - Gesture() : group( - {"threshold", "mode", "axis", "axis_multiplier"}, - &Gesture::threshold, - &Gesture::mode, - &Gesture::axis, - &Gesture::axis_multiplier - ) { } - }; - struct Button : public group { - std::optional action; + std::optional action; Button() : group({"action"}, &Button::action) { } }; - struct Smartshift : public group { + struct SmartShift : public group { std::optional on; std::optional threshold; - Smartshift() : group({"on", "threshold"}, - &Smartshift::on, &Smartshift::threshold) { } + SmartShift() : group({"on", "threshold"}, + &SmartShift::on, &SmartShift::threshold) { } }; - struct Hiresscroll : public group { + struct HiresScroll : public group { std::optional hires; std::optional invert; std::optional target; - Hiresscroll() : group({"hires", "invert", "target"}, - &Hiresscroll::hires, - &Hiresscroll::invert, - &Hiresscroll::target) { } + std::optional up; + std::optional down; + HiresScroll() : group({"hires", "invert", "target", "up", "down"}, + &HiresScroll::hires, + &HiresScroll::invert, + &HiresScroll::target, + &HiresScroll::up, + &HiresScroll::down) { } }; - using DPI = std::variant>; + typedef std::variant> DPI; + struct ThumbWheel : public group { + std::optional divert; + std::optional invert; + std::optional left; + std::optional right; + std::optional proxy; + std::optional touch; + std::optional tap; + + ThumbWheel() : group({"divert", "invert", "left", "right", + "proxy", "touch", "tap" }, + &ThumbWheel::divert, &ThumbWheel::invert, + &ThumbWheel::left, &ThumbWheel::right, + &ThumbWheel::proxy, &ThumbWheel::touch, + &ThumbWheel::tap) { } + }; + + typedef map RemapButton; struct Profile : public group { std::optional dpi; - std::optional smartshift; - std::optional> hiresscroll; - std::optional> buttons; + std::optional smartshift; + std::optional> hiresscroll; + std::optional thumbwheel; + std::optional buttons; - Profile() : group({"dpi", "smartshift", "hiresscroll", "buttons"}, - &Profile::dpi, - &Profile::smartshift, - &Profile::hiresscroll, - &Profile::buttons) { } + Profile() : group({"dpi", "smartshift", "hiresscroll", + "buttons", "thumbwheel"}, + &Profile::dpi, &Profile::smartshift, + &Profile::hiresscroll, &Profile::buttons, + &Profile::thumbwheel) { } }; struct Device : public group { @@ -166,8 +273,8 @@ namespace logid::config { struct Config : public group { std::optional, "name">> devices; - std::optional> ignore; + std::variant, "name">> devices; + std::optional> ignore; std::optional io_timeout; std::optional workers; Config() : group({"devices", "ignore", "io_timeout", "workers"}, diff --git a/src/logid/config/types.h b/src/logid/config/types.h index a8a8393..ad729ae 100644 --- a/src/logid/config/types.h +++ b/src/logid/config/types.h @@ -22,12 +22,16 @@ #include #include #include +#include +#include #include "group.h" #include "map.h" #include "../util/log.h" /// TODO: A single element failing should not cause the container to be invalid. +// Containers are chosen specifically so that no iterator is invalidated. + namespace logid::config { namespace { template @@ -37,13 +41,13 @@ namespace logid::config { static T get(const libconfig::Setting& parent, const std::string& name) { T t {}; - t.load(parent.lookup(name)); + t._load(parent.lookup(name)); return t; } static T get(const libconfig::Setting& setting) { T t {}; - t.load(setting); + t._load(setting); return t; } @@ -54,13 +58,14 @@ namespace logid::config { parent.add(name, libconfig::Setting::TypeGroup); } else if(parent.lookup(name).getType() != libconfig::Setting::TypeGroup) { - + parent.remove(name); + parent.add(name, libconfig::Setting::TypeGroup); } - t.save(parent.lookup(name)); + t._save(parent.lookup(name)); } static void set(libconfig::Setting& setting, const T& t) { - t.save(setting); + t._save(setting); } static void append(libconfig::Setting& list, const T& t) { @@ -83,8 +88,12 @@ namespace logid::config { static void set(libconfig::Setting& parent, const std::string& name, const T& t) { - if(!parent.exists(name)) + if(!parent.exists(name)) { parent.add(name, TypeEnum); + } else if(parent.lookup(name).getType() != TypeEnum) { + parent.remove(name); + parent.add(name, TypeEnum); + } set(parent.lookup(name), t); } @@ -98,38 +107,68 @@ namespace logid::config { } }; + template + struct reinterpret_io { + static T get(const libconfig::Setting& parent, + const std::string& name) { + return static_cast(primitive_io::get(parent, name)); + } + + static T get(const libconfig::Setting& setting) { + return static_cast(primitive_io::get(setting)); + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const T& t) { + primitive_io::set(parent, name, + static_cast(t)); + } + + static void set(libconfig::Setting& setting, const T& t) { + primitive_io::set(setting, + static_cast(t)); + } + + static void append(libconfig::Setting& list, const T& t) { + primitive_io::append(list, + static_cast(t)); + } + }; + template <> struct config_io : public primitive_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io { }; + struct config_io : public reinterpret_io { }; template <> struct config_io : public primitive_io { }; template <> - struct config_io : public primitive_io { }; + struct config_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io : public reinterpret_io { }; template <> - struct config_io : public primitive_io { }; + struct config_io : public reinterpret_io { }; template <> struct config_io : public primitive_io { }; template <> - struct config_io : public primitive_io : + public reinterpret_io { }; template <> struct config_io : public primitive_io - struct config_io> { - static std::vector get(const libconfig::Setting& setting) { + struct config_io> { + static std::list get(const libconfig::Setting& setting) { const auto size = setting.getLength(); - std::vector t(size); - for(int i = 0; i < size; ++i) - t[i] = config_io::get(setting[i]); + std::list t {}; + for(int i = 0; i < size; ++i) { + try { + t.emplace_back(config_io::get(setting[i])); + } catch(libconfig::SettingException& e) { } + } return t; } - static std::vector get(const libconfig::Setting& parent, + static std::list get(const libconfig::Setting& parent, const std::string& name) { return get(parent.lookup(name)); } static void set(libconfig::Setting& setting, - const std::vector& t) { - const auto orig_size = setting.getLength(); - for(int i = 0; i < orig_size; ++i) - config_io::set(setting[i], t[i]); - for(int i = orig_size; i < t.size(); ++i) - config_io::append(setting, t[i]); + const std::list& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(auto& x : t) { + config_io::append(setting, x); + } } static void set(libconfig::Setting& parent, const std::string& name, - const std::vector& t) { + const std::list& t) { if (!parent.exists(name)) { - parent.add(name, libconfig::Setting::TypeArray); - } else if(!parent.lookup(name).isArray()) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isList()) { parent.remove(name); - parent.add(name, libconfig::Setting::TypeArray); + parent.add(name, libconfig::Setting::TypeList); } set(parent.lookup(name), t); } static void append(libconfig::Setting& list, - const std::vector& t) { - auto& s = list.add(libconfig::Setting::TypeArray); + const std::list& t) { + auto& s = list.add(libconfig::Setting::TypeList); + set(s, t); + } + }; + + template + struct config_io> { + static std::set get(const libconfig::Setting& setting) { + const auto size = setting.getLength(); + std::set t; + for(int i = 0; i < size; ++i) { + try { + t.emplace(config_io::get(setting[i])); + } catch(libconfig::SettingException& e) { } + } + return t; + } + + static std::set get(const libconfig::Setting& parent, + const std::string& name) { + return get(parent.lookup(name)); + } + + static void set(libconfig::Setting& setting, + const std::set& t) { + while(setting.getLength() != 0) + setting.remove((int)0); + for(auto& x : t) { + auto& s = setting.add(libconfig::Setting::TypeGroup); + config_io::set(s, x); + } + } + + static void set(libconfig::Setting& parent, + const std::string& name, + const std::set& t) { + if (!parent.exists(name)) { + parent.add(name, libconfig::Setting::TypeList); + } else if(!parent.lookup(name).isArray()) { + parent.remove(name); + parent.add(name, libconfig::Setting::TypeList); + } + set(parent.lookup(name), t); + } + + static void append(libconfig::Setting& list, + const std::set& t) { + auto& s = list.add(libconfig::Setting::TypeList); set(s, t); } }; @@ -246,8 +335,10 @@ namespace logid::config { map t; for(int i = 0; i < size; ++i) { auto& s = setting[i]; - t.emplace(config_io::get(s.lookup(KeyName.value)), - config_io::get(s)); + try { + t.emplace(config_io::get(s.lookup(KeyName.value)), + config_io::get(s)); + } catch(libconfig::SettingException& e) { } } return t; } @@ -287,49 +378,6 @@ namespace logid::config { } }; - template - struct config_io>> { - static std::vector> get( - const libconfig::Setting& setting) { - const auto size = setting.getLength(); - std::vector> t(size); - for(int i = 0; i < size; ++i) - t[i] = config_io>::get(setting[i]); - return t; - } - - static std::vector> get( - const libconfig::Setting& parent, const std::string& name) { - return get(parent.lookup(name)); - } - - static void set(libconfig::Setting& setting, - const std::vector>& t) { - while(setting.getLength() != 0) - setting.remove((int)0); - for(int i = 0; i < t.size(); ++i) - config_io>::append(setting, t[i]); - } - - static void set(libconfig::Setting& parent, - const std::string& name, - const std::vector>& t) { - if (!parent.exists(name)) { - parent.add(name, libconfig::Setting::TypeList); - } else if(!parent.lookup(name).isList()) { - parent.remove(name); - parent.add(name, libconfig::Setting::TypeList); - } - set(parent.lookup(name), t); - } - - static void append(libconfig::Setting& list, - const std::variant>& t) { - auto& s = list.add(libconfig::Setting::TypeList); - set(s, t); - } - }; - template struct config_io> { static std::optional get(const libconfig::Setting& parent, @@ -356,7 +404,7 @@ namespace logid::config { }; template - struct config_io>> { + struct config_io>> { static_assert(!sizeof(std::optional), "Invalid type"); }; diff --git a/src/logid/features/DPI.cpp b/src/logid/features/DPI.cpp index 82093a1..1fd856c 100644 --- a/src/logid/features/DPI.cpp +++ b/src/logid/features/DPI.cpp @@ -19,12 +19,11 @@ #include #include "DPI.h" #include "../Device.h" -#include "../util/log.h" using namespace logid::features; using namespace logid::backend; -uint16_t getClosestDPI(hidpp20::AdjustableDPI::SensorDPIList& dpi_list, +uint16_t getClosestDPI(const hidpp20::AdjustableDPI::SensorDPIList& dpi_list, uint16_t dpi) { if(dpi_list.isRange) { @@ -58,7 +57,8 @@ uint16_t getClosestDPI(hidpp20::AdjustableDPI::SensorDPIList& dpi_list, } } -DPI::DPI(Device* device) : DeviceFeature(device), _config (device) +DPI::DPI(Device* device) : DeviceFeature(device), + _config (device->activeProfile().dpi) { try { _adjustable_dpi = std::make_shared @@ -70,20 +70,23 @@ DPI::DPI(Device* device) : DeviceFeature(device), _config (device) void DPI::configure() { - const uint8_t sensors = _adjustable_dpi->getSensorCount(); - for(uint8_t i = 0; i < _config.getSensorCount(); i++) { - hidpp20::AdjustableDPI::SensorDPIList dpi_list; - if(_dpi_lists.size() <= i) { - dpi_list = _adjustable_dpi->getSensorDPIList(i); - _dpi_lists.push_back(dpi_list); + if(_config.has_value()) { + const auto& config = _config.value(); + if(std::holds_alternative(config)) { + const auto& dpi = std::get(config); + _adjustable_dpi->setSensorDPI( + 0, + getClosestDPI(_adjustable_dpi->getSensorDPIList(0), + dpi) ); } else { - dpi_list = _dpi_lists[i]; - } - if(i < sensors) { - auto dpi = _config.getDPI(i); - if(dpi) { - _adjustable_dpi->setSensorDPI(i, getClosestDPI(dpi_list, - dpi)); + const auto& dpis = std::get>(config); + int i = 0; + for(const auto& dpi : dpis) { + _adjustable_dpi->setSensorDPI( + i, + getClosestDPI(_adjustable_dpi->getSensorDPIList(i), + dpi) ); + ++i; } } } @@ -111,36 +114,3 @@ void DPI::setDPI(uint16_t dpi, uint8_t sensor) dpi_list = _dpi_lists[sensor]; _adjustable_dpi->setSensorDPI(sensor, getClosestDPI(dpi_list, dpi)); } - -/* Some devices have multiple sensors, but an older config format - * only supports a single DPI. The dpi setting can be an array or - * an integer. - */ -DPI::Config::Config(Device *dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("dpi"); - if(config_root.isNumber()) { - int dpi = config_root; - _dpis.push_back(dpi); - } else if(config_root.isArray()) { - for(int i = 0; i < config_root.getLength(); i++) - _dpis.push_back((int)config_root[i]); - } else { - logPrintf(WARN, "Line %d: dpi is improperly formatted", - config_root.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - // DPI not configured, use default - } -} - -uint8_t DPI::Config::getSensorCount() -{ - return _dpis.size(); -} - -uint16_t DPI::Config::getDPI(uint8_t sensor) -{ - return _dpis[sensor]; -} diff --git a/src/logid/features/DPI.h b/src/logid/features/DPI.h index f2f6c33..de804b8 100644 --- a/src/logid/features/DPI.h +++ b/src/logid/features/DPI.h @@ -20,6 +20,7 @@ #include "../backend/hidpp20/features/AdjustableDPI.h" #include "DeviceFeature.h" +#include "../config/schema.h" namespace logid { namespace features @@ -33,18 +34,8 @@ namespace features uint16_t getDPI(uint8_t sensor=0); void setDPI(uint16_t dpi, uint8_t sensor=0); - - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - uint16_t getDPI(uint8_t sensor); - uint8_t getSensorCount(); - protected: - std::vector _dpis; - }; private: - Config _config; + std::optional& _config; std::shared_ptr _adjustable_dpi; std::vector _dpi_lists; }; diff --git a/src/logid/features/DeviceFeature.h b/src/logid/features/DeviceFeature.h index b5d60ee..7b7ed4a 100644 --- a/src/logid/features/DeviceFeature.h +++ b/src/logid/features/DeviceFeature.h @@ -44,15 +44,6 @@ namespace features virtual void configure() = 0; virtual void listen() = 0; virtual ~DeviceFeature() = default; - class Config - { - public: - explicit Config(Device* dev) : _device (dev) - { - } - protected: - Device* _device; - }; protected: Device* _device; diff --git a/src/logid/features/DeviceStatus.cpp b/src/logid/features/DeviceStatus.cpp index b41a7a2..e7c2bc7 100644 --- a/src/logid/features/DeviceStatus.cpp +++ b/src/logid/features/DeviceStatus.cpp @@ -34,7 +34,7 @@ DeviceStatus::DeviceStatus(logid::Device *dev) : DeviceFeature(dev) throw UnsupportedFeature(); try { - _wireless_device_status =std::make_shared< + _wireless_device_status = std::make_shared< hidpp20::WirelessDeviceStatus>(&dev->hidpp20()); } catch(hidpp20::UnsupportedFeature& e) { throw UnsupportedFeature(); diff --git a/src/logid/features/HiresScroll.cpp b/src/logid/features/HiresScroll.cpp index 720f994..b52b950 100644 --- a/src/logid/features/HiresScroll.cpp +++ b/src/logid/features/HiresScroll.cpp @@ -18,7 +18,6 @@ #include "HiresScroll.h" #include "../Device.h" #include "../InputDevice.h" -#include "../actions/gesture/Gesture.h" #include "../actions/gesture/AxisGesture.h" using namespace logid::features; @@ -26,38 +25,45 @@ using namespace logid::backend; #define MOVE_EVENTHANDLER_NAME "HIRES_SCROLL" -HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), _config(dev) +HiresScroll::HiresScroll(Device *dev) : DeviceFeature(dev), + _config (dev->activeProfile().hiresscroll), _mode (0), _mask (0) { + if(_config.has_value()) { + if(std::holds_alternative(_config.value())) { + config::HiresScroll conf {}; + conf.hires = std::get(_config.value()); + conf.invert = false; + conf.target = false; + _mask |= hidpp20::HiresScroll::Mode::HiRes; + _config.value() = conf; + } + auto& conf = std::get(_config.value()); + if(conf.hires.has_value()) { + _mask |= hidpp20::HiresScroll::Mode::HiRes; + if(conf.hires.value()) + _mode |= hidpp20::HiresScroll::Mode::HiRes; + } + if(conf.invert.has_value()) { + _mask |= hidpp20::HiresScroll::Mode::Inverted; + if(conf.invert.value()) + _mode |= hidpp20::HiresScroll::Mode::Inverted; + } + if(conf.target.has_value()) { + _mask |= hidpp20::HiresScroll::Mode::Target; + if(conf.target.value()) + _mode |= hidpp20::HiresScroll::Mode::Target; + } + + _makeAction(_up_action, conf.up); + _makeAction(_down_action, conf.down); + } + try { _hires_scroll = std::make_shared(&dev->hidpp20()); } catch(hidpp20::UnsupportedFeature& e) { throw UnsupportedFeature(); } - if(_config.upAction()) { - try { - auto up_axis = std::dynamic_pointer_cast( - _config.upAction()); - if(up_axis) - up_axis->setHiresMultiplier( - _hires_scroll->getCapabilities().multiplier); - } catch(std::bad_cast& e) { } - - _config.upAction()->press(true); - } - - if(_config.downAction()) { - try { - auto down_axis = std::dynamic_pointer_cast( - _config.downAction()); - if(down_axis) - down_axis->setHiresMultiplier( - _hires_scroll->getCapabilities().multiplier); - } catch(std::bad_cast& e) { } - - _config.downAction()->press(true); - } - _last_scroll = std::chrono::system_clock::now(); } @@ -69,8 +75,8 @@ HiresScroll::~HiresScroll() void HiresScroll::configure() { auto mode = _hires_scroll->getMode(); - mode &= ~_config.getMask(); - mode |= (_config.getMode() & _config.getMask()); + mode &= ~_mask; + mode |= (_mode & _mask); _hires_scroll->setMode(mode); } @@ -103,18 +109,37 @@ void HiresScroll::setMode(uint8_t mode) _hires_scroll->setMode(mode); } +void HiresScroll::_makeAction(std::shared_ptr &gesture, + std::optional &config) +{ + if(config.has_value()) { + gesture = actions::Gesture::makeGesture(_device, config.value()); + try { + auto axis = std::dynamic_pointer_cast( + gesture); + if(axis) + axis->setHiresMultiplier( + _hires_scroll->getCapabilities().multiplier); + } catch(std::bad_cast& e) { } + if(gesture) + gesture->press(true); + } else { + gesture.reset(); + } +} + void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) { auto now = std::chrono::system_clock::now(); if(std::chrono::duration_cast( now - _last_scroll).count() >= 1) { - if(_config.upAction()) { - _config.upAction()->release(); - _config.upAction()->press(true); + if(_up_action) { + _up_action->release(); + _up_action->press(true); } - if(_config.downAction()) { - _config.downAction()->release(); - _config.downAction()->press(true); + if(_down_action) { + _down_action->release(); + _down_action->press(true); } _last_direction = 0; @@ -122,140 +147,25 @@ void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) if(event.deltaV > 0) { if(_last_direction == -1) { - if(_config.downAction()){ - _config.downAction()->release(); - _config.downAction()->press(true); + if(_down_action){ + _down_action->release(); + _down_action->press(true); } } - if(_config.upAction()) - _config.upAction()->move(event.deltaV); + if(_up_action) + _up_action->move(event.deltaV); _last_direction = 1; } else if(event.deltaV < 0) { if(_last_direction == 1) { - if(_config.upAction()){ - _config.upAction()->release(); - _config.upAction()->press(true); + if(_up_action){ + _up_action->release(); + _up_action->press(true); } } - if(_config.downAction()) - _config.downAction()->move(-event.deltaV); + if(_down_action) + _down_action->move(-event.deltaV); _last_direction = -1; } _last_scroll = now; } - -HiresScroll::Config::Config(Device *dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("hiresscroll"); - if(!config_root.isGroup()) { - logPrintf(WARN, "Line %d: hiresscroll must be a group", - config_root.getSourceLine()); - return; - } - _mode = 0; - _mask = 0; - try { - auto& hires = config_root.lookup("hires"); - if(hires.getType() == libconfig::Setting::TypeBoolean) { - _mask |= hidpp20::HiresScroll::Mode::HiRes; - if(hires) - _mode |= hidpp20::HiresScroll::Mode::HiRes; - } else { - logPrintf(WARN, "Line %d: hires must be a boolean", - hires.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - try { - auto& invert = config_root.lookup("invert"); - if(invert.getType() == libconfig::Setting::TypeBoolean) { - _mask |= hidpp20::HiresScroll::Mode::Inverted; - if(invert) - _mode |= hidpp20::HiresScroll::Mode::Inverted; - } else { - logPrintf(WARN, "Line %d: invert must be a boolean, ignoring.", - invert.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - try { - auto& target = config_root.lookup("target"); - if(target.getType() == libconfig::Setting::TypeBoolean) { - _mask |= hidpp20::HiresScroll::Mode::Target; - if(target) - _mode |= hidpp20::HiresScroll::Mode::Target; - } else { - logPrintf(WARN, "Line %d: target must be a boolean, ignoring.", - target.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - if(_mode & hidpp20::HiresScroll::Mode::Target) { - try { - auto& up = config_root.lookup("up"); - try { - auto g = actions::Gesture::makeGesture(dev, up); - if(g->wheelCompatibility()) { - _up_action = g; - } else { - logPrintf(WARN, "Line %d: This gesture cannot be used" - " as a scroll action.", - up.getSourceLine()); - } - } catch(actions::InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid scroll action", - up.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException&) { - logPrintf(WARN, "Line %d: target is true but no up action was" - " set", config_root.getSourceLine()); - } - - try { - auto& down = config_root.lookup("down"); - try { - auto g = actions::Gesture::makeGesture(dev, down); - if(g->wheelCompatibility()) { - _down_action = g; - } else { - logPrintf(WARN, "Line %d: This gesture cannot be used" - " as a scroll action.", - down.getSourceLine()); - } - } catch(actions::InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid scroll action", - down.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException&) { - logPrintf(WARN, "Line %d: target is true but no down action was" - " set", config_root.getSourceLine()); - } - } - } catch(libconfig::SettingNotFoundException& e) { - // HiresScroll not configured, use default - } -} - -uint8_t HiresScroll::Config::getMode() const -{ - return _mode; -} - -uint8_t HiresScroll::Config::getMask() const -{ - return _mask; -} - -const std::shared_ptr& - HiresScroll::Config::upAction() const -{ - return _up_action; -} - -const std::shared_ptr& - HiresScroll::Config::downAction() const -{ - return _down_action; -} \ No newline at end of file diff --git a/src/logid/features/HiresScroll.h b/src/logid/features/HiresScroll.h index 7cc2f67..1f74825 100644 --- a/src/logid/features/HiresScroll.h +++ b/src/logid/features/HiresScroll.h @@ -35,29 +35,22 @@ namespace features uint8_t getMode(); void setMode(uint8_t mode); - - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - uint8_t getMode() const; - uint8_t getMask() const; - - const std::shared_ptr& upAction() const; - const std::shared_ptr& downAction() const; - protected: - uint8_t _mode; - uint8_t _mask; - - std::shared_ptr _up_action; - std::shared_ptr _down_action; - }; private: + void _makeAction(std::shared_ptr& gesture, + std::optional& config); + void _handleScroll(backend::hidpp20::HiresScroll::WheelStatus event); std::shared_ptr _hires_scroll; std::chrono::time_point _last_scroll; int16_t _last_direction = 0; - Config _config; + + std::optional>& _config; + + uint8_t _mode; + uint8_t _mask; + + std::shared_ptr _up_action; + std::shared_ptr _down_action; }; }} diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index e019c46..ea86014 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -29,9 +29,26 @@ using namespace logid::actions; #define EVENTHANDLER_NAME "REMAP_BUTTON" -RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), +RemapButton::RemapButton(Device *dev): DeviceFeature(dev), + _config (dev->activeProfile().buttons), _ipc_node (dev->ipcNode()->make_child("buttons")) { + if(_config.has_value()) { + for(auto& button : _config.value()) { + if(button.second.action.has_value()) { + try { + _buttons.emplace( + button.first, + Action::makeAction( + dev,button.second.action.value())); + } catch(std::exception& e) { + logPrintf(WARN, "Error creating button action: %s", + e.what()); + } + } + } + } + try { _reprog_controls = hidpp20::ReprogControls::autoVersion( &dev->hidpp20()); @@ -42,10 +59,10 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), _reprog_controls->initCidMap(); if(global_loglevel <= DEBUG) { - #define FLAG(x) control.second.flags & hidpp20::ReprogControls::x ? \ - "YES" : "" - #define ADDITIONAL_FLAG(x) control.second.additionalFlags & \ - hidpp20::ReprogControls::x ? "YES" : "" + #define FLAG(x) (control.second.flags & hidpp20::ReprogControls::x ? \ + "YES" : "") + #define ADDITIONAL_FLAG(x) (control.second.additionalFlags & \ + hidpp20::ReprogControls::x ? "YES" : "") // Print CIDs, originally by zv0n logPrintf(DEBUG, "%s:%d remappable buttons:", @@ -57,6 +74,7 @@ RemapButton::RemapButton(Device *dev): DeviceFeature(dev), _config (dev), logPrintf(DEBUG, "0x%02x | %-7s | %-7s | %-10s | %s", control.first, FLAG(TemporaryDivertable), FLAG(FKey), FLAG(MouseButton), ADDITIONAL_FLAG(RawXY)); + #undef ADDITIONAL_FLAG #undef FLAG } @@ -77,7 +95,7 @@ RemapButton::~RemapButton() void RemapButton::configure() { ///TODO: DJ reporting trickery if cannot be remapped - for(const auto& i : _config.buttons()) { + for(const auto& i : _buttons) { hidpp20::ReprogControls::ControlInfo info{}; try { info = _reprog_controls->getControlIdInfo(i.first); @@ -123,7 +141,7 @@ void RemapButton::listen() report)); else { // RawXY auto divertedXY = _reprog_controls->divertedRawXYEvent(report); - for(const auto& button : this->_config.buttons()) + for(const auto& button : this->_buttons) if(button.second->pressed()) button.second->move(divertedXY.x, divertedXY.y); } @@ -144,80 +162,22 @@ void RemapButton::_buttonEvent(const std::set& new_state) if(old_i != _pressed_buttons.end()) { _pressed_buttons.erase(old_i); } else { - auto action = _config.buttons().find(i); - if(action != _config.buttons().end()) + auto action = _buttons.find(i); + if(action != _buttons.end()) action->second->press(); } } // Release all removed buttons for(auto& i : _pressed_buttons) { - auto action = _config.buttons().find(i); - if(action != _config.buttons().end()) + auto action = _buttons.find(i); + if(action != _buttons.end()) action->second->release(); } _pressed_buttons = new_state; } -RemapButton::Config::Config(Device *dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("buttons"); - if(!config_root.isList()) { - logPrintf(WARN, "Line %d: buttons must be a list.", - config_root.getSourceLine()); - return; - } - int button_count = config_root.getLength(); - for(int i = 0; i < button_count; i++) - _parseButton(config_root[i]); - } catch(libconfig::SettingNotFoundException& e) { - // buttons not configured, use default - } -} - -void RemapButton::Config::_parseButton(libconfig::Setting &setting) -{ - if(!setting.isGroup()) { - logPrintf(WARN, "Line %d: button must be an object, ignoring.", - setting.getSourceLine()); - return; - } - - uint16_t cid; - try { - auto& cid_setting = setting.lookup("cid"); - if(!cid_setting.isNumber()) { - logPrintf(WARN, "Line %d: cid must be a number, ignoring.", - cid_setting.getSourceLine()); - return; - } - cid = (int)cid_setting; - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: cid is required, ignoring.", - setting.getSourceLine()); - return; - } - - try { - _buttons.emplace(cid, Action::makeAction(_device, - setting.lookup("action"))); - } catch(libconfig::SettingNotFoundException& e) { - logPrintf(WARN, "Line %d: action is required, ignoring.", - setting.getSourceLine()); - } catch(InvalidAction& e) { - logPrintf(WARN, "Line %d: %s is not a valid action, ignoring.", - setting["action"].getSourceLine(), e.what()); - } -} - -const std::map>& RemapButton::Config::buttons() -{ - return _buttons; -} - - RemapButton::ButtonIPC::ButtonIPC( RemapButton *parent, backend::hidpp20::ReprogControls::ControlInfo info) : @@ -225,9 +185,11 @@ RemapButton::ButtonIPC::ButtonIPC( {"ControlID", ipcgull::property( ipcgull::property_readable, info.controlID)}, {"Remappable", ipcgull::property( - ipcgull::property_readable, info.flags & hidpp20::ReprogControls::TemporaryDivertable)}, + ipcgull::property_readable, + info.flags & hidpp20::ReprogControls::TemporaryDivertable)}, {"GestureSupport", ipcgull::property( - ipcgull::property_readable, (info.additionalFlags & hidpp20::ReprogControls::RawXY) + ipcgull::property_readable, + (info.additionalFlags & hidpp20::ReprogControls::RawXY) )} }, {}) { diff --git a/src/logid/features/RemapButton.h b/src/logid/features/RemapButton.h index 1aa1425..e78fe26 100644 --- a/src/logid/features/RemapButton.h +++ b/src/logid/features/RemapButton.h @@ -33,16 +33,6 @@ namespace features virtual void configure(); virtual void listen(); - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - const std::map>& - buttons(); - protected: - void _parseButton(libconfig::Setting& setting); - std::map> _buttons; - }; private: class ButtonIPC : public ipcgull::interface { @@ -52,11 +42,13 @@ namespace features }; void _buttonEvent(const std::set& new_state); - Config _config; std::shared_ptr _reprog_controls; std::set _pressed_buttons; std::mutex _button_lock; + std::optional& _config; + std::map> _buttons; + std::shared_ptr _ipc_node; typedef std::pair, std::shared_ptr> ButtonIPCPair; diff --git a/src/logid/features/SmartShift.cpp b/src/logid/features/SmartShift.cpp index 5f219e7..91f319d 100644 --- a/src/logid/features/SmartShift.cpp +++ b/src/logid/features/SmartShift.cpp @@ -22,8 +22,8 @@ using namespace logid::features; using namespace logid::backend; -SmartShift::SmartShift(Device* device) : DeviceFeature(device), _config - (device) +SmartShift::SmartShift(Device* device) : DeviceFeature(device), + _config (device->activeProfile().smartshift) { try { _smartshift = std::make_shared(&device->hidpp20()); @@ -34,7 +34,18 @@ SmartShift::SmartShift(Device* device) : DeviceFeature(device), _config void SmartShift::configure() { - _smartshift->setStatus(_config.getSettings()); + if(_config.has_value()) { + const auto& conf = _config.value(); + hidpp20::SmartShift::SmartshiftStatus settings {}; + settings.setActive = conf.on.has_value(); + if(settings.setActive) + settings.active = conf.on.value(); + settings.setAutoDisengage = conf.threshold.has_value(); + if(settings.setAutoDisengage) + settings.autoDisengage = conf.threshold.value(); + + _smartshift->setStatus(settings); + } } void SmartShift::listen() @@ -51,31 +62,3 @@ void SmartShift::setStatus(backend::hidpp20::SmartShift::SmartshiftStatus { _smartshift->setStatus(status); } - -SmartShift::Config::Config(Device *dev) : DeviceFeature::Config(dev), _status() -{ - try { - auto& config_root = dev->config().getSetting("smartshift"); - if(!config_root.isGroup()) { - logPrintf(WARN, "Line %d: smartshift must be an object", - config_root.getSourceLine()); - return; - } - _status.setActive = config_root.lookupValue("on", _status.active); - int tmp; - _status.setAutoDisengage = config_root.lookupValue("threshold", tmp); - if(_status.setAutoDisengage) - _status.autoDisengage = tmp; - _status.setDefaultAutoDisengage = config_root.lookupValue - ("default_threshold", tmp); - if(_status.setDefaultAutoDisengage) - _status.defaultAutoDisengage = tmp; - } catch(libconfig::SettingNotFoundException& e) { - // SmartShift not configured, use default - } -} - -hidpp20::SmartShift::SmartshiftStatus SmartShift::Config::getSettings() -{ - return _status; -} \ No newline at end of file diff --git a/src/logid/features/SmartShift.h b/src/logid/features/SmartShift.h index ed7ac35..6ef3330 100644 --- a/src/logid/features/SmartShift.h +++ b/src/logid/features/SmartShift.h @@ -20,6 +20,7 @@ #include "../backend/hidpp20/features/SmartShift.h" #include "DeviceFeature.h" +#include "../config/schema.h" namespace logid { namespace features @@ -34,16 +35,8 @@ namespace features backend::hidpp20::SmartShift::SmartshiftStatus getStatus(); void setStatus(backend::hidpp20::SmartShift::SmartshiftStatus status); - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - backend::hidpp20::SmartShift::SmartshiftStatus getSettings(); - protected: - backend::hidpp20::SmartShift::SmartshiftStatus _status; - }; private: - Config _config; + std::optional& _config; std::shared_ptr _smartshift; }; }} diff --git a/src/logid/features/ThumbWheel.cpp b/src/logid/features/ThumbWheel.cpp index 14b5dcc..458de92 100644 --- a/src/logid/features/ThumbWheel.cpp +++ b/src/logid/features/ThumbWheel.cpp @@ -29,9 +29,46 @@ using namespace logid; #define SCROLL_EVENTHANDLER_NAME "THUMB_WHEEL" -ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), - _config(dev) +std::shared_ptr _genAction( + Device* dev, std::optional& conf) { + if(conf.has_value()) { + try { + return actions::Action::makeAction(dev, conf.value()); + } catch(actions::InvalidAction& e) { + logPrintf(WARN, "Mapping thumb wheel to invalid action"); + } + } + + return nullptr; +} + +std::shared_ptr _genGesture( + Device* dev, std::optional& conf) +{ + if(conf.has_value()) { + try { + return actions::Gesture::makeGesture(dev, conf.value()); + } catch (actions::InvalidAction &e) { + logPrintf(WARN, "Mapping thumb wheel to invalid gesture"); + } + } + + return nullptr; +} + +ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), + _config (dev->activeProfile().thumbwheel) +{ + if(_config.has_value()) { + auto& conf = _config.value(); + _left_action = _genGesture(dev, conf.left); + _right_action = _genGesture(dev, conf.right); + _touch_action = _genAction(dev, conf.touch); + _tap_action = _genAction(dev, conf.tap); + _proxy_action = _genAction(dev, conf.proxy); + } + try { _thumb_wheel = std::make_shared(&dev->hidpp20()); } catch(hidpp20::UnsupportedFeature& e) { @@ -47,33 +84,41 @@ ThumbWheel::ThumbWheel(Device *dev) : DeviceFeature(dev), _wheel_info(), logPrintf(DEBUG, "Thumb wheel resolution: native (%d), diverted (%d)", _wheel_info.nativeRes, _wheel_info.divertedRes); - if(_config.leftAction()) { + if(_left_action) { try { auto left_axis = std::dynamic_pointer_cast( - _config.leftAction()); + _left_action); // TODO: How do hires multipliers work on 0x2150 thumbwheels? if(left_axis) left_axis->setHiresMultiplier(_wheel_info.divertedRes); } catch(std::bad_cast& e) { } - _config.leftAction()->press(true); + _left_action->press(true); } - if(_config.rightAction()) { + if(_right_action) { try { auto right_axis = std::dynamic_pointer_cast( - _config.rightAction()); + _right_action); if(right_axis) right_axis->setHiresMultiplier(_wheel_info.divertedRes); } catch(std::bad_cast& e) { } - _config.rightAction()->press(true); + _right_action->press(true); } } +ThumbWheel::~ThumbWheel() { + _device->hidpp20().removeEventHandler(SCROLL_EVENTHANDLER_NAME); +} + void ThumbWheel::configure() { - _thumb_wheel->setStatus(_config.divert(), _config.invert()); + if(_config.has_value()) { + const auto& config = _config.value(); + _thumb_wheel->setStatus(config.divert.value_or(false), + config.invert.value_or(false)); + } } void ThumbWheel::listen() @@ -98,7 +143,7 @@ void ThumbWheel::listen() void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) { if(event.flags & hidpp20::ThumbWheel::SingleTap) { - auto action = _config.tapAction(); + auto action = _tap_action; if(action) { action->press(); action->release(); @@ -107,23 +152,21 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) if((bool)(event.flags & hidpp20::ThumbWheel::Proxy) != _last_proxy) { _last_proxy = !_last_proxy; - auto action = _config.proxyAction(); - if(action) { + if(_proxy_action) { if(_last_proxy) - action->press(); + _proxy_action->press(); else - action->release(); + _proxy_action->release(); } } if((bool)(event.flags & hidpp20::ThumbWheel::Touch) != _last_touch) { _last_touch = !_last_touch; - auto action = _config.touchAction(); - if(action) { + if(_touch_action) { if(_last_touch) - action->press(); + _touch_action->press(); else - action->release(); + _touch_action->release(); } } @@ -132,10 +175,10 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) event.rotation *= _wheel_info.defaultDirection; if(event.rotationStatus == hidpp20::ThumbWheel::Start) { - if(_config.rightAction()) - _config.rightAction()->press(true); - if(_config.leftAction()) - _config.leftAction()->press(true); + if(_right_action) + _right_action->press(true); + if(_left_action) + _left_action->press(true); _last_direction = 0; } @@ -144,9 +187,9 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) std::shared_ptr scroll_action; if(direction > 0) - scroll_action = _config.rightAction(); + scroll_action = _right_action; else - scroll_action = _config.leftAction(); + scroll_action = _left_action; if(scroll_action) { scroll_action->press(true); @@ -157,136 +200,10 @@ void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) } if(event.rotationStatus == hidpp20::ThumbWheel::Stop) { - if(_config.rightAction()) - _config.rightAction()->release(); - if(_config.leftAction()) - _config.leftAction()->release(); + if(_right_action) + _right_action->release(); + if(_left_action) + _left_action->release(); } } } - -ThumbWheel::Config::Config(Device* dev) : DeviceFeature::Config(dev) -{ - try { - auto& config_root = dev->config().getSetting("thumbwheel"); - if(!config_root.isGroup()) { - logPrintf(WARN, "Line %d: thumbwheel must be a group", - config_root.getSourceLine()); - return; - } - - try { - auto& divert = config_root.lookup("divert"); - if(divert.getType() == libconfig::Setting::TypeBoolean) { - _divert = divert; - } else { - logPrintf(WARN, "Line %d: divert must be a boolean", - divert.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - try { - auto& invert = config_root.lookup("invert"); - if(invert.getType() == libconfig::Setting::TypeBoolean) { - _invert = invert; - } else { - logPrintf(WARN, "Line %d: invert must be a boolean, ignoring.", - invert.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { } - - if(_divert) { - _left_action = _genGesture(dev, config_root, "left"); - if(!_left_action) - logPrintf(WARN, "Line %d: divert is true but no left action " - "was set", config_root.getSourceLine()); - - _right_action = _genGesture(dev, config_root, "right"); - if(!_right_action) - logPrintf(WARN, "Line %d: divert is true but no right action " - "was set", config_root.getSourceLine()); - } - - _proxy_action = _genAction(dev, config_root, "proxy"); - _tap_action = _genAction(dev, config_root, "tap"); - _touch_action = _genAction(dev, config_root, "touch"); - } catch(libconfig::SettingNotFoundException& e) { - // ThumbWheel not configured, use default - } -} - -std::shared_ptr ThumbWheel::Config::_genAction(Device* dev, - libconfig::Setting& config_root, const std::string& name) -{ - try { - auto& a_group = config_root.lookup(name); - try { - return actions::Action::makeAction(dev, a_group); - } catch(actions::InvalidAction& e) { - logPrintf(WARN, "Line %d: Invalid action", - a_group.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - - } - return nullptr; -} - -std::shared_ptr ThumbWheel::Config::_genGesture(Device* dev, - libconfig::Setting& config_root, const std::string& name) -{ - try { - auto& g_group = config_root.lookup(name); - try { - auto g = actions::Gesture::makeGesture(dev, g_group); - if(g->wheelCompatibility()) { - return g; - } else { - logPrintf(WARN, "Line %d: This gesture cannot be used" - " as a scroll action.", - g_group.getSourceLine()); - } - } catch(actions::InvalidGesture& e) { - logPrintf(WARN, "Line %d: Invalid scroll action", - g_group.getSourceLine()); - } - } catch(libconfig::SettingNotFoundException& e) { - - } - return nullptr; -} - -bool ThumbWheel::Config::divert() const -{ - return _divert; -} - -bool ThumbWheel::Config::invert() const -{ - return _invert; -} - -const std::shared_ptr& ThumbWheel::Config::leftAction() const -{ - return _left_action; -} - -const std::shared_ptr& ThumbWheel::Config::rightAction() const -{ - return _right_action; -} - -const std::shared_ptr& ThumbWheel::Config::proxyAction() const -{ - return _proxy_action; -} - -const std::shared_ptr& ThumbWheel::Config::tapAction() const -{ - return _tap_action; -} - -const std::shared_ptr& ThumbWheel::Config::touchAction() const -{ - return _touch_action; -} diff --git a/src/logid/features/ThumbWheel.h b/src/logid/features/ThumbWheel.h index fae93ea..f76fd33 100644 --- a/src/logid/features/ThumbWheel.h +++ b/src/logid/features/ThumbWheel.h @@ -21,6 +21,7 @@ #include "../backend/hidpp20/features/ThumbWheel.h" #include "DeviceFeature.h" #include "../actions/gesture/Gesture.h" +#include "../config/schema.h" namespace logid { namespace features @@ -29,45 +30,26 @@ namespace features { public: explicit ThumbWheel(Device* dev); + ~ThumbWheel(); virtual void configure(); virtual void listen(); - class Config : public DeviceFeature::Config - { - public: - explicit Config(Device* dev); - bool divert() const; - bool invert() const; - - const std::shared_ptr& leftAction() const; - const std::shared_ptr& rightAction() const; - const std::shared_ptr& proxyAction() const; - const std::shared_ptr& tapAction() const; - const std::shared_ptr& touchAction() const; - protected: - bool _divert = false; - bool _invert = false; - - static std::shared_ptr _genGesture(Device* dev, - libconfig::Setting& setting, const std::string& name); - static std::shared_ptr _genAction(Device* dev, - libconfig::Setting& setting, const std::string& name); - - std::shared_ptr _left_action; - std::shared_ptr _right_action; - std::shared_ptr _proxy_action; - std::shared_ptr _tap_action; - std::shared_ptr _touch_action; - }; private: void _handleEvent(backend::hidpp20::ThumbWheel::ThumbwheelEvent event); std::shared_ptr _thumb_wheel; backend::hidpp20::ThumbWheel::ThumbwheelInfo _wheel_info; + + std::shared_ptr _left_action; + std::shared_ptr _right_action; + std::shared_ptr _proxy_action; + std::shared_ptr _tap_action; + std::shared_ptr _touch_action; + int8_t _last_direction = 0; bool _last_proxy = false; bool _last_touch = false; - Config _config; + std::optional& _config; }; }}