Add full profile support

This commit is contained in:
pixl 2023-05-02 18:06:25 -04:00
parent c0e532b1de
commit 27b6a2fd8f
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
16 changed files with 334 additions and 128 deletions

View File

@ -25,6 +25,7 @@
#include <features/DeviceStatus.h> #include <features/DeviceStatus.h>
#include <features/ThumbWheel.h> #include <features/ThumbWheel.h>
#include <backend/hidpp20/features/Reset.h> #include <backend/hidpp20/features/Reset.h>
#include <util/task.h>
#include <util/log.h> #include <util/log.h>
#include <thread> #include <thread>
#include <utility> #include <utility>
@ -94,9 +95,11 @@ std::shared_ptr<Device> Device::make(
Device::Device(std::string path, backend::hidpp::DeviceIndex index, Device::Device(std::string path, backend::hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager) : const std::shared_ptr<DeviceManager>& manager) :
_hidpp20(hidpp20::Device::make(path, index, manager, _hidpp20(hidpp20::Device::make(path, index, manager,
manager->config()->io_timeout.value_or(defaults::io_timeout))), manager->config()->io_timeout.value_or(
defaults::io_timeout))),
_path(std::move(path)), _index(index), _path(std::move(path)), _index(index),
_config(_getConfig(manager, _hidpp20->name())), _config(_getConfig(manager, _hidpp20->name())),
_profile_name(ipcgull::property_readable, ""),
_receiver(nullptr), _receiver(nullptr),
_manager(manager), _manager(manager),
_nickname(manager), _nickname(manager),
@ -112,6 +115,7 @@ Device::Device(std::shared_ptr<backend::raw::RawDevice> raw_device,
manager->config()->io_timeout.value_or(defaults::io_timeout))), manager->config()->io_timeout.value_or(defaults::io_timeout))),
_path(raw_device->rawPath()), _index(index), _path(raw_device->rawPath()), _index(index),
_config(_getConfig(manager, _hidpp20->name())), _config(_getConfig(manager, _hidpp20->name())),
_profile_name(ipcgull::property_readable, ""),
_receiver(nullptr), _receiver(nullptr),
_manager(manager), _manager(manager),
_nickname(manager), _nickname(manager),
@ -127,6 +131,7 @@ Device::Device(Receiver* receiver, hidpp::DeviceIndex index,
manager->config()->io_timeout.value_or(defaults::io_timeout))), manager->config()->io_timeout.value_or(defaults::io_timeout))),
_path(receiver->path()), _index(index), _path(receiver->path()), _index(index),
_config(_getConfig(manager, _hidpp20->name())), _config(_getConfig(manager, _hidpp20->name())),
_profile_name(ipcgull::property_readable, ""),
_receiver(receiver), _receiver(receiver),
_manager(manager), _manager(manager),
_nickname(manager), _nickname(manager),
@ -139,9 +144,13 @@ void Device::_init() {
logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(), logPrintf(INFO, "Device found: %s on %s:%d", name().c_str(),
hidpp20().devicePath().c_str(), _index); hidpp20().devicePath().c_str(), _index);
_profile = _config.profiles.find(_config.default_profile); {
if (_profile == _config.profiles.end()) std::unique_lock lock(_profile_mutex);
_profile = _config.profiles.insert({_config.default_profile, {}}).first; _profile = _config.profiles.find(_config.default_profile);
if (_profile == _config.profiles.end())
_profile = _config.profiles.insert({_config.default_profile, {}}).first;
_profile_name = _config.default_profile;
}
_addFeature<features::DPI>("dpi"); _addFeature<features::DPI>("dpi");
_addFeature<features::SmartShift>("smartshift"); _addFeature<features::SmartShift>("smartshift");
@ -180,10 +189,7 @@ void Device::wakeup() {
std::lock_guard<std::mutex> lock(_state_lock); std::lock_guard<std::mutex> lock(_state_lock);
logPrintf(INFO, "%s:%d woke up.", _path.c_str(), _index); logPrintf(INFO, "%s:%d woke up.", _path.c_str(), _index);
reset(); reconfigure();
for (auto& feature: _features)
feature.second->configure();
if (!_awake) { if (!_awake) {
_awake = true; _awake = true;
@ -191,6 +197,13 @@ void Device::wakeup() {
} }
} }
void Device::reconfigure() {
reset();
for (auto& feature: _features)
feature.second->configure();
}
void Device::reset() { void Device::reset() {
if (_reset_mechanism) if (_reset_mechanism)
(*_reset_mechanism)(); (*_reset_mechanism)();
@ -215,11 +228,71 @@ std::shared_ptr<ipcgull::node> Device::ipcNode() const {
return _ipc_node; return _ipc_node;
} }
config::Profile& Device::activeProfile() { std::vector<std::string> Device::getProfiles() const {
return _profile->second; std::shared_lock lock(_profile_mutex);
std::vector<std::string> ret;
for (auto& profile : _config.profiles) {
ret.push_back(profile.first);
}
return ret;
} }
const config::Profile& Device::activeProfile() const { void Device::setProfile(const std::string& profile) {
std::unique_lock lock(_profile_mutex);
_profile = _config.profiles.find(profile);
if (_profile == _config.profiles.end())
_profile = _config.profiles.insert({profile, {}}).first;
_profile_name = profile;
for (auto& feature : _features)
feature.second->setProfile(_profile->second);
reconfigure();
}
void Device::setProfileDelayed(const std::string& profile) {
run_task([self_weak = _self, profile](){
if (auto self = self_weak.lock())
self->setProfile(profile);
});
}
void Device::removeProfile(const std::string& profile) {
std::unique_lock lock(_profile_mutex);
if (profile == (std::string)_profile_name)
throw std::invalid_argument("cannot remove active profile");
else if (profile == (std::string)_config.default_profile)
throw std::invalid_argument("cannot remove default profile");
_config.profiles.erase(profile);
}
void Device::clearProfile(const std::string& profile) {
std::unique_lock lock(_profile_mutex);
if (profile == (std::string)_profile_name) {
_profile->second = config::Profile();
for (auto& feature : _features)
feature.second->setProfile(_profile->second);
reconfigure();
} else {
auto it = _config.profiles.find(profile);
if (it != _config.profiles.end()) {
it->second = config::Profile();
} else {
throw std::invalid_argument("unknown profile");
}
}
}
config::Profile& Device::activeProfile() {
std::shared_lock lock(_profile_mutex);
return _profile->second; return _profile->second;
} }
@ -243,17 +316,22 @@ void Device::_makeResetMechanism() {
Device::IPC::IPC(Device* device) : Device::IPC::IPC(Device* device) :
ipcgull::interface( ipcgull::interface(
SERVICE_ROOT_NAME ".Device", SERVICE_ROOT_NAME ".Device",
{}, {
{"GetProfiles", {device, &Device::getProfiles, {"profiles"}}},
{"SetProfile", {device, &Device::setProfile, {"profile"}}},
{"RemoveProfile", {device, &Device::removeProfile, {"profile"}}},
{"ClearProfile", {device, &Device::clearProfile, {"profile"}}}
},
{ {
{"Name", ipcgull::property<std::string>( {"Name", ipcgull::property<std::string>(
ipcgull::property_readable, device->name())}, ipcgull::property_readable, device->name())},
{"ProductID", ipcgull::property<uint16_t>( {"ProductID", ipcgull::property<uint16_t>(
ipcgull::property_readable, device->pid())}, ipcgull::property_readable, device->pid())},
{"Active", device->_awake}, {"Active", device->_awake},
{"DefaultProfile", device->_config.default_profile} {"DefaultProfile", device->_config.default_profile},
{"ActiveProfile", device->_profile_name}
}, { }, {
{"StatusChanged", {"StatusChanged", ipcgull::signal::make_signal<bool>({"active"})}
ipcgull::signal::make_signal<bool>({"active"})}
}), _device(*device) { }), _device(*device) {
} }

View File

@ -62,10 +62,17 @@ namespace logid {
uint16_t pid(); uint16_t pid();
//config::Device& config(); [[nodiscard]] config::Profile& activeProfile();
config::Profile& activeProfile();
[[nodiscard]] const config::Profile& activeProfile() const; [[nodiscard]] std::vector<std::string> getProfiles() const;
void setProfile(const std::string& profile);
void setProfileDelayed(const std::string& profile);
void removeProfile(const std::string& profile);
void clearProfile(const std::string& profile);
backend::hidpp20::Device& hidpp20(); backend::hidpp20::Device& hidpp20();
@ -88,6 +95,8 @@ namespace logid {
void sleep(); void sleep();
void reconfigure();
void reset(); void reset();
[[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const; [[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const;
@ -107,7 +116,9 @@ namespace logid {
} }
Device(const Device&) = delete; Device(const Device&) = delete;
Device(Device&&) = delete; Device(Device&&) = delete;
private: private:
friend class DeviceWrapper; friend class DeviceWrapper;
@ -139,9 +150,11 @@ namespace logid {
std::shared_ptr<backend::hidpp20::Device> _hidpp20; std::shared_ptr<backend::hidpp20::Device> _hidpp20;
std::string _path; std::string _path;
backend::hidpp::DeviceIndex _index; backend::hidpp::DeviceIndex _index;
std::map<std::string, std::shared_ptr<features::DeviceFeature>> std::map<std::string, std::shared_ptr<features::DeviceFeature>> _features;
_features;
config::Device& _config; config::Device& _config;
mutable std::shared_mutex _profile_mutex;
ipcgull::property<std::string> _profile_name;
std::map<std::string, config::Profile>::iterator _profile; std::map<std::string, config::Profile>::iterator _profile;
Receiver* _receiver; Receiver* _receiver;

View File

@ -69,11 +69,7 @@ namespace logid::actions {
virtual void release() = 0; virtual void release() = 0;
virtual void move(int16_t x, int16_t y) { virtual void move([[maybe_unused]] int16_t x, [[maybe_unused]] int16_t y) { }
// Suppress unused warning
(void) x;
(void) y;
}
virtual bool pressed() { virtual bool pressed() {
return _pressed; return _pressed;

View File

@ -69,8 +69,8 @@ DPI::DPI(Device* device) : DeviceFeature(device), _config(device->activeProfile(
void DPI::configure() { void DPI::configure() {
std::shared_lock lock(_config_mutex); std::shared_lock lock(_config_mutex);
if (_config.has_value()) { if (_config.get().has_value()) {
const auto& config = _config.value(); const auto& config = _config.get().value();
if (std::holds_alternative<int>(config)) { if (std::holds_alternative<int>(config)) {
const auto& dpi = std::get<int>(config); const auto& dpi = std::get<int>(config);
_fillDPILists(0); _fillDPILists(0);
@ -96,6 +96,11 @@ void DPI::configure() {
void DPI::listen() { void DPI::listen() {
} }
void DPI::setProfile(config::Profile& profile) {
std::unique_lock lock(_config_mutex);
_config = profile.dpi;
}
uint16_t DPI::getDPI(uint8_t sensor) { uint16_t DPI::getDPI(uint8_t sensor) {
return _adjustable_dpi->getSensorDPI(sensor); return _adjustable_dpi->getSensorDPI(sensor);
} }
@ -145,17 +150,19 @@ std::tuple<std::vector<uint16_t>, uint16_t, bool> DPI::IPC::getDPIs(uint8_t sens
uint16_t DPI::IPC::getDPI(uint8_t sensor) const { uint16_t DPI::IPC::getDPI(uint8_t sensor) const {
std::shared_lock lock(_parent._config_mutex); std::shared_lock lock(_parent._config_mutex);
if (!_parent._config.has_value()) auto& config = _parent._config.get();
if (!config.has_value())
return _parent.getDPI(sensor); return _parent.getDPI(sensor);
if (std::holds_alternative<int>(_parent._config.value())) { if (std::holds_alternative<int>(config.value())) {
if (sensor == 0) if (sensor == 0)
return std::get<int>(_parent._config.value()); return std::get<int>(config.value());
else else
return _parent.getDPI(sensor); return _parent.getDPI(sensor);
} }
const auto& list = std::get<std::list<int>>(_parent._config.value()); const auto& list = std::get<std::list<int>>(config.value());
if (list.size() > sensor) { if (list.size() > sensor) {
auto it = list.begin(); auto it = list.begin();
@ -168,21 +175,22 @@ uint16_t DPI::IPC::getDPI(uint8_t sensor) const {
void DPI::IPC::setDPI(uint16_t dpi, uint8_t sensor) { void DPI::IPC::setDPI(uint16_t dpi, uint8_t sensor) {
std::unique_lock lock(_parent._config_mutex); std::unique_lock lock(_parent._config_mutex);
auto& config = _parent._config.get();
if (!_parent._config.has_value()) if (!config.has_value())
_parent._config.emplace(std::list<int>()); config.emplace(std::list<int>());
if (std::holds_alternative<int>(_parent._config.value())) { if (std::holds_alternative<int>(config.value())) {
if (sensor == 0) { if (sensor == 0) {
_parent._config.value() = dpi; config.value() = dpi;
} else { } else {
auto list = std::list<int>(sensor + 1, 0); auto list = std::list<int>(sensor + 1, 0);
*list.rbegin() = dpi; *list.rbegin() = dpi;
*list.begin() = dpi; *list.begin() = dpi;
_parent._config.value() = list; config.value() = list;
} }
} else { } else {
auto& list = std::get<std::list<int>>(_parent._config.value()); auto& list = std::get<std::list<int>>(config.value());
while (list.size() <= sensor) { while (list.size() <= sensor) {
list.emplace_back(0); list.emplace_back(0);

View File

@ -31,6 +31,8 @@ namespace logid::features {
void listen() final; void listen() final;
void setProfile(config::Profile& profile) final;
uint16_t getDPI(uint8_t sensor = 0); uint16_t getDPI(uint8_t sensor = 0);
void setDPI(uint16_t dpi, uint8_t sensor = 0); void setDPI(uint16_t dpi, uint8_t sensor = 0);
@ -59,7 +61,7 @@ namespace logid::features {
}; };
mutable std::shared_mutex _config_mutex; mutable std::shared_mutex _config_mutex;
std::optional<config::DPI>& _config; std::reference_wrapper<std::optional<config::DPI>> _config;
std::shared_ptr<backend::hidpp20::AdjustableDPI> _adjustable_dpi; std::shared_ptr<backend::hidpp20::AdjustableDPI> _adjustable_dpi;
mutable std::shared_mutex _dpi_list_mutex; mutable std::shared_mutex _dpi_list_mutex;
std::vector<backend::hidpp20::AdjustableDPI::SensorDPIList> _dpi_lists; std::vector<backend::hidpp20::AdjustableDPI::SensorDPIList> _dpi_lists;

View File

@ -26,6 +26,10 @@ namespace logid {
class Device; class Device;
} }
namespace logid::config {
struct Profile;
}
namespace logid::features { namespace logid::features {
class UnsupportedFeature : public std::exception { class UnsupportedFeature : public std::exception {
public: public:
@ -59,6 +63,8 @@ namespace logid::features {
virtual void listen() = 0; virtual void listen() = 0;
virtual void setProfile(config::Profile& profile) = 0;
virtual ~DeviceFeature() = default; virtual ~DeviceFeature() = default;
DeviceFeature(const DeviceFeature&) = delete; DeviceFeature(const DeviceFeature&) = delete;

View File

@ -61,4 +61,7 @@ void DeviceStatus::listen() {
} }
}); });
} }
} }
void DeviceStatus::setProfile(config::Profile&) {
}

View File

@ -30,6 +30,8 @@ namespace logid::features {
void listen() final; void listen() final;
void setProfile(config::Profile& profile) final;
protected: protected:
explicit DeviceStatus(Device* dev); explicit DeviceStatus(Device* dev);

View File

@ -39,16 +39,28 @@ HiresScroll::HiresScroll(Device* dev) :
throw UnsupportedFeature(); throw UnsupportedFeature();
} }
if (_config.has_value()) { _makeConfig();
if (std::holds_alternative<bool>(_config.value())) {
_last_scroll = std::chrono::system_clock::now();
_ipc_interface = dev->ipcNode()->make_interface<IPC>(this);
}
void HiresScroll::_makeConfig() {
auto& config = _config.get();
_mode = 0;
_mask = 0;
if (config.has_value()) {
if (std::holds_alternative<bool>(config.value())) {
config::HiresScroll conf{}; config::HiresScroll conf{};
conf.hires = std::get<bool>(_config.value()); conf.hires = std::get<bool>(config.value());
conf.invert = false; conf.invert = false;
conf.target = false; conf.target = false;
_mask |= hidpp20::HiresScroll::Mode::HiRes; _mask |= hidpp20::HiresScroll::Mode::HiRes;
_config.value() = conf; config.value() = conf;
} }
auto& conf = std::get<config::HiresScroll>(_config.value()); auto& conf = std::get<config::HiresScroll>(config.value());
if (conf.hires.has_value()) { if (conf.hires.has_value()) {
_mask |= hidpp20::HiresScroll::Mode::HiRes; _mask |= hidpp20::HiresScroll::Mode::HiRes;
if (conf.hires.value()) if (conf.hires.value())
@ -68,10 +80,6 @@ HiresScroll::HiresScroll(Device* dev) :
_makeGesture(_up_gesture, conf.up, "up"); _makeGesture(_up_gesture, conf.up, "up");
_makeGesture(_down_gesture, conf.down, "down"); _makeGesture(_down_gesture, conf.down, "down");
} }
_last_scroll = std::chrono::system_clock::now();
_ipc_interface = dev->ipcNode()->make_interface<IPC>(this);
} }
void HiresScroll::configure() { void HiresScroll::configure() {
@ -103,6 +111,15 @@ void HiresScroll::listen() {
} }
} }
void HiresScroll::setProfile(config::Profile& profile) {
std::unique_lock lock(_config_mutex);
_up_gesture.reset();
_down_gesture.reset();
_config = profile.hiresscroll;
_makeConfig();
}
uint8_t HiresScroll::getMode() { uint8_t HiresScroll::getMode() {
return _hires_scroll->getMode(); return _hires_scroll->getMode();
} }
@ -189,15 +206,17 @@ HiresScroll::IPC::IPC(HiresScroll* parent) : ipcgull::interface(
std::tuple<bool, bool, bool> HiresScroll::IPC::getConfig() const { std::tuple<bool, bool, bool> HiresScroll::IPC::getConfig() const {
std::shared_lock lock(_parent._config_mutex); std::shared_lock lock(_parent._config_mutex);
if (_parent._config.has_value()) { auto& config = _parent._config.get();
if (std::holds_alternative<bool>(_parent._config.value())) {
return {std::get<bool>(_parent._config.value()), false, false}; if (config.has_value()) {
if (std::holds_alternative<bool>(config.value())) {
return {std::get<bool>(config.value()), false, false};
} else { } else {
const auto& config = std::get<config::HiresScroll>(_parent._config.value()); const auto& config_obj = std::get<config::HiresScroll>(config.value());
return { return {
config.hires.value_or(true), config_obj.hires.value_or(true),
config.invert.value_or(false), config_obj.invert.value_or(false),
config.target.value_or(false) config_obj.target.value_or(false)
}; };
} }
} else { } else {
@ -206,16 +225,17 @@ std::tuple<bool, bool, bool> HiresScroll::IPC::getConfig() const {
} }
config::HiresScroll& HiresScroll::IPC::_parentConfig() { config::HiresScroll& HiresScroll::IPC::_parentConfig() {
if (!_parent._config.has_value()) { auto& config = _parent._config.get();
_parent._config = config::HiresScroll(); if (!config.has_value()) {
} else if (std::holds_alternative<bool>(_parent._config.value())) { config = config::HiresScroll();
bool hires = std::get<bool>(_parent._config.value()); } else if (std::holds_alternative<bool>(config.value())) {
auto config = config::HiresScroll(); bool hires = std::get<bool>(config.value());
config.hires = hires; auto new_config = config::HiresScroll();
_parent._config = hires; new_config.hires = hires;
config = new_config;
} }
return std::get<config::HiresScroll>(_parent._config.value()); return std::get<config::HiresScroll>(config.value());
} }
void HiresScroll::IPC::setHires(bool hires) { void HiresScroll::IPC::setHires(bool hires) {

View File

@ -34,6 +34,8 @@ namespace logid::features {
void listen() final; void listen() final;
void setProfile(config::Profile& profile) final;
[[nodiscard]] uint8_t getMode(); [[nodiscard]] uint8_t getMode();
void setMode(uint8_t mode); void setMode(uint8_t mode);
@ -42,6 +44,8 @@ namespace logid::features {
explicit HiresScroll(Device* dev); explicit HiresScroll(Device* dev);
private: private:
void _makeConfig();
EventHandlerLock<backend::hidpp::Device> _ev_handler; EventHandlerLock<backend::hidpp::Device> _ev_handler;
void _makeGesture(std::shared_ptr<actions::Gesture>& gesture, void _makeGesture(std::shared_ptr<actions::Gesture>& gesture,
@ -81,7 +85,7 @@ namespace logid::features {
int16_t _last_direction = 0; int16_t _last_direction = 0;
mutable std::shared_mutex _config_mutex; mutable std::shared_mutex _config_mutex;
std::optional<std::variant<bool, config::HiresScroll>>& _config; std::reference_wrapper<std::optional<std::variant<bool, config::HiresScroll>>> _config;
uint8_t _mode; uint8_t _mode;
uint8_t _mask; uint8_t _mask;

View File

@ -46,8 +46,10 @@ RemapButton::RemapButton(Device* dev) : DeviceFeature(dev),
_reprog_controls->initCidMap(); _reprog_controls->initCidMap();
if (!_config.has_value()) auto& config = _config.get();
_config = config::RemapButton();
if (!config.has_value())
config = config::RemapButton();
for (const auto& control: _reprog_controls->getControls()) { for (const auto& control: _reprog_controls->getControls()) {
const auto i = _buttons.size(); const auto i = _buttons.size();
@ -58,8 +60,7 @@ RemapButton::RemapButton(Device* dev) : DeviceFeature(dev),
report.flags = hidpp20_reprog_rebind; report.flags = hidpp20_reprog_rebind;
if (action) { if (action) {
if ((action->reprogFlags() & if ((action->reprogFlags() & hidpp20::ReprogControls::RawXYDiverted) &&
hidpp20::ReprogControls::RawXYDiverted) &&
(!_reprog_controls->supportsRawXY() || (!_reprog_controls->supportsRawXY() ||
!(info.additionalFlags & hidpp20::ReprogControls::RawXY))) !(info.additionalFlags & hidpp20::ReprogControls::RawXY)))
logPrintf(WARN, "%s: Cannot divert raw XY movements for CID 0x%02x", logPrintf(WARN, "%s: Cannot divert raw XY movements for CID 0x%02x",
@ -72,7 +73,7 @@ RemapButton::RemapButton(Device* dev) : DeviceFeature(dev),
_buttons.emplace(control.second.controlID, _buttons.emplace(control.second.controlID,
Button::make(control.second, (int) i, Button::make(control.second, (int) i,
_device, func, _ipc_node, _device, func, _ipc_node,
_config.value()[control.first])); config.value()[control.first]));
} }
_ipc_interface = _device->ipcNode()->make_interface<IPC>(this); _ipc_interface = _device->ipcNode()->make_interface<IPC>(this);
@ -137,6 +138,18 @@ void RemapButton::listen() {
} }
} }
void RemapButton::setProfile(config::Profile& profile) {
std::lock_guard<std::mutex> lock(_button_lock);
_config = profile.buttons;
if (!_config.get().has_value())
_config.get().emplace();
auto& config = _config.get().value();
for(auto& button : _buttons)
button.second->setProfile(config[button.first]);
}
void RemapButton::_buttonEvent(const std::set<uint16_t>& new_state) { void RemapButton::_buttonEvent(const std::set<uint16_t>& new_state) {
// Ensure I/O doesn't occur while updating button state // Ensure I/O doesn't occur while updating button state
std::lock_guard<std::mutex> lock(_button_lock); std::lock_guard<std::mutex> lock(_button_lock);
@ -191,48 +204,59 @@ Button::Button(Info info, int index,
_device(device), _conf_func(std::move(conf_func)), _device(device), _conf_func(std::move(conf_func)),
_config(config), _config(config),
_info(info) { _info(info) {
if (_config.action.has_value()) { _makeConfig();
try {
_action = Action::makeAction(_device, _config.action.value(), _node);
} catch (std::exception& e) {
logPrintf(WARN, "Error creating button action: %s",
e.what());
}
}
_ipc_interface = _node->make_interface<IPC>(this, _info); _ipc_interface = _node->make_interface<IPC>(this, _info);
} }
void Button::_makeConfig() {
auto& config = _config.get();
if (config.action.has_value()) {
try {
_action = Action::makeAction(_device, config.action.value(), _node);
} catch (std::exception& e) {
logPrintf(WARN, "Error creating button action: %s", e.what());
}
}
}
void Button::press() const { void Button::press() const {
std::lock_guard<std::mutex> lock(_action_lock); std::shared_lock lock(_action_lock);
if (_action) if (_action)
_action->press(); _action->press();
} }
void Button::release() const { void Button::release() const {
std::lock_guard<std::mutex> lock(_action_lock); std::shared_lock lock(_action_lock);
if (_action) if (_action)
_action->release(); _action->release();
} }
void Button::move(int16_t x, int16_t y) const { void Button::move(int16_t x, int16_t y) const {
std::lock_guard<std::mutex> lock(_action_lock); std::shared_lock lock(_action_lock);
if (_action) if (_action)
_action->move(x, y); _action->move(x, y);
} }
bool Button::pressed() const { bool Button::pressed() const {
std::lock_guard<std::mutex> lock(_action_lock); std::shared_lock lock(_action_lock);
if (_action) if (_action)
return _action->pressed(); return _action->pressed();
return false; return false;
} }
void Button::configure() const { void Button::configure() const {
std::lock_guard<std::mutex> lock(_action_lock); std::shared_lock lock(_action_lock);
_conf_func(_action); _conf_func(_action);
} }
void Button::setProfile(config::Button& config) {
std::unique_lock lock(_action_lock);
_config = config;
_action.reset();
_makeConfig();
}
std::shared_ptr<ipcgull::node> Button::node() const { std::shared_ptr<ipcgull::node> Button::node() const {
return _node; return _node;
} }
@ -265,11 +289,11 @@ void Button::IPC::setAction(const std::string& type) {
throw std::invalid_argument("No gesture support"); throw std::invalid_argument("No gesture support");
{ {
std::lock_guard<std::mutex> lock(_button._action_lock); std::unique_lock lock(_button._action_lock);
_button._action.reset(); _button._action.reset();
_button._action = Action::makeAction( _button._action = Action::makeAction(
_button._device, type, _button._device, type,
_button._config.action, _button._node); _button._config.get().action, _button._node);
} }
_button.configure(); _button.configure();
} }

View File

@ -42,6 +42,8 @@ namespace logid::features {
void move(int16_t x, int16_t y) const; void move(int16_t x, int16_t y) const;
void setProfile(config::Button& config);
[[nodiscard]] std::shared_ptr<ipcgull::node> node() const; [[nodiscard]] std::shared_ptr<ipcgull::node> node() const;
void configure() const; void configure() const;
@ -51,6 +53,8 @@ namespace logid::features {
private: private:
friend class ButtonWrapper; friend class ButtonWrapper;
void _makeConfig();
Button(Info info, int index, Button(Info info, int index,
Device* device, ConfigFunction conf_func, Device* device, ConfigFunction conf_func,
const std::shared_ptr<ipcgull::node>& root, const std::shared_ptr<ipcgull::node>& root,
@ -72,9 +76,9 @@ namespace logid::features {
Device* _device; Device* _device;
const ConfigFunction _conf_func; const ConfigFunction _conf_func;
config::Button& _config; std::reference_wrapper<config::Button> _config;
mutable std::mutex _action_lock; mutable std::shared_mutex _action_lock;
std::shared_ptr<actions::Action> _action; std::shared_ptr<actions::Action> _action;
const Info _info; const Info _info;
@ -89,6 +93,8 @@ namespace logid::features {
void listen() final; void listen() final;
void setProfile(config::Profile& profile) final;
protected: protected:
explicit RemapButton(Device* dev); explicit RemapButton(Device* dev);
@ -99,7 +105,7 @@ namespace logid::features {
std::set<uint16_t> _pressed_buttons; std::set<uint16_t> _pressed_buttons;
std::mutex _button_lock; std::mutex _button_lock;
std::optional<config::RemapButton>& _config; std::reference_wrapper<std::optional<config::RemapButton>> _config;
std::map<uint16_t, std::shared_ptr<Button>> _buttons; std::map<uint16_t, std::shared_ptr<Button>> _buttons;
std::shared_ptr<ipcgull::node> _ipc_node; std::shared_ptr<ipcgull::node> _ipc_node;

View File

@ -34,8 +34,10 @@ SmartShift::SmartShift(Device* device) : DeviceFeature(device),
} }
void SmartShift::configure() { void SmartShift::configure() {
if (_config.has_value()) { std::shared_lock lock(_config_mutex);
const auto& conf = _config.value(); auto& config = _config.get();
if (config.has_value()) {
const auto& conf = config.value();
Status settings{}; Status settings{};
settings.setActive = conf.on.has_value(); settings.setActive = conf.on.has_value();
if (settings.setActive) if (settings.setActive)
@ -51,6 +53,11 @@ void SmartShift::configure() {
void SmartShift::listen() { void SmartShift::listen() {
} }
void SmartShift::setProfile(config::Profile& profile) {
std::unique_lock lock(_config_mutex);
_config = profile.smartshift;
}
SmartShift::Status SmartShift::getStatus() const { SmartShift::Status SmartShift::getStatus() const {
return _smartshift->getStatus(); return _smartshift->getStatus();
} }
@ -94,39 +101,51 @@ void SmartShift::IPC::setThreshold(uint8_t threshold) {
} }
std::tuple<bool, bool, bool, uint8_t> SmartShift::IPC::getDefault() const { std::tuple<bool, bool, bool, uint8_t> SmartShift::IPC::getDefault() const {
if (!_parent._config.has_value()) std::shared_lock lock(_parent._config_mutex);
auto& config = _parent._config.get();
if (!config.has_value())
return {false, false, false, 0}; return {false, false, false, 0};
std::tuple<bool, bool, bool, uint8_t> ret; std::tuple<bool, bool, bool, uint8_t> ret;
std::get<0>(ret) = _parent._config.value().on.has_value(); std::get<0>(ret) = config.value().on.has_value();
if (std::get<0>(ret)) if (std::get<0>(ret))
std::get<1>(ret) = _parent._config.value().on.value(); std::get<1>(ret) = config.value().on.value();
std::get<2>(ret) = _parent._config.value().threshold.has_value(); std::get<2>(ret) = config.value().threshold.has_value();
if (std::get<2>(ret)) if (std::get<2>(ret))
std::get<3>(ret) = _parent._config.value().threshold.value(); std::get<3>(ret) = config.value().threshold.value();
return ret; return ret;
} }
void SmartShift::IPC::clearDefaultActive() { void SmartShift::IPC::clearDefaultActive() {
if (_parent._config.has_value()) std::unique_lock lock(_parent._config_mutex);
_parent._config.value().on.reset(); auto& config = _parent._config.get();
if (config.has_value())
config.value().on.reset();
} }
void SmartShift::IPC::setDefaultActive(bool active) { void SmartShift::IPC::setDefaultActive(bool active) {
if (!_parent._config.has_value()) std::unique_lock lock(_parent._config_mutex);
_parent._config = config::SmartShift{}; auto& config = _parent._config.get();
_parent._config.value().on = active; if (!config.has_value())
config = config::SmartShift{};
config.value().on = active;
} }
void SmartShift::IPC::clearDefaultThreshold() { void SmartShift::IPC::clearDefaultThreshold() {
if (_parent._config.has_value()) std::unique_lock lock(_parent._config_mutex);
_parent._config.value().threshold.reset(); auto& config = _parent._config.get();
if (config.has_value())
config.value().threshold.reset();
} }
void SmartShift::IPC::setDefaultThreshold(uint8_t threshold) { void SmartShift::IPC::setDefaultThreshold(uint8_t threshold) {
if (!_parent._config.has_value()) std::unique_lock lock(_parent._config_mutex);
_parent._config = config::SmartShift{}; auto& config = _parent._config.get();
_parent._config.value().threshold = threshold; if (!config.has_value())
config = config::SmartShift{};
config.value().threshold = threshold;
} }

View File

@ -22,6 +22,7 @@
#include <backend/hidpp20/features/SmartShift.h> #include <backend/hidpp20/features/SmartShift.h>
#include <ipcgull/interface.h> #include <ipcgull/interface.h>
#include <config/schema.h> #include <config/schema.h>
#include <shared_mutex>
namespace logid::features { namespace logid::features {
class SmartShift : public DeviceFeature { class SmartShift : public DeviceFeature {
@ -31,6 +32,8 @@ namespace logid::features {
void listen() final; void listen() final;
void setProfile(config::Profile& profile) final;
typedef backend::hidpp20::SmartShift::SmartshiftStatus Status; typedef backend::hidpp20::SmartShift::SmartshiftStatus Status;
[[nodiscard]] Status getStatus() const; [[nodiscard]] Status getStatus() const;
@ -41,7 +44,8 @@ namespace logid::features {
explicit SmartShift(Device* dev); explicit SmartShift(Device* dev);
private: private:
std::optional<config::SmartShift>& _config; mutable std::shared_mutex _config_mutex;
std::reference_wrapper<std::optional<config::SmartShift>> _config;
std::shared_ptr<backend::hidpp20::SmartShift> _smartshift; std::shared_ptr<backend::hidpp20::SmartShift> _smartshift;
class IPC : public ipcgull::interface { class IPC : public ipcgull::interface {

View File

@ -80,14 +80,7 @@ ThumbWheel::ThumbWheel(Device* dev) : DeviceFeature(dev), _wheel_info(),
throw UnsupportedFeature(); throw UnsupportedFeature();
} }
if (_config.has_value()) { _makeConfig();
auto& conf = _config.value();
_left_gesture = _genGesture(dev, conf.left, _left_node, "left");
_right_gesture = _genGesture(dev, conf.right, _right_node, "right");
_touch_action = _genAction(dev, conf.touch, _touch_node);
_tap_action = _genAction(dev, conf.tap, _tap_node);
_proxy_action = _genAction(dev, conf.proxy, _proxy_node);
}
_wheel_info = _thumb_wheel->getInfo(); _wheel_info = _thumb_wheel->getInfo();
@ -109,12 +102,24 @@ ThumbWheel::ThumbWheel(Device* dev) : DeviceFeature(dev), _wheel_info(),
_ipc_interface = dev->ipcNode()->make_interface<IPC>(this); _ipc_interface = dev->ipcNode()->make_interface<IPC>(this);
} }
void ThumbWheel::_makeConfig() {
if (_config.get().has_value()) {
auto& conf = _config.get().value();
_left_gesture = _genGesture(_device, conf.left, _left_node, "left");
_right_gesture = _genGesture(_device, conf.right, _right_node, "right");
_touch_action = _genAction(_device, conf.touch, _touch_node);
_tap_action = _genAction(_device, conf.tap, _tap_node);
_proxy_action = _genAction(_device, conf.proxy, _proxy_node);
}
}
void ThumbWheel::configure() { void ThumbWheel::configure() {
std::shared_lock lock(_config_mutex); std::shared_lock lock(_config_mutex);
if (_config.has_value()) { auto& config = _config.get();
const auto& config = _config.value(); if (config.has_value()) {
_thumb_wheel->setStatus(config.divert.value_or(false), const auto& value = config.value();
config.invert.value_or(false)); _thumb_wheel->setStatus(value.divert.value_or(false),
value.invert.value_or(false));
} }
} }
@ -123,10 +128,8 @@ void ThumbWheel::listen() {
_ev_handler = _device->hidpp20().addEventHandler( _ev_handler = _device->hidpp20().addEventHandler(
{[index = _thumb_wheel->featureIndex()] {[index = _thumb_wheel->featureIndex()]
(const hidpp::Report& report) -> bool { (const hidpp::Report& report) -> bool {
return (report.feature() == return (report.feature() == index) &&
index) && (report.function() == hidpp20::ThumbWheel::Event);
(report.function() ==
hidpp20::ThumbWheel::Event);
}, },
[self_weak = self<ThumbWheel>()](const hidpp::Report& report) -> void { [self_weak = self<ThumbWheel>()](const hidpp::Report& report) -> void {
if (auto self = self_weak.lock()) if (auto self = self_weak.lock())
@ -136,6 +139,17 @@ void ThumbWheel::listen() {
} }
} }
void ThumbWheel::setProfile(config::Profile& profile) {
std::unique_lock lock(_config_mutex);
_config = profile.thumbwheel;
_left_gesture.reset();
_right_gesture.reset();
_touch_action.reset();
_tap_action.reset();
_proxy_action.reset();
_makeConfig();
}
void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) { void ThumbWheel::_handleEvent(hidpp20::ThumbWheel::ThumbwheelEvent event) {
std::shared_lock lock(_config_mutex); std::shared_lock lock(_config_mutex);
if (event.flags & hidpp20::ThumbWheel::SingleTap) { if (event.flags & hidpp20::ThumbWheel::SingleTap) {
@ -227,22 +241,24 @@ ThumbWheel::IPC::IPC(ThumbWheel* parent) : ipcgull::interface(
} }
config::ThumbWheel& ThumbWheel::IPC::_parentConfig() { config::ThumbWheel& ThumbWheel::IPC::_parentConfig() {
if (!_parent._config.has_value()) { auto& config = _parent._config.get();
_parent._config.emplace(); if (!config.has_value()) {
config.emplace();
} }
return _parent._config.value(); return config.value();
} }
std::tuple<bool, bool> ThumbWheel::IPC::getConfig() const { std::tuple<bool, bool> ThumbWheel::IPC::getConfig() const {
std::shared_lock lock(_parent._config_mutex); std::shared_lock lock(_parent._config_mutex);
if (!_parent._config.has_value()) { auto& config = _parent._config.get();
if (!config.has_value()) {
return {false, false}; return {false, false};
} }
return {_parent._config.value().divert.value_or(false), return {config.value().divert.value_or(false),
_parent._config.value().invert.value_or(false)}; config.value().invert.value_or(false)};
} }
void ThumbWheel::IPC::setDivert(bool divert) { void ThumbWheel::IPC::setDivert(bool divert) {

View File

@ -32,7 +32,11 @@ namespace logid::features {
void listen() final; void listen() final;
void setProfile(config::Profile& profile) final;
private: private:
void _makeConfig();
void _handleEvent(backend::hidpp20::ThumbWheel::ThumbwheelEvent event); void _handleEvent(backend::hidpp20::ThumbWheel::ThumbwheelEvent event);
void _fixGesture(const std::shared_ptr<actions::Gesture>& gesture) const; void _fixGesture(const std::shared_ptr<actions::Gesture>& gesture) const;
@ -59,6 +63,7 @@ namespace logid::features {
private: private:
config::ThumbWheel& _parentConfig(); config::ThumbWheel& _parentConfig();
ThumbWheel& _parent; ThumbWheel& _parent;
}; };
@ -82,7 +87,7 @@ namespace logid::features {
bool _last_touch = false; bool _last_touch = false;
mutable std::shared_mutex _config_mutex; mutable std::shared_mutex _config_mutex;
std::optional<config::ThumbWheel>& _config; std::reference_wrapper<std::optional<config::ThumbWheel>> _config;
EventHandlerLock<backend::hidpp::Device> _ev_handler; EventHandlerLock<backend::hidpp::Device> _ev_handler;