diff --git a/src/logid/actions/Action.h b/src/logid/actions/Action.h index f00979b..0ce327f 100644 --- a/src/logid/actions/Action.h +++ b/src/logid/actions/Action.h @@ -71,6 +71,11 @@ namespace logid::actions { virtual void move([[maybe_unused]] int16_t x, [[maybe_unused]] int16_t y) { } + virtual void scroll(int16_t s) { + // Suppress unused warning + (void)s; + }; + virtual bool pressed() { return _pressed; } diff --git a/src/logid/actions/GestureAction.cpp b/src/logid/actions/GestureAction.cpp index 8afceb6..c0a0114 100644 --- a/src/logid/actions/GestureAction.cpp +++ b/src/logid/actions/GestureAction.cpp @@ -37,6 +37,10 @@ GestureAction::Direction GestureAction::toDirection(std::string direction) { return Left; else if (direction == "right") return Right; + else if(direction == "scrollup") + return ScrollUp; + else if(direction == "scrolldown") + return ScrollDown; else if (direction == "none") return None; else @@ -53,6 +57,10 @@ std::string GestureAction::fromDirection(Direction direction) { return "left"; case Right: return "right"; + case ScrollUp: + return "scrollup"; + case ScrollDown: + return "scrolldown"; case None: return "none"; } @@ -61,15 +69,15 @@ std::string GestureAction::fromDirection(Direction direction) { throw InvalidGesture(); } -GestureAction::Direction GestureAction::toDirection(int32_t x, int32_t y) { - if (x >= 0 && y >= 0) - return x >= y ? Right : Down; - else if (x < 0 && y >= 0) - return -x <= y ? Down : Left; - else if (x <= 0 /* && y < 0 */) - return x <= y ? Left : Up; +GestureAction::Direction GestureAction::toDirection(int32_t x, int32_t y, int16_t s) { + if(isScroll()) + return s > 0 ? ScrollUp : ScrollDown; + else if(isVertical()) + return y < 0 ? Up : Down; + else if(isHorizontal()) + return x < 0 ? Left : Right; else - return x <= -y ? Up : Right; + return None; } GestureAction::GestureAction(Device* dev, config::GestureAction& config, @@ -118,40 +126,50 @@ void GestureAction::release() { std::shared_lock lock(_config_mutex); _pressed = false; - bool threshold_met = false; - - auto d = toDirection(_x, _y); - auto primary_gesture = _gestures.find(d); - if (primary_gesture != _gestures.end()) { - threshold_met = primary_gesture->second->metThreshold(); - primary_gesture->second->release(true); - } + Direction d = toDirection(_x, _y, _s); for (auto& gesture: _gestures) { - if (gesture.first == d || gesture.first == None) - continue; - if (!threshold_met) { - if (gesture.second->metThreshold()) { - // If the primary gesture did not meet its threshold, use the - // secondary one. - threshold_met = true; - gesture.second->release(true); - } - } else { - gesture.second->release(false); - } + gesture.second->release(gesture.first == d); } auto none_gesture = _gestures.find(None); - if (none_gesture != _gestures.end()) { - none_gesture->second->release(!threshold_met); + if (d == None && none_gesture != _gestures.end()) { + none_gesture->second->release(none_gesture->first == d); } } -void GestureAction::move(int16_t x, int16_t y) { + +bool GestureAction::isScroll() +{ + auto scrollUp = _gestures.find(ScrollUp); + bool isScrollUp = scrollUp == _gestures.end() ? false : scrollUp->second->metThreshold(); + auto scrollDown = _gestures.find(ScrollDown); + bool isScrollDown = scrollDown == _gestures.end() ? false : scrollDown->second->metThreshold(); + return isScrollUp || isScrollDown; +} + +bool GestureAction::isVertical() +{ + auto up = _gestures.find(Up); + bool isUp = up == _gestures.end() ? false : up->second->metThreshold(); + auto down = _gestures.find(Down); + bool isDown = down == _gestures.end() ? false : down->second->metThreshold(); + return isUp || isDown; +} + +bool GestureAction::isHorizontal() +{ + auto left = _gestures.find(Left); + bool isLeft = left == _gestures.end() ? false : left->second->metThreshold(); + auto right = _gestures.find(Right); + bool isRight = right == _gestures.end() ? false : right->second->metThreshold(); + return isLeft || isRight; +} + +void GestureAction::move3D(int16_t x, int16_t y, int16_t s) { std::shared_lock lock(_config_mutex); - int32_t new_x = _x + x, new_y = _y + y; + int32_t new_x = _x + x, new_y = _y + y, new_s = _s + s; if (abs(x) > 0) { if (_x < 0 && new_x >= 0) { // Left -> Origin/Right @@ -213,8 +231,39 @@ void GestureAction::move(int16_t x, int16_t y) { } } + if (abs(s) > 0) { + if(_s > 0 && new_s <= 0) { // ScrollDown -> Origin/ScrollUp + auto down = _gestures.find(ScrollDown); + if(down != _gestures.end()) + down->second->move(_s); + if(new_s) { // Ignore to origin + auto up = _gestures.find(ScrollUp); + if(up != _gestures.end()) + up->second->move(new_s); + } + } else if(_s < 0 && new_s >= 0) { // ScrollUp -> Origin/ScrollDown + auto up = _gestures.find(ScrollUp); + if(up != _gestures.end()) + up->second->move(-_s); + if(new_s) { // Ignore to origin + auto down = _gestures.find(ScrollDown); + if(down != _gestures.end()) + down->second->move(-new_s); + } + } else if(new_s < 0) { // Origin/ScrollDown to ScrollDown + auto down = _gestures.find(ScrollDown); + if(down != _gestures.end()) + down->second->move(-s); + } else if(new_s > 0) {// Origin/ScrollUp to ScrollUp + auto up = _gestures.find(ScrollUp); + if(up != _gestures.end()) + up->second->move(s); + } + } + _x = new_x; _y = new_y; + _s = new_s; } uint8_t GestureAction::reprogFlags() const { @@ -231,7 +280,7 @@ void GestureAction::setGesture(const std::string& direction, const std::string& if (it != _gestures.end()) { if (pressed()) { - auto current = toDirection(_x, _y); + auto current = toDirection(_x, _y, _s); if (it->second) it->second->release(current == d); } diff --git a/src/logid/actions/GestureAction.h b/src/logid/actions/GestureAction.h index 7ef8f3a..ea572ed 100644 --- a/src/logid/actions/GestureAction.h +++ b/src/logid/actions/GestureAction.h @@ -32,14 +32,16 @@ namespace logid::actions { Up, Down, Left, - Right + Right, + ScrollUp, + ScrollDown, }; static Direction toDirection(std::string direction); static std::string fromDirection(Direction direction); - static Direction toDirection(int32_t x, int32_t y); + Direction toDirection(int32_t x, int32_t y, int16_t s); GestureAction(Device* dev, config::GestureAction& config, const std::shared_ptr& parent); @@ -48,7 +50,13 @@ namespace logid::actions { void release() final; - void move(int16_t x, int16_t y) final; + void move(int16_t x, int16_t y) final { + move3D(x, y, 0); + }; + + void scroll(int16_t s) { + move3D(0, 0, s); + }; uint8_t reprogFlags() const final; @@ -56,10 +64,19 @@ namespace logid::actions { const std::string& type); protected: - int32_t _x{}, _y{}; + int32_t _x{}, _y{}, _s{}; std::shared_ptr _node; std::map> _gestures; config::GestureAction& _config; + + bool isScroll(); + + bool isVertical(); + + bool isHorizontal(); + + private: + void move3D(int16_t, int16_t, int16_t); }; } diff --git a/src/logid/features/HiresScroll.cpp b/src/logid/features/HiresScroll.cpp index c1c4587..6764ba1 100644 --- a/src/logid/features/HiresScroll.cpp +++ b/src/logid/features/HiresScroll.cpp @@ -16,6 +16,7 @@ * */ #include +#include #include #include #include @@ -152,6 +153,9 @@ void HiresScroll::_fixGesture(const std::shared_ptr& gesture) } void HiresScroll::_handleScroll(hidpp20::HiresScroll::WheelStatus event) { + auto remapbutton = _device->getFeature("remapbutton"); + if (remapbutton && remapbutton->onHiresScroll(event.deltaV)) return; + std::shared_lock lock(_config_mutex); auto now = std::chrono::system_clock::now(); if (std::chrono::duration_cast(now - _last_scroll).count() >= 1) { diff --git a/src/logid/features/RemapButton.cpp b/src/logid/features/RemapButton.cpp index 0d6dd9a..5efe917 100644 --- a/src/logid/features/RemapButton.cpp +++ b/src/logid/features/RemapButton.cpp @@ -150,6 +150,17 @@ void RemapButton::setProfile(config::Profile& profile) { button.second->setProfile(config[button.first]); } +bool RemapButton::onHiresScroll(int16_t deltaV) +{ + bool handled = false; + for (const auto& button: _buttons) + if (button.second->pressed()) { + button.second->getAction()->scroll(deltaV); + handled = true; + } + return handled; +} + void RemapButton::_buttonEvent(const std::set& new_state) { // Ensure I/O doesn't occur while updating button state std::lock_guard lock(_button_lock); diff --git a/src/logid/features/RemapButton.h b/src/logid/features/RemapButton.h index 2a6bc8e..6533e09 100644 --- a/src/logid/features/RemapButton.h +++ b/src/logid/features/RemapButton.h @@ -50,6 +50,10 @@ namespace logid::features { bool pressed() const; + auto getAction() const { + return _action; + }; + private: friend class ButtonWrapper; @@ -97,6 +101,8 @@ namespace logid::features { void setProfile(config::Profile& profile) final; + bool onHiresScroll(int16_t); + protected: explicit RemapButton(Device* dev);