From 0b515feb1765e098cf7e2f4b971d0298f9b68a3d Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 29 Apr 2023 14:59:00 -0400 Subject: [PATCH] Add HiresScroll IPC support --- src/logid/features/HiresScroll.cpp | 233 +++++++++++++++++++++++------ src/logid/features/HiresScroll.h | 40 ++++- src/logid/features/ThumbWheel.cpp | 26 ++-- src/logid/features/ThumbWheel.h | 2 +- 4 files changed, 234 insertions(+), 67 deletions(-) diff --git a/src/logid/features/HiresScroll.cpp b/src/logid/features/HiresScroll.cpp index a8d2bc4..e5fc4bb 100644 --- a/src/logid/features/HiresScroll.cpp +++ b/src/logid/features/HiresScroll.cpp @@ -19,14 +19,19 @@ #include #include #include +#include "ipc_defs.h" +using namespace logid; using namespace logid::features; using namespace logid::backend; -HiresScroll::HiresScroll(Device* dev) : DeviceFeature(dev), - _config(dev->activeProfile().hiresscroll), _mode(0), - _mask(0), - _node(dev->ipcNode()->make_child("hires")) { +HiresScroll::HiresScroll(Device* dev) : + DeviceFeature(dev), + _config(dev->activeProfile().hiresscroll), _mode(0), + _mask(0), + _node(dev->ipcNode()->make_child("hires_scroll")), + _up_node(_node->make_child("up")), + _down_node(_node->make_child("down")) { if (_config.has_value()) { if (std::holds_alternative(_config.value())) { config::HiresScroll conf{}; @@ -53,8 +58,8 @@ HiresScroll::HiresScroll(Device* dev) : DeviceFeature(dev), _mode |= hidpp20::HiresScroll::Mode::Target; } - _makeAction(_up_action, conf.up, "up"); - _makeAction(_down_action, conf.down, "down"); + _makeGesture(_up_gesture, conf.up, "up"); + _makeGesture(_down_gesture, conf.down, "down"); } try { @@ -64,6 +69,8 @@ HiresScroll::HiresScroll(Device* dev) : DeviceFeature(dev), } _last_scroll = std::chrono::system_clock::now(); + + _ipc_interface = _node->make_interface(this); } HiresScroll::~HiresScroll() noexcept { @@ -72,6 +79,11 @@ HiresScroll::~HiresScroll() noexcept { } void HiresScroll::configure() { + std::shared_lock lock(_config_mutex); + _configure(); +} + +void HiresScroll::_configure() { auto mode = _hires_scroll->getMode(); mode &= ~_mask; mode |= (_mode & _mask); @@ -79,21 +91,19 @@ void HiresScroll::configure() { } void HiresScroll::listen() { + std::shared_lock lock(_config_mutex); if (!_ev_handler.has_value()) { - _ev_handler = _device->hidpp20().addEventHandler({ - [index = _hires_scroll->featureIndex()]( - const hidpp::Report& report) -> bool { - return (report.feature() == - index) && - (report.function() == - hidpp20::HiresScroll::WheelMovement); - }, - [this](const hidpp::Report& report) { - _handleScroll( - _hires_scroll->wheelMovementEvent( - report)); - } - }); + _ev_handler = _device->hidpp20().addEventHandler( + { + [index = _hires_scroll->featureIndex()]( + const hidpp::Report& report) -> bool { + return (report.feature() == index) && + (report.function() == hidpp20::HiresScroll::WheelMovement); + }, + [this](const hidpp::Report& report) { + _handleScroll(_hires_scroll->wheelMovementEvent(report)); + } + }); } } @@ -105,35 +115,40 @@ void HiresScroll::setMode(uint8_t mode) { _hires_scroll->setMode(mode); } -void HiresScroll::_makeAction(std::shared_ptr& gesture, - std::optional& config, - const std::string& direction) { +void HiresScroll::_makeGesture(std::shared_ptr& gesture, + std::optional& config, + const std::string& direction) { if (config.has_value()) { gesture = actions::Gesture::makeGesture(_device, config.value(), _node->make_child(direction)); - 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); + + _fixGesture(gesture); } else { gesture.reset(); } } +void HiresScroll::_fixGesture(const std::shared_ptr& gesture) { + 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); +} + void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) { + std::shared_lock lock(_config_mutex); auto now = std::chrono::system_clock::now(); - if (std::chrono::duration_cast( - now - _last_scroll).count() >= 1) { - if (_up_action) { - _up_action->release(false); - _up_action->press(true); + if (std::chrono::duration_cast(now - _last_scroll).count() >= 1) { + if (_up_gesture) { + _up_gesture->release(false); + _up_gesture->press(true); } - if (_down_action) { - _down_action->release(false); - _down_action->press(true); + if (_down_gesture) { + _down_gesture->release(false); + _down_gesture->press(true); } _last_direction = 0; @@ -141,25 +156,147 @@ void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) { if (event.deltaV > 0) { if (_last_direction == -1) { - if (_down_action) { - _down_action->release(false); - _down_action->press(true); + if (_down_gesture) { + _down_gesture->release(false); + _down_gesture->press(true); } } - if (_up_action) - _up_action->move(event.deltaV); + if (_up_gesture) + _up_gesture->move(event.deltaV); _last_direction = 1; } else if (event.deltaV < 0) { if (_last_direction == 1) { - if (_up_action) { - _up_action->release(false); - _up_action->press(true); + if (_up_gesture) { + _up_gesture->release(false); + _up_gesture->press(true); } } - if (_down_action) - _down_action->move((int16_t) -event.deltaV); + if (_down_gesture) + _down_gesture->move((int16_t) -event.deltaV); _last_direction = -1; } _last_scroll = now; } + +HiresScroll::IPC::IPC(HiresScroll* parent) : ipcgull::interface( + SERVICE_ROOT_NAME ".HiresScroll", { + {"GetConfig", {this, &IPC::getConfig, {"hires", "invert", "target"}}}, + {"SetHires", {this, &IPC::setHires, {"hires"}}}, + {"SetInvert", {this, &IPC::setInvert, {"invert"}}}, + {"SetTarget", {this, &IPC::setTarget, {"target"}}}, + {"SetUp", {this, &IPC::setUp, {"type"}}}, + {"SetDown", {this, &IPC::setDown, {"type"}}}, + }, {}, {}), _parent(*parent) { +} + +std::tuple HiresScroll::IPC::getConfig() const { + std::shared_lock lock(_parent._config_mutex); + + if (_parent._config.has_value()) { + if (std::holds_alternative(_parent._config.value())) { + return {std::get(_parent._config.value()), false, false}; + } else { + const auto& config = std::get(_parent._config.value()); + return { + config.hires.value_or(true), + config.invert.value_or(false), + config.target.value_or(false) + }; + } + } else { + return {true, false, false}; + } +} + +config::HiresScroll& HiresScroll::IPC::_parentConfig() { + if (!_parent._config.has_value()) { + _parent._config = config::HiresScroll(); + } else if (std::holds_alternative(_parent._config.value())) { + bool hires = std::get(_parent._config.value()); + auto config = config::HiresScroll(); + config.hires = hires; + _parent._config = hires; + } + + return std::get(_parent._config.value()); +} + +void HiresScroll::IPC::setHires(bool hires) { + std::unique_lock lock(_parent._config_mutex); + _parentConfig().hires = hires; + + _parent._mask |= hidpp20::HiresScroll::Mode::HiRes; + if (hires) + _parent._mode |= hidpp20::HiresScroll::Mode::HiRes; + else + _parent._mode &= ~hidpp20::HiresScroll::Mode::HiRes; + + _parent._configure(); +} + +void HiresScroll::IPC::setInvert(bool invert) { + std::unique_lock lock(_parent._config_mutex); + _parentConfig().invert = invert; + + _parent._mask |= hidpp20::HiresScroll::Mode::Inverted; + if (invert) + _parent._mode |= hidpp20::HiresScroll::Mode::Inverted; + else + _parent._mode &= ~hidpp20::HiresScroll::Mode::Inverted; + + _parent._configure(); +} + +void HiresScroll::IPC::setTarget(bool target) { + std::unique_lock lock(_parent._config_mutex); + _parentConfig().target = target; + + _parent._mask |= hidpp20::HiresScroll::Mode::Target; + if (target) + _parent._mode |= hidpp20::HiresScroll::Mode::Target; + else + _parent._mode &= ~hidpp20::HiresScroll::Mode::Target; + + _parent._configure(); +} + +void HiresScroll::IPC::setUp(const std::string& type) { + std::unique_lock lock(_parent._config_mutex); + + auto& config = _parentConfig(); + + if (!config.up.has_value()) { + config.up = config::NoGesture(); + } + _parent._up_gesture = actions::Gesture::makeGesture( + _parent._device, type, config.up.value(), _parent._up_node); + if (!_parent._up_gesture->wheelCompatibility()) { + _parent._up_node.reset(); + config.up.reset(); + + throw std::invalid_argument("incompatible gesture"); + } else { + _parent._fixGesture(_parent._up_gesture); + } +} + +void HiresScroll::IPC::setDown(const std::string& type) { + std::unique_lock lock(_parent._config_mutex); + + auto& config = _parentConfig(); + + if (!config.down.has_value()) { + config.down = config::NoGesture(); + } + _parent._down_gesture = actions::Gesture::makeGesture( + _parent._device, type, config.down.value(), _parent._down_node); + if (!_parent._down_gesture->wheelCompatibility()) { + _parent._down_node.reset(); + config.down.reset(); + + throw std::invalid_argument("incompatible gesture"); + } else { + _parent._fixGesture(_parent._down_gesture); + } +} diff --git a/src/logid/features/HiresScroll.h b/src/logid/features/HiresScroll.h index 982666b..b987d95 100644 --- a/src/logid/features/HiresScroll.h +++ b/src/logid/features/HiresScroll.h @@ -45,25 +45,55 @@ namespace logid::features { private: std::optional _ev_handler; - void _makeAction(std::shared_ptr& gesture, - std::optional& config, - const std::string& direction); + void _makeGesture(std::shared_ptr& gesture, + std::optional& config, + const std::string& direction); + + void _configure(); + + void _fixGesture(const std::shared_ptr& gesture); void _handleScroll(backend::hidpp20::HiresScroll::WheelStatus event); + class IPC : public ipcgull::interface { + public: + explicit IPC(HiresScroll* parent); + + [[nodiscard]] std::tuple getConfig() const; + + void setHires(bool hires); + + void setInvert(bool invert); + + void setTarget(bool target); + + void setUp(const std::string& type); + + void setDown(const std::string& type); + + private: + config::HiresScroll& _parentConfig(); + HiresScroll& _parent; + }; + std::shared_ptr _hires_scroll; std::chrono::time_point _last_scroll; int16_t _last_direction = 0; + mutable std::shared_mutex _config_mutex; std::optional>& _config; uint8_t _mode; uint8_t _mask; - std::shared_ptr _up_action; - std::shared_ptr _down_action; + std::shared_ptr _up_gesture; + std::shared_ptr _down_gesture; std::shared_ptr _node; + std::shared_ptr _up_node; + std::shared_ptr _down_node; + + std::shared_ptr _ipc_interface; }; } diff --git a/src/logid/features/ThumbWheel.cpp b/src/logid/features/ThumbWheel.cpp index 9de1aa0..69030df 100644 --- a/src/logid/features/ThumbWheel.cpp +++ b/src/logid/features/ThumbWheel.cpp @@ -218,21 +218,21 @@ void ThumbWheel::_fixGesture(const std::shared_ptr& gesture) c axis->setHiresMultiplier(_wheel_info.divertedRes); } catch (std::bad_cast& e) {} - gesture->press(true); + if (gesture) + gesture->press(true); } -ThumbWheel::IPC::IPC(ThumbWheel* parent) : - ipcgull::interface( - SERVICE_ROOT_NAME ".ThumbWheel", { - {"GetConfig", {this, &IPC::getConfig, {"divert", "invert"}}}, - {"SetDivert", {this, &IPC::setDivert, {"divert"}}}, - {"SetInvert", {this, &IPC::setInvert, {"invert"}}}, - {"SetLeft", {this, &IPC::setLeft, {"type"}}}, - {"SetRight", {this, &IPC::setRight, {"type"}}}, - {"SetProxy", {this, &IPC::setProxy, {"type"}}}, - {"SetTap", {this, &IPC::setTap, {"type"}}}, - {"SetTouch", {this, &IPC::setTouch, {"type"}}}, - }, {}, {}), _parent(*parent) { +ThumbWheel::IPC::IPC(ThumbWheel* parent) : ipcgull::interface( + SERVICE_ROOT_NAME ".ThumbWheel", { + {"GetConfig", {this, &IPC::getConfig, {"divert", "invert"}}}, + {"SetDivert", {this, &IPC::setDivert, {"divert"}}}, + {"SetInvert", {this, &IPC::setInvert, {"invert"}}}, + {"SetLeft", {this, &IPC::setLeft, {"type"}}}, + {"SetRight", {this, &IPC::setRight, {"type"}}}, + {"SetProxy", {this, &IPC::setProxy, {"type"}}}, + {"SetTap", {this, &IPC::setTap, {"type"}}}, + {"SetTouch", {this, &IPC::setTouch, {"type"}}}, + }, {}, {}), _parent(*parent) { } config::ThumbWheel& ThumbWheel::IPC::_parentConfig() { diff --git a/src/logid/features/ThumbWheel.h b/src/logid/features/ThumbWheel.h index 472ee56..4a448a3 100644 --- a/src/logid/features/ThumbWheel.h +++ b/src/logid/features/ThumbWheel.h @@ -85,7 +85,7 @@ namespace logid::features { int8_t _last_direction = 0; bool _last_proxy = false; bool _last_touch = false; - std::shared_mutex _config_mutex; + mutable std::shared_mutex _config_mutex; std::optional& _config; std::optional _ev_handler;