diff --git a/README.md b/README.md index 4291e8f..e8eef3c 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,9 @@ plugin { # must be >= 3 workspace_swipe_fingers = 3 + # in milliseconds + long_press_delay = 400 + experimental { # send proper cancel events to windows instead of hacky touch_up events, # NOT recommended as it crashed a few times, once it's stabilized I'll make it the default @@ -152,8 +155,7 @@ where (skip to [examples](#examples) if this is confusing): 3. `edge::` - `` is from which edge to start from (l/r/u/d) - `` is in which direction to swipe (l/r/u/d/lu/ld/ru/rd) - -> :warning: `` with misspellings will be silently ignored. + 4. `longpress:` #### Examples @@ -178,6 +180,10 @@ bind = , swipe:3:ld, exec, foot # tap with 3 fingers # NOTE: tap events only trigger for finger count of >= 3 bind = , tap:3, exec, foot + +# longpress can trigger mouse binds: +bindm = , longpress:2, movewindow +bindm = , longpress:3, resizewindow ``` # Acknowledgements diff --git a/scripts/hotreload b/scripts/hotreload new file mode 100755 index 0000000..f03dc3c --- /dev/null +++ b/scripts/hotreload @@ -0,0 +1,50 @@ +#!/bin/sh + +set -e + +TMP=/tmp/hyprgrass-testing +helpText=" + usage: $0 FILE + +Hot reload a hyprland plugin + +Plugins loaded by this script will not be 'cached' (not really but don't worry about it :D). +If a new plugin with the same file name is loaded, the old one is first unloaded. + + example: $(basename $0) ./build/libhyprgrass.so + + Subsequent calls will automatically unload the plugin as needed" + +error () { + echo "$helpText" + exit 1 +} + +if [ -z "$1" ]; then + error +fi + +if ! [ -f "$1" ]; then + echo "'$1' is not a valid file" + echo '' + error +fi + +baseFileName="$(basename "$1")" +fileHash="$(sha256sum "$1" | cut -d ' ' -f 1)" +pluginTempDir="$TMP/$fileHash" +pluginTempFile="$pluginTempDir/$baseFileName" + +for soPath in $TMP/*/$baseFileName; do + if [ -f "$soPath" ]; then + hyprctl plugin unload "$soPath" + rm -r $(dirname "$soPath") + fi +done + +mkdir -p "$pluginTempDir" + +cp "$1" "$pluginTempDir" + +hyprctl plugin load "$pluginTempFile" + diff --git a/src/GestureManager.cpp b/src/GestureManager.cpp index 1f89971..df00756 100644 --- a/src/GestureManager.cpp +++ b/src/GestureManager.cpp @@ -1,4 +1,6 @@ #include "GestureManager.hpp" +#include "hyprland/src/managers/LayoutManager.hpp" +#include "wayfire/touch/touch.hpp" #include #include #include @@ -6,16 +8,35 @@ #include #include #include +#include // constexpr double SWIPE_THRESHOLD = 30.; +bool handleGestureBind(std::string bind, bool pressed); + +int handleLongPressTimer(void* data) { + const auto gesture_manager = (GestureManager*)data; + gesture_manager->onLongPressTimeout(gesture_manager->long_press_next_trigger_time); + + return 0; +} + GestureManager::GestureManager() { static auto* const PSENSITIVITY = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:sensitivity")->floatValue; + static auto* const LONG_PRESS_DELAY = + &HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:long_press_delay")->intValue; + + this->addMultiFingerGesture(PSENSITIVITY, LONG_PRESS_DELAY); + this->addMultiFingerTap(PSENSITIVITY, LONG_PRESS_DELAY); + this->addLongPress(PSENSITIVITY, LONG_PRESS_DELAY); + this->addEdgeSwipeGesture(PSENSITIVITY, LONG_PRESS_DELAY); + + this->long_press_timer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleLongPressTimer, this); +} - this->addMultiFingerGesture(PSENSITIVITY); - this->addMultiFingerTap(PSENSITIVITY); - this->addEdgeSwipeGesture(PSENSITIVITY); +GestureManager::~GestureManager() { + wl_event_source_remove(this->long_press_timer); } void GestureManager::emulateSwipeBegin(uint32_t time) { @@ -60,24 +81,32 @@ void GestureManager::emulateSwipeUpdate(uint32_t time) { m_vGestureLastCenter = currentCenter; } -bool GestureManager::handleGesture(const CompletedGesture& gev) { - if (gev.type == TouchGestureType::SWIPE_HOLD) { - return this->handleWorkspaceSwipe(gev); - } - if (gev.type == TouchGestureType::SWIPE && this->dragGestureIsActive()) { - this->emulateSwipeEnd(0, false); - return true; +bool GestureManager::handleCompletedGesture(const CompletedGesture& gev) { + return handleGestureBind(gev.to_string(), false); +} + +bool GestureManager::handleDragGesture(const DragGesture& gev) { + switch (gev.type) { + case DragGestureType::SWIPE: + return this->handleWorkspaceSwipe(gev); + default: + break; } - const auto bind = gev.to_string(); - bool found = false; + return handleGestureBind(gev.to_string(), true); +} + +// bind is the name of the gesture event. +// pressed only matters for mouse binds: only start of drag gestures should set it to true +bool handleGestureBind(std::string bind, bool pressed) { + bool found = false; Debug::log(LOG, "[hyprgrass] Gesture Triggered: {}", bind); for (const auto& k : g_pKeybindManager->m_lKeybinds) { if (k.key != bind) continue; - const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(k.handler); + const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(k.mouse ? "mouse" : k.handler); // Should never happen, as we check in the ConfigManager, but oh well if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) { @@ -91,28 +120,78 @@ bool GestureManager::handleGesture(const CompletedGesture& gev) { if (k.handler == "pass") continue; - DISPATCHER->second(k.arg); - found = true; + if (k.handler == "mouse") { + DISPATCHER->second((pressed ? "1" : "0") + k.arg); + } else { + DISPATCHER->second(k.arg); + } + + if (!k.nonConsuming) { + found = true; + } } + return found; } void GestureManager::handleCancelledGesture() { - if (!this->dragGestureIsActive()) { + if (!this->getActiveDragGesture().has_value()) { + return; + } + + // FIXME: make it so handleDragGestureEnd is called instead of handling this here + switch (this->getActiveDragGesture()->type) { + case DragGestureType::SWIPE: + this->emulateSwipeEnd(0, false); + return; + case DragGestureType::LONG_PRESS: + break; + } +} + +void GestureManager::dragGestureUpdate(const wf::touch::gesture_event_t& ev) { + if (!this->getActiveDragGesture().has_value()) { + return; + } + + switch (this->getActiveDragGesture()->type) { + case DragGestureType::SWIPE: + emulateSwipeUpdate(ev.time); + return; + case DragGestureType::LONG_PRESS: { + const auto pos = this->m_sGestureState.get_center().current; + wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, pos.x, pos.y); + // HACK: g_pInputManager->onMouseMoveUnified is private so I'm using just this + g_pLayoutManager->getCurrentLayout()->onMouseMove(Vector2D(pos.x, pos.y)); + return; + } + } +} + +void GestureManager::handleDragGestureEnd(const DragGesture& gev) { + if (!this->getActiveDragGesture().has_value()) { return; } - this->emulateSwipeEnd(0, false); + switch (this->getActiveDragGesture()->type) { + case DragGestureType::SWIPE: + emulateSwipeEnd(0, false); + return; + case DragGestureType::LONG_PRESS: + break; + } + + handleGestureBind(gev.to_string(), false); } -bool GestureManager::handleWorkspaceSwipe(const CompletedGesture& gev) { +bool GestureManager::handleWorkspaceSwipe(const DragGesture& gev) { static auto* const PWORKSPACEFINGERS = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers")->intValue; const auto VERTANIMS = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace) ->m_vRenderOffset.getConfig() ->pValues->internalStyle == "slidevert"; - if (gev.type == TouchGestureType::SWIPE_HOLD && gev.finger_count == *PWORKSPACEFINGERS) { + if (gev.type == DragGestureType::SWIPE && gev.finger_count == *PWORKSPACEFINGERS) { const auto horizontal = GESTURE_DIRECTION_LEFT | GESTURE_DIRECTION_RIGHT; const auto vertical = GESTURE_DIRECTION_UP | GESTURE_DIRECTION_DOWN; const auto workspace_directions = VERTANIMS ? vertical : horizontal; @@ -129,6 +208,15 @@ bool GestureManager::handleWorkspaceSwipe(const CompletedGesture& gev) { return false; } +void GestureManager::updateLongPressTimer(uint32_t current_time, uint32_t delay) { + this->long_press_next_trigger_time = current_time + delay + 1; + wl_event_source_timer_update(this->long_press_timer, delay); +} + +void GestureManager::stopLongPressTimer() { + wl_event_source_timer_update(this->long_press_timer, 0); +} + void GestureManager::sendCancelEventsToWindows() { static auto* const SEND_CANCEL = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:experimental:send_cancel")->intValue; @@ -198,8 +286,6 @@ bool GestureManager::onTouchUp(wlr_touch_up_event* ev) { if (g_pCompositor->m_sSeat.exclusiveClient) // lock screen, I think return false; - // NOTE this is neccessary because onTouchDown might fail and exit without - // updating gestures wf::touch::point_t lift_off_pos; try { lift_off_pos = this->m_sGestureState.fingers.at(ev->touch_id).current; @@ -227,10 +313,6 @@ bool GestureManager::onTouchMove(wlr_touch_motion_event* ev) { if (g_pCompositor->m_sSeat.exclusiveClient) // lock screen, I think return false; - if (this->dragGestureIsActive()) { - this->emulateSwipeUpdate(0); - } - auto pos = wlrTouchEventPositionAsPixels(ev->x, ev->y); const wf::touch::gesture_event_t gesture_event = { @@ -247,6 +329,23 @@ SMonitorArea GestureManager::getMonitorArea() const { return this->m_sMonitorArea; } +void GestureManager::onLongPressTimeout(uint32_t time_msec) { + if (this->m_sGestureState.fingers.empty()) { + return; + } + + const auto finger = this->m_sGestureState.fingers.begin(); + + const wf::touch::gesture_event_t touch_event = { + .type = wf::touch::EVENT_TYPE_MOTION, + .time = time_msec, + .finger = finger->first, + .pos = finger->second.current, + }; + + IGestureManager::onTouchMove(touch_event); +} + wf::touch::point_t GestureManager::wlrTouchEventPositionAsPixels(double x, double y) const { auto area = this->getMonitorArea(); // TODO do I need to add area.x and area.y respectively? diff --git a/src/GestureManager.hpp b/src/GestureManager.hpp index 9c07428..863f5f6 100644 --- a/src/GestureManager.hpp +++ b/src/GestureManager.hpp @@ -6,10 +6,13 @@ #include #include #include +#include class GestureManager : public IGestureManager { public: + uint32_t long_press_next_trigger_time; GestureManager(); + ~GestureManager(); // @return whether this touch event should be blocked from forwarding to the // client window/surface bool onTouchDown(wlr_touch_down_event*); @@ -22,15 +25,18 @@ class GestureManager : public IGestureManager { // client window/surface bool onTouchMove(wlr_touch_motion_event*); + void onLongPressTimeout(uint32_t time_msec); + protected: SMonitorArea getMonitorArea() const override; - bool handleGesture(const CompletedGesture& gev) override; + bool handleCompletedGesture(const CompletedGesture& gev) override; void handleCancelledGesture() override; private: std::vector touchedSurfaces; CMonitor* m_pLastTouchedMonitor; SMonitorArea m_sMonitorArea; + wl_event_source* long_press_timer; // for workspace swipe wf::touch::point_t m_vGestureLastCenter; @@ -39,7 +45,14 @@ class GestureManager : public IGestureManager { void emulateSwipeUpdate(uint32_t time); wf::touch::point_t wlrTouchEventPositionAsPixels(double x, double y) const; - bool handleWorkspaceSwipe(const CompletedGesture& gev); + bool handleWorkspaceSwipe(const DragGesture& gev); + + bool handleDragGesture(const DragGesture& gev) override; + void dragGestureUpdate(const wf::touch::gesture_event_t&) override; + void handleDragGestureEnd(const DragGesture& gev) override; + + void updateLongPressTimer(uint32_t current_time, uint32_t delay) override; + void stopLongPressTimer() override; void sendCancelEventsToWindows() override; }; diff --git a/src/gestures/Gestures.cpp b/src/gestures/Gestures.cpp index 60eca6b..bb92564 100644 --- a/src/gestures/Gestures.cpp +++ b/src/gestures/Gestures.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -29,22 +30,34 @@ std::string stringifyDirection(gestureDirection direction) { std::string CompletedGesture::to_string() const { switch (type) { - case TouchGestureType::EDGE_SWIPE: + case CompletedGestureType::EDGE_SWIPE: return "edge:" + stringifyDirection(this->edge_origin) + ":" + stringifyDirection(this->direction); - case TouchGestureType::SWIPE: + case CompletedGestureType::SWIPE: return "swipe:" + std::to_string(finger_count) + ":" + stringifyDirection(this->direction); break; - case TouchGestureType::SWIPE_HOLD: - // this gesture is only used internally for workspace swipe - return "workspace_swipe"; - case TouchGestureType::TAP: + case CompletedGestureType::TAP: return "tap:" + std::to_string(finger_count); + case CompletedGestureType::LONG_PRESS: + return "longpress:" + std::to_string(finger_count); } + + return ""; +} + +std::string DragGesture::to_string() const { + switch (type) { + case DragGestureType::LONG_PRESS: + return "longpress:" + std::to_string(finger_count); + case DragGestureType::SWIPE: + return "swipe:" + std::to_string(finger_count) + ":" + stringifyDirection(this->direction); + } + + return ""; } wf::touch::action_status_t CMultiAction::update_state(const wf::touch::gesture_state_t& state, const wf::touch::gesture_event_t& event) { - if (event.time - this->start_time > this->get_duration()) { + if (event.time - this->start_time > *this->timeout) { return wf::touch::ACTION_STATUS_CANCELLED; } @@ -105,7 +118,7 @@ wf::touch::action_status_t MultiFingerDownAction::update_state(const wf::touch:: wf::touch::action_status_t MultiFingerTap::update_state(const wf::touch::gesture_state_t& state, const wf::touch::gesture_event_t& event) { - if (event.time - this->start_time > this->get_duration()) { + if (event.time - this->start_time > *this->timeout) { return wf::touch::ACTION_STATUS_CANCELLED; } @@ -116,7 +129,7 @@ wf::touch::action_status_t MultiFingerTap::update_state(const wf::touch::gesture if (event.type == wf::touch::EVENT_TYPE_MOTION) { for (const auto& finger : state.fingers) { const auto delta = finger.second.delta(); - if (delta.x * delta.x + delta.y + delta.y > this->base_threshold * *this->sensitivity) { + if (delta.x * delta.x + delta.y + delta.y > this->base_threshold / *this->sensitivity) { return wf::touch::ACTION_STATUS_CANCELLED; } } @@ -125,9 +138,37 @@ wf::touch::action_status_t MultiFingerTap::update_state(const wf::touch::gesture return wf::touch::ACTION_STATUS_RUNNING; } +wf::touch::action_status_t LongPress::update_state(const wf::touch::gesture_state_t& state, + const wf::touch::gesture_event_t& event) { + if (event.time - this->start_time > *this->delay) { + return wf::touch::ACTION_STATUS_COMPLETED; + } + + switch (event.type) { + case wf::touch::EVENT_TYPE_MOTION: + for (const auto& finger : state.fingers) { + const auto delta = finger.second.delta(); + if (delta.x * delta.x + delta.y + delta.y > this->base_threshold / *this->sensitivity) { + return wf::touch::ACTION_STATUS_CANCELLED; + } + } + break; + + case wf::touch::EVENT_TYPE_TOUCH_DOWN: + // TODO: also reset wl_timer here + gesture_action_t::reset(event.time); + this->update_external_timer_callback(event.time, *this->delay); + break; + + case wf::touch::EVENT_TYPE_TOUCH_UP: + return wf::touch::ACTION_STATUS_CANCELLED; + } + + return wf::touch::ACTION_STATUS_RUNNING; +} + wf::touch::action_status_t LiftoffAction::update_state(const wf::touch::gesture_state_t& state, const wf::touch::gesture_event_t& event) { - if (event.time - this->start_time > this->get_duration()) { return wf::touch::ACTION_STATUS_CANCELLED; } @@ -143,18 +184,36 @@ wf::touch::action_status_t LiftoffAction::update_state(const wf::touch::gesture_ return wf::touch::ACTION_STATUS_RUNNING; } -wf::touch::action_status_t CallbackAction::update_state(const wf::touch::gesture_state_t& state, - const wf::touch::gesture_event_t& event) { - this->callback(); - return wf::touch::ACTION_STATUS_COMPLETED; +wf::touch::action_status_t TouchUpOrDownAction::update_state(const wf::touch::gesture_state_t& state, + const wf::touch::gesture_event_t& event) { + if (event.time - this->start_time > this->get_duration()) { + return wf::touch::ACTION_STATUS_CANCELLED; + } + + if (event.type == wf::touch::EVENT_TYPE_TOUCH_UP || event.type == wf::touch::EVENT_TYPE_TOUCH_DOWN) { + return wf::touch::ACTION_STATUS_COMPLETED; + } + + return wf::touch::ACTION_STATUS_RUNNING; +} + +wf::touch::action_status_t OnCompleteAction::update_state(const wf::touch::gesture_state_t& state, + const wf::touch::gesture_event_t& event) { + auto status = this->action->update_state(state, event); + + if (status == wf::touch::ACTION_STATUS_COMPLETED) { + this->callback(); + } + + return status; } void IGestureManager::updateGestures(const wf::touch::gesture_event_t& ev) { if (m_sGestureState.fingers.size() == 1 && ev.type == wf::touch::EVENT_TYPE_TOUCH_DOWN) { this->inhibitTouchEvents = false; - this->dragGestureActive = false; + this->activeDragGesture = std::nullopt; } - for (auto& gesture : m_vGestures) { + for (const auto& gesture : m_vGestures) { if (m_sGestureState.fingers.size() == 1 && ev.type == wf::touch::EVENT_TYPE_TOUCH_DOWN) { gesture->reset(ev.time); } @@ -178,18 +237,33 @@ bool IGestureManager::onTouchDown(const wf::touch::gesture_event_t& ev) { // gestures this->m_sGestureState.update(ev); this->updateGestures(ev); + + if (this->activeDragGesture.has_value()) { + this->dragGestureUpdate(ev); + } + return this->eventForwardingInhibited(); } bool IGestureManager::onTouchUp(const wf::touch::gesture_event_t& ev) { this->updateGestures(ev); this->m_sGestureState.update(ev); + + if (this->activeDragGesture.has_value()) { + this->dragGestureUpdate(ev); + } + return this->eventForwardingInhibited(); } bool IGestureManager::onTouchMove(const wf::touch::gesture_event_t& ev) { this->updateGestures(ev); this->m_sGestureState.update(ev); + + if (this->activeDragGesture.has_value()) { + this->dragGestureUpdate(ev); + } + return this->eventForwardingInhibited(); } @@ -228,23 +302,23 @@ void IGestureManager::addTouchGesture(std::unique_ptr gest // threshold. // * further emits a TouchGestureType::SWIPE event if the SWIPE_HOLD event was // emitted and once a finger is lifted -void IGestureManager::addMultiFingerGesture(const float* sensitivity) { +// TODO: ^^^ remove +void IGestureManager::addMultiFingerGesture(const float* sensitivity, const int64_t* timeout) { auto multi_down = std::make_unique([this]() { this->cancelTouchEventsOnAllWindows(); }); multi_down->set_duration(GESTURE_BASE_DURATION); - auto swipe = std::make_unique(SWIPE_INCORRECT_DRAG_TOLERANCE, sensitivity); - swipe->set_duration(GESTURE_BASE_DURATION); + auto swipe = std::make_unique(SWIPE_INCORRECT_DRAG_TOLERANCE, sensitivity, timeout); auto swipe_ptr = swipe.get(); - auto trigger_swipe = std::make_unique([=, this]() { - if (this->dragGestureActive) { + auto swipe_and_emit = std::make_unique(std::move(swipe), [=, this]() { + if (this->activeDragGesture.has_value()) { return; } - const auto gesture = CompletedGesture{TouchGestureType::SWIPE_HOLD, swipe_ptr->target_direction, - static_cast(this->m_sGestureState.fingers.size())}; + const auto gesture = DragGesture{DragGestureType::SWIPE, swipe_ptr->target_direction, + static_cast(this->m_sGestureState.fingers.size())}; - this->dragGestureActive = this->handleGesture(gesture); + this->activeDragGesture = this->handleDragGesture(gesture) ? std::optional(gesture) : std::nullopt; }); auto swipe_liftoff = std::make_unique(); @@ -252,46 +326,92 @@ void IGestureManager::addMultiFingerGesture(const float* sensitivity) { std::vector> swipe_actions; swipe_actions.emplace_back(std::move(multi_down)); - swipe_actions.emplace_back(std::move(swipe)); - swipe_actions.emplace_back(std::move(trigger_swipe)); + swipe_actions.emplace_back(std::move(swipe_and_emit)); swipe_actions.emplace_back(std::move(swipe_liftoff)); auto ack = [swipe_ptr, this]() { - const auto gesture = CompletedGesture{TouchGestureType::SWIPE, swipe_ptr->target_direction, - static_cast(this->m_sGestureState.fingers.size())}; - this->handleGesture(gesture); + if (this->activeDragGesture.has_value() && this->activeDragGesture->type == DragGestureType::SWIPE) { + const auto gesture = + DragGesture{DragGestureType::SWIPE, 0, static_cast(this->m_sGestureState.fingers.size())}; + + this->handleDragGestureEnd(gesture); + this->activeDragGesture = std::nullopt; + } else { + const auto gesture = CompletedGesture{CompletedGestureType::SWIPE, swipe_ptr->target_direction, + static_cast(this->m_sGestureState.fingers.size())}; + + this->handleCompletedGesture(gesture); + } }; auto cancel = [this]() { this->handleCancelledGesture(); }; this->addTouchGesture(std::make_unique(std::move(swipe_actions), ack, cancel)); } -void IGestureManager::addMultiFingerTap(const float* sensitivity) { - auto tap = std::make_unique(SWIPE_INCORRECT_DRAG_TOLERANCE, sensitivity); - tap->set_duration(GESTURE_BASE_DURATION); - // swipe_liftoff->set_duration(GESTURE_BASE_DURATION / 2); +void IGestureManager::addMultiFingerTap(const float* sensitivity, const int64_t* timeout) { + auto tap = std::make_unique(SWIPE_INCORRECT_DRAG_TOLERANCE, sensitivity, timeout); std::vector> tap_actions; tap_actions.emplace_back(std::move(tap)); auto ack = [this]() { const auto gesture = - CompletedGesture{TouchGestureType::TAP, 0, static_cast(this->m_sGestureState.fingers.size())}; - this->handleGesture(gesture); + CompletedGesture{CompletedGestureType::TAP, 0, static_cast(this->m_sGestureState.fingers.size())}; + this->handleCompletedGesture(gesture); }; auto cancel = [this]() { this->handleCancelledGesture(); }; this->addTouchGesture(std::make_unique(std::move(tap_actions), ack, cancel)); } -// TODO: fix duration, do not depend on sensitivity -void IGestureManager::addEdgeSwipeGesture(const float* sensitivity) { +void IGestureManager::addLongPress(const float* sensitivity, const int64_t* delay) { + auto long_press_and_emit = std::make_unique( + std::make_unique( + SWIPE_INCORRECT_DRAG_TOLERANCE, sensitivity, delay, + [this](uint32_t current_time, uint32_t delay) { this->updateLongPressTimer(current_time, delay); }), + [this]() { + if (this->activeDragGesture.has_value()) { + return; + } + const auto gesture = + DragGesture{DragGestureType::LONG_PRESS, 0, static_cast(this->m_sGestureState.fingers.size())}; + + this->activeDragGesture = this->handleDragGesture(gesture) ? std::optional(gesture) : std::nullopt; + }); + + auto touch_up_or_down = std::make_unique(); + + std::vector> long_press_actions; + long_press_actions.emplace_back(std::move(long_press_and_emit)); + long_press_actions.emplace_back(std::move(touch_up_or_down)); + + auto ack = [this]() { + if (this->activeDragGesture.has_value() && this->activeDragGesture->type == DragGestureType::LONG_PRESS) { + const auto gesture = + DragGesture{DragGestureType::LONG_PRESS, 0, static_cast(this->m_sGestureState.fingers.size())}; + + this->handleDragGestureEnd(gesture); + this->activeDragGesture = std::nullopt; + } else { + const auto gesture = CompletedGesture{CompletedGestureType::LONG_PRESS, 0, + static_cast(this->m_sGestureState.fingers.size())}; + + this->handleCompletedGesture(gesture); + }; + }; + auto cancel = [this]() { + this->stopLongPressTimer(); + this->handleCancelledGesture(); + }; + + this->addTouchGesture(std::make_unique(std::move(long_press_actions), ack, cancel)); +} + +void IGestureManager::addEdgeSwipeGesture(const float* sensitivity, const int64_t* timeout) { // Edge swipe needs a quick release to be considered edge swipe - auto edge = std::make_unique(MAX_SWIPE_DISTANCE, sensitivity); + auto edge = std::make_unique(MAX_SWIPE_DISTANCE, sensitivity, timeout); auto edge_release = std::make_unique(1, false); - // FIXME make this adjustable: - edge->set_duration(GESTURE_BASE_DURATION * *sensitivity); // TODO do I really need this: // edge->set_move_tolerance(SWIPE_INCORRECT_DRAG_TOLERANCE * *sensitivity); @@ -313,8 +433,9 @@ void IGestureManager::addEdgeSwipeGesture(const float* sensitivity) { return; } auto direction = edge_ptr->target_direction; - auto gesture = CompletedGesture{TouchGestureType::EDGE_SWIPE, direction, edge_ptr->finger_count, origin_edges}; - this->handleGesture(gesture); + auto gesture = + CompletedGesture{CompletedGestureType::EDGE_SWIPE, direction, edge_ptr->finger_count, origin_edges}; + this->handleCompletedGesture(gesture); }; auto cancel = [this]() { this->handleCancelledGesture(); }; diff --git a/src/gestures/Gestures.hpp b/src/gestures/Gestures.hpp index 434afd7..93fecb5 100644 --- a/src/gestures/Gestures.hpp +++ b/src/gestures/Gestures.hpp @@ -24,15 +24,22 @@ constexpr static uint32_t GESTURE_BASE_DURATION = 400; constexpr static uint32_t SEND_CANCEL_EVENT_FINGER_COUNT = 3; -enum class TouchGestureType { +using UpdateExternalTimerCallback = std::function; + +enum class CompletedGestureType { // Invalid Gesture SWIPE, - SWIPE_HOLD, // same as SWIPE but fingers were not lifted EDGE_SWIPE, TAP, + LONG_PRESS, // PINCH, }; +enum class DragGestureType { + SWIPE, + LONG_PRESS, +}; + enum TouchGestureDirection { /* Swipe-specific */ GESTURE_DIRECTION_LEFT = (1 << 0), @@ -53,7 +60,7 @@ using gestureDirection = uint32_t; * Finger count can be arbitrary (might be a good idea to limit to >3) */ struct CompletedGesture { - TouchGestureType type; + CompletedGestureType type; gestureDirection direction; int finger_count; @@ -64,21 +71,31 @@ struct CompletedGesture { std::string to_string() const; }; +struct DragGesture { + DragGestureType type; + gestureDirection direction; + int finger_count; + + std::string to_string() const; +}; + struct SMonitorArea { double x, y, w, h; }; // swipe and with multiple fingers and directions class CMultiAction : public wf::touch::gesture_action_t { + private: + double base_threshold; + const float* sensitivity; + const int64_t* timeout; + public: // threshold = base_threshold / sensitivity // if the threshold needs to be adjusted dynamically, the sensitivity // pointer is used - CMultiAction(double base_threshold, const float* sensitivity) - : base_threshold(base_threshold), sensitivity(sensitivity){}; - - double base_threshold; - const float* sensitivity; + CMultiAction(double base_threshold, const float* sensitivity, const int64_t* timeout) + : base_threshold(base_threshold), sensitivity(sensitivity), timeout(timeout){}; gestureDirection target_direction = 0; int finger_count = 0; @@ -101,17 +118,32 @@ class MultiFingerTap : public wf::touch::gesture_action_t { private: double base_threshold; const float* sensitivity; + const int64_t* timeout; public: - MultiFingerTap(double base_threshold, const float* sensitivity) - : base_threshold(base_threshold), sensitivity(sensitivity){}; + MultiFingerTap(double base_threshold, const float* sensitivity, const int64_t* timeout) + : base_threshold(base_threshold), sensitivity(sensitivity), timeout(timeout){}; wf::touch::action_status_t update_state(const wf::touch::gesture_state_t& state, const wf::touch::gesture_event_t& event) override; +}; - void reset(uint32_t time) override { - gesture_action_t::reset(time); - }; +class LongPress : public wf::touch::gesture_action_t { + private: + double base_threshold; + const float* sensitivity; + const int64_t* delay; + UpdateExternalTimerCallback update_external_timer_callback; + + public: + // TODO: I hope one day I can figure out how not to pass a function for the update timer callback + LongPress(double base_threshold, const float* sensitivity, const int64_t* delay, + UpdateExternalTimerCallback update_external_timer) + : base_threshold(base_threshold), sensitivity(sensitivity), delay(delay), + update_external_timer_callback(update_external_timer){}; + + wf::touch::action_status_t update_state(const wf::touch::gesture_state_t& state, + const wf::touch::gesture_event_t& event) override; }; // Completes upon receiving enough touch down events within a short duration @@ -137,18 +169,30 @@ class LiftoffAction : public wf::touch::gesture_action_t { const wf::touch::gesture_event_t& event) override; }; -// This action is used to call a function in between other actions -// -// NOTE: this action consumes any event, and must consume an event to work. -class CallbackAction : public wf::touch::gesture_action_t { - public: - CallbackAction(std::function callback) : callback(callback) {} - +// Completes upon receiving a touch up or touch down event +class TouchUpOrDownAction : public wf::touch::gesture_action_t { wf::touch::action_status_t update_state(const wf::touch::gesture_state_t& state, const wf::touch::gesture_event_t& event) override; +}; +// This action is used to call a function right after another action is completed +class OnCompleteAction : public wf::touch::gesture_action_t { private: + std::unique_ptr action; const std::function callback; + + public: + OnCompleteAction(std::unique_ptr action, std::function callback) + : callback(callback) { + this->action = std::move(action); + } + + wf::touch::action_status_t update_state(const wf::touch::gesture_state_t& state, + const wf::touch::gesture_event_t& event) override; + + void reset(uint32_t time) override { + this->action->reset(time); + } }; /* @@ -176,12 +220,13 @@ class IGestureManager { bool onTouchMove(const wf::touch::gesture_event_t&); void addTouchGesture(std::unique_ptr gesture); - void addMultiFingerGesture(const float* sensitivity); - void addMultiFingerTap(const float* sensitivity); - void addEdgeSwipeGesture(const float* sensitivity); + void addMultiFingerGesture(const float* sensitivity, const int64_t* timeout); + void addMultiFingerTap(const float* sensitivity, const int64_t* timeout); + void addLongPress(const float* sensitivity, const int64_t* delay); + void addEdgeSwipeGesture(const float* sensitivity, const int64_t* timeout); - bool dragGestureIsActive() const { - return dragGestureActive; + std::optional getActiveDragGesture() const { + return activeDragGesture; } // indicates whether events should be blocked from forwarding to client @@ -198,14 +243,26 @@ class IGestureManager { virtual SMonitorArea getMonitorArea() const = 0; // handles gesture events and returns whether or not the event is used. - virtual bool handleGesture(const CompletedGesture& gev) = 0; + virtual bool handleCompletedGesture(const CompletedGesture& gev) = 0; + + // called at the start of drag evetns and returns whether or not the event is used. + virtual bool handleDragGesture(const DragGesture& gev) = 0; + + // called on every touch event while a drag gesture is active + virtual void dragGestureUpdate(const wf::touch::gesture_event_t&) = 0; + + // called at the end of a drag event + virtual void handleDragGestureEnd(const DragGesture& gev) = 0; // this function should cleanup after drag gestures virtual void handleCancelledGesture() = 0; + virtual void updateLongPressTimer(uint32_t current_time, uint32_t delay) = 0; + virtual void stopLongPressTimer() = 0; + private: bool inhibitTouchEvents; - bool dragGestureActive; + std::optional activeDragGesture; // this function is called when needed to send "cancel touch" events to // client windows/surfaces diff --git a/src/gestures/test/MockGestureManager.cpp b/src/gestures/test/MockGestureManager.cpp index 5c39a13..03ee96d 100644 --- a/src/gestures/test/MockGestureManager.cpp +++ b/src/gestures/test/MockGestureManager.cpp @@ -5,14 +5,26 @@ #define CONFIG_SENSITIVITY 1.0 -CMockGestureManager::CMockGestureManager() {} - -bool CMockGestureManager::handleGesture(const CompletedGesture& gev) { +bool CMockGestureManager::handleCompletedGesture(const CompletedGesture& gev) { std::cout << "gesture triggered: " << gev.to_string() << "\n"; - this->triggered = this->triggered || gev.type != TouchGestureType::SWIPE_HOLD; + this->triggered = true; return true; } +bool CMockGestureManager::handleDragGesture(const DragGesture& gev) { + std::cout << "drag started: " << gev.to_string() << "\n"; + return this->handlesDragEvents; +} + +void CMockGestureManager::dragGestureUpdate(const wf::touch::gesture_event_t& gev) { + std::cout << "drag update" << std::endl; +} + +void CMockGestureManager::handleDragGestureEnd(const DragGesture& gev) { + std::cout << "drag end: " << gev.to_string() << "\n"; + this->dragEnded = true; +} + void CMockGestureManager::handleCancelledGesture() { std::cout << "gesture cancelled\n"; this->cancelled = true; diff --git a/src/gestures/test/MockGestureManager.hpp b/src/gestures/test/MockGestureManager.hpp index bea90cd..2020dea 100644 --- a/src/gestures/test/MockGestureManager.hpp +++ b/src/gestures/test/MockGestureManager.hpp @@ -15,14 +15,30 @@ class Tester { class CMockGestureManager final : public IGestureManager { public: - CMockGestureManager(); + CMockGestureManager(bool handlesDragEvents) : handlesDragEvents(handlesDragEvents) {} ~CMockGestureManager() {} + // if set to true, handleDragGesture() will return true + bool handlesDragEvents; + bool triggered = false; bool cancelled = false; + bool dragEnded = false; + + // creates a gesture manager that handles all drag gestures + static CMockGestureManager newDragHandler() { + return CMockGestureManager(true); + } + + // creates a gesture manager that ignores drag gesture events + static CMockGestureManager newCompletedGestureOnlyHandler() { + return CMockGestureManager(false); + } + void resetTestResults() { triggered = false; cancelled = false; + dragEnded = false; } auto getGestureAt(int index) const { @@ -34,9 +50,15 @@ class CMockGestureManager final : public IGestureManager { return {pos->x, pos->y}; } - bool handleGesture(const CompletedGesture& gev) override; + bool handleCompletedGesture(const CompletedGesture& gev) override; + bool handleDragGesture(const DragGesture& gev) override; + void dragGestureUpdate(const wf::touch::gesture_event_t&) override; + void handleDragGestureEnd(const DragGesture& gev) override; void handleCancelledGesture() override; + void updateLongPressTimer(uint32_t current_time, uint32_t delay) override {} + void stopLongPressTimer() override {} + protected: SMonitorArea getMonitorArea() const override { return SMonitorArea{MONITOR_X, MONITOR_Y, MONITOR_WIDTH, MONITOR_HEIGHT}; diff --git a/src/gestures/test/test.cpp b/src/gestures/test/test.cpp index d2ec588..7186864 100644 --- a/src/gestures/test/test.cpp +++ b/src/gestures/test/test.cpp @@ -7,7 +7,8 @@ #include #include -constexpr float SENSITIVITY = 1.0; +constexpr float SENSITIVITY = 1.0; +constexpr int64_t LONG_PRESS_DELAY = GESTURE_BASE_DURATION; void Tester::testFindSwipeEdges() { using Test = struct { @@ -30,7 +31,7 @@ void Tester::testFindSwipeEdges() { {{MONITOR_X + MONITOR_WIDTH - 11, MONITOR_Y + MONITOR_HEIGHT - 11}, 0}, }; - CMockGestureManager mockGM; + auto mockGM = CMockGestureManager::newCompletedGestureOnlyHandler(); for (auto& test : tests) { CHECK_EQ(mockGM.find_swipe_edges(test.origin), test.result); } @@ -39,6 +40,7 @@ void Tester::testFindSwipeEdges() { enum class ExpectResultType { COMPLETED, DRAG_TRIGGERED, + DRAG_ENDED, CANCELLED, CHECK_PROGRESS, }; @@ -83,7 +85,10 @@ void ProcessEvents(CMockGestureManager& gm, ExpectResult expect, CHECK(gm.triggered); break; case ExpectResultType::DRAG_TRIGGERED: - CHECK(gm.dragGestureIsActive()); + CHECK(gm.getActiveDragGesture().has_value()); + break; + case ExpectResultType::DRAG_ENDED: + CHECK(gm.dragEnded); break; case ExpectResultType::CANCELLED: CHECK(gm.cancelled); @@ -92,6 +97,7 @@ void ProcessEvents(CMockGestureManager& gm, ExpectResult expect, const auto got = gm.getGestureAt(expect.gesture_index)->get()->get_progress(); // fuck floating point math CHECK(std::abs(got - expect.progress) < 1e-5); + break; } } @@ -101,34 +107,27 @@ using wf::touch::point_t; TEST_CASE("Multifinger: block touch events to client surfaces when more than a " "certain number of fingers touch down.") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addMultiFingerGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 120, 1, {500, 300}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 140, 2, {550, 290}}, }; - ProcessEvents(gm, {.type = ExpectResultType::CHECK_PROGRESS, .progress = 1.0 / 4.0}, events); + ProcessEvents(gm, {.type = ExpectResultType::CHECK_PROGRESS, .progress = 1.0 / 3.0}, events); CHECK(gm.eventForwardingInhibited()); } -TEST_CASE("Swipe Drag: Complete upon moving more than the threshold") { +TEST_CASE("Swipe Drag: Start drag upon moving more than the threshold") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newDragHandler(); + gm.addMultiFingerGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 1, {500, 300}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 2, {550, 290}}, {wf::touch::EVENT_TYPE_MOTION, 200, 0, {0, 290}}, - // CallbackAction needs an extra event to trigger - {wf::touch::EVENT_TYPE_MOTION, 200, 0, {0, 290}}, - /* FIXME idk why this triggers after one finger movement, should be - after all finers moved? threshold should be 450, I thought the center is - used for distance? */ - // {wf::touch::EVENT_TYPE_MOTION, 200, 1, point_t{50, 300}}, - // {wf::touch::EVENT_TYPE_MOTION, 200, 2, point_t{100, 290}}, }; ProcessEvents(gm, {.type = ExpectResultType::DRAG_TRIGGERED}, events); } @@ -136,8 +135,8 @@ TEST_CASE("Swipe Drag: Complete upon moving more than the threshold") { TEST_CASE("Swipe Drag: Cancel 3 finger swipe due to moving too much before " "adding new finger, but not enough to trigger 3 finger swipe first") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newDragHandler(); + gm.addMultiFingerGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 1, {500, 300}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 2, {401, 290}}, {wf::touch::EVENT_TYPE_MOTION, 110, 0, {409, 290}}, @@ -149,15 +148,14 @@ TEST_CASE("Swipe Drag: Cancel 3 finger swipe due to moving too much before " TEST_CASE("Swipe: Complete upon moving more than the threshold then lifting a " "finger") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addMultiFingerGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 1, {500, 300}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 2, {550, 290}}, {wf::touch::EVENT_TYPE_MOTION, 200, 0, {0, 290}}, - // FIXME same issue as in Swipe Drag // TODO CHECK progress == 0.5 {wf::touch::EVENT_TYPE_MOTION, 200, 1, {50, 300}}, {wf::touch::EVENT_TYPE_MOTION, 200, 2, {100, 290}}, @@ -168,8 +166,8 @@ TEST_CASE("Swipe: Complete upon moving more than the threshold then lifting a " TEST_CASE("Multi-finger Tap") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerTap(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addMultiFingerTap(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, @@ -183,8 +181,8 @@ TEST_CASE("Multi-finger Tap") { TEST_CASE("Multi-finger Tap: Timeout") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerTap(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addMultiFingerTap(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, @@ -198,8 +196,8 @@ TEST_CASE("Multi-finger Tap: Timeout") { TEST_CASE("Multi-finger Tap: finger moved too much") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addMultiFingerTap(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addMultiFingerTap(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, @@ -212,13 +210,71 @@ TEST_CASE("Multi-finger Tap: finger moved too much") { ProcessEvents(gm, {.type = ExpectResultType::CANCELLED}, events); } +TEST_CASE("Long press: begin drag") { + std::cout << " ==== stdout:" << std::endl; + auto gm = CMockGestureManager::newDragHandler(); + gm.addLongPress(&SENSITIVITY, &LONG_PRESS_DELAY); + + const std::vector events{ + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 105, 1, {500, 300}}, + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 110, 2, {550, 290}}, {wf::touch::EVENT_TYPE_MOTION, 200, 0, {460, 300}}, + {wf::touch::EVENT_TYPE_MOTION, 300, 1, {510, 290}}, {wf::touch::EVENT_TYPE_MOTION, 511, 2, {560, 300}}, + }; + + ProcessEvents(gm, {.type = ExpectResultType::DRAG_TRIGGERED}, events); +} + +TEST_CASE("Long press and drag: full drag") { + std::cout << " ==== stdout:" << std::endl; + auto gm = CMockGestureManager::newDragHandler(); + gm.addLongPress(&SENSITIVITY, &LONG_PRESS_DELAY); + + const std::vector events{ + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 105, 1, {500, 300}}, + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 110, 2, {550, 290}}, {wf::touch::EVENT_TYPE_MOTION, 200, 0, {460, 300}}, + {wf::touch::EVENT_TYPE_MOTION, 300, 1, {510, 290}}, {wf::touch::EVENT_TYPE_MOTION, 511, 2, {560, 300}}, + {wf::touch::EVENT_TYPE_MOTION, 530, 0, {470, 310}}, {wf::touch::EVENT_TYPE_TOUCH_UP, 550, 2, {560, 300}}}; + + ProcessEvents(gm, {.type = ExpectResultType::DRAG_ENDED}, events); +} + +TEST_CASE("Long press and drag: cancelled due to short hold duration") { + std::cout << " ==== stdout:" << std::endl; + auto gm = CMockGestureManager::newDragHandler(); + gm.addLongPress(&SENSITIVITY, &LONG_PRESS_DELAY); + + const std::vector events{ + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, {wf::touch::EVENT_TYPE_TOUCH_DOWN, 105, 1, {500, 300}}, + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 110, 2, {550, 290}}, {wf::touch::EVENT_TYPE_MOTION, 200, 0, {460, 300}}, + {wf::touch::EVENT_TYPE_MOTION, 300, 1, {510, 290}}, {wf::touch::EVENT_TYPE_MOTION, 350, 2, {560, 300}}, + {wf::touch::EVENT_TYPE_MOTION, 400, 1, {510, 290}}, {wf::touch::EVENT_TYPE_TOUCH_UP, 500, 2, {560, 300}}, + }; + + ProcessEvents(gm, {.type = ExpectResultType::CANCELLED}, events); +} + +TEST_CASE("Long press and drag: cancelled due to too much movement") { + std::cout << " ==== stdout:" << std::endl; + auto gm = CMockGestureManager::newDragHandler(); + gm.addLongPress(&SENSITIVITY, &LONG_PRESS_DELAY); + + const std::vector events{ + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {450, 290}}, + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 105, 1, {500, 300}}, + {wf::touch::EVENT_TYPE_TOUCH_DOWN, 110, 2, {550, 290}}, + {wf::touch::EVENT_TYPE_MOTION, 200, 1, {650, 290}}, + }; + + ProcessEvents(gm, {.type = ExpectResultType::CANCELLED}, events); +} + TEST_CASE("Edge Swipe: Complete upon: \n" "1. touch down on edge of screen\n" "2. swiping more than the threshold, within the time limit, then\n" "3. lifting the finger, within the time limit.\n") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addEdgeSwipeGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addEdgeSwipeGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {5, 300}}, @@ -232,8 +288,8 @@ TEST_CASE("Edge Swipe: Complete upon: \n" TEST_CASE("Edge Swipe: Timeout during swiping phase") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addEdgeSwipeGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addEdgeSwipeGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {5, 300}}, @@ -248,8 +304,8 @@ TEST_CASE("Edge Swipe: Timout during liftoff phase: \n" "2. swipe more than the threshold, within the time limit, then\n" "3. do not lift finger until after timeout.") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addEdgeSwipeGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addEdgeSwipeGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {5, 300}}, @@ -267,8 +323,8 @@ TEST_CASE("Edge Swipe: Fail check at the end for not starting swipe from an edge "The starting position of the swipe is checked at the end and should " "fail.") { std::cout << " ==== stdout:" << std::endl; - CMockGestureManager gm; - gm.addEdgeSwipeGesture(&SENSITIVITY); + auto gm = CMockGestureManager::newCompletedGestureOnlyHandler(); + gm.addEdgeSwipeGesture(&SENSITIVITY, &LONG_PRESS_DELAY); const std::vector events{ {wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {11, 300}}, diff --git a/src/main.cpp b/src/main.cpp index a09efd2..2608c03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,21 +41,12 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() { APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; - bool cfgStatus = true; - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-field-initializers" - cfgStatus = cfgStatus && HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers", - SConfigValue{.intValue = 3}); - cfgStatus = cfgStatus && HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:sensitivity", - SConfigValue{.floatValue = 1.0}); - cfgStatus = cfgStatus && HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:experimental:send_cancel", - SConfigValue{.intValue = 0}); - - if (!cfgStatus) { - HyprlandAPI::addNotification(PHANDLE, "config values cannot be properly added", CColor(0.8, 0.2, 0.2, 1.0), - 5000); - } + HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers", SConfigValue{.intValue = 3}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:sensitivity", SConfigValue{.floatValue = 1.0}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:long_press_delay", SConfigValue{.intValue = 400}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:experimental:send_cancel", SConfigValue{.intValue = 0}); #pragma GCC diagnostic pop const auto hlTargetVersion = GIT_COMMIT_HASH;