Skip to content

Commit

Permalink
feat workspace edge swipe (#73)
Browse files Browse the repository at this point in the history
* internal: emit edge swipe drag events

* dev: add config option workspace_swipe_edge

* feat: add workspace swipe from edge

* fixup! feat: add workspace swipe from edge

* docs: add option workspace_swipe_edge
  • Loading branch information
horriblename committed Jan 3, 2024
1 parent 0165a9e commit 60bf0c0
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 24 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ plugin {
# must be >= 3
workspace_swipe_fingers = 3
# switching workspaces by swiping from an edge, this is separate from workspace_swipe_fingers
# and can be used at the same time
# possible values: l, r, u, or d
# to disable it set it to anything else
workspace_swipe_edge = d
# in milliseconds
long_press_delay = 400
Expand Down
62 changes: 46 additions & 16 deletions src/GestureManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,34 @@ bool GestureManager::handleCompletedGesture(const CompletedGesture& gev) {
}

bool GestureManager::handleDragGesture(const DragGesture& gev) {
static auto* const WORKSPACE_SWIPE_FINGERS =
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers")->intValue;
static auto* const WORKSPACE_SWIPE_EDGE =
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_edge")->strValue;

switch (gev.type) {
case DragGestureType::SWIPE:
return this->handleWorkspaceSwipe(gev);
if (*WORKSPACE_SWIPE_FINGERS != gev.finger_count) {
return false;
}
return this->handleWorkspaceSwipe(gev.direction);

case DragGestureType::EDGE_SWIPE:
if (*WORKSPACE_SWIPE_EDGE == "l" && gev.direction == GESTURE_DIRECTION_LEFT) {
return this->handleWorkspaceSwipe(gev.direction);
}
if (*WORKSPACE_SWIPE_EDGE == "r" && gev.edge_origin == GESTURE_DIRECTION_RIGHT) {
return this->handleWorkspaceSwipe(gev.direction);
}
if (*WORKSPACE_SWIPE_EDGE == "u" && gev.edge_origin == GESTURE_DIRECTION_UP) {
return this->handleWorkspaceSwipe(gev.direction);
}
if (*WORKSPACE_SWIPE_EDGE == "d" && gev.edge_origin == GESTURE_DIRECTION_DOWN) {
return this->handleWorkspaceSwipe(gev.direction);
}

return false;

default:
break;
}
Expand Down Expand Up @@ -146,6 +171,9 @@ void GestureManager::handleCancelledGesture() {
return;
case DragGestureType::LONG_PRESS:
break;
case DragGestureType::EDGE_SWIPE:
this->emulateSwipeEnd(0, false);
break;
}
}

Expand All @@ -165,6 +193,9 @@ void GestureManager::dragGestureUpdate(const wf::touch::gesture_event_t& ev) {
g_pLayoutManager->getCurrentLayout()->onMouseMove(Vector2D(pos.x, pos.y));
return;
}
case DragGestureType::EDGE_SWIPE:
emulateSwipeUpdate(ev.time);
return;
}
}

Expand All @@ -179,30 +210,29 @@ void GestureManager::handleDragGestureEnd(const DragGesture& gev) {
return;
case DragGestureType::LONG_PRESS:
break;
case DragGestureType::EDGE_SWIPE:
emulateSwipeEnd(0, false);
return;
}

handleGestureBind(gev.to_string(), false);
}

bool GestureManager::handleWorkspaceSwipe(const DragGesture& gev) {
static auto* const PWORKSPACEFINGERS =
&HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers")->intValue;
bool GestureManager::handleWorkspaceSwipe(const GestureDirection direction) {
const auto VERTANIMS = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace)
->m_vRenderOffset.getConfig()
->pValues->internalStyle == "slidevert";

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;
const auto anti_directions = VERTANIMS ? horizontal : vertical;

if (gev.direction & workspace_directions && !(gev.direction & anti_directions)) {
// FIXME time arg of @emulateSwipeBegin should probably be assigned
// something useful (though its not really used later)
this->emulateSwipeBegin(0);
return true;
}
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;
const auto anti_directions = VERTANIMS ? horizontal : vertical;

if (direction & workspace_directions && !(direction & anti_directions)) {
// FIXME time arg of @emulateSwipeBegin should probably be assigned
// something useful (though its not really used later)
this->emulateSwipeBegin(0);
return true;
}

return false;
Expand Down
3 changes: 2 additions & 1 deletion src/GestureManager.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "./gestures/Gestures.hpp"
#include "gestures/Shared.hpp"
#include "globals.hpp"
#include <hyprland/src/debug/Log.hpp>
#include <hyprland/src/helpers/Monitor.hpp>
Expand Down Expand Up @@ -45,7 +46,7 @@ class GestureManager : public IGestureManager {
void emulateSwipeUpdate(uint32_t time);

wf::touch::point_t wlrTouchEventPositionAsPixels(double x, double y) const;
bool handleWorkspaceSwipe(const DragGesture& gev);
bool handleWorkspaceSwipe(const GestureDirection direction);

bool handleDragGesture(const DragGesture& gev) override;
void dragGestureUpdate(const wf::touch::gesture_event_t&) override;
Expand Down
24 changes: 17 additions & 7 deletions src/gestures/Gestures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ std::string DragGesture::to_string() const {
return "longpress:" + std::to_string(finger_count);
case DragGestureType::SWIPE:
return "swipe:" + std::to_string(finger_count) + ":" + stringifyDirection(this->direction);
case DragGestureType::EDGE_SWIPE:
return "edge:" + stringifyDirection(this->edge_origin) + ":" + stringifyDirection(this->direction);
}

return "";
Expand Down Expand Up @@ -249,9 +251,19 @@ void IGestureManager::addLongPress(const float* sensitivity, const int64_t* dela
}

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<CMultiAction>(MAX_SWIPE_DISTANCE, sensitivity, timeout);
auto edge_release = std::make_unique<wf::touch::touch_action_t>(1, false);
auto edge = std::make_unique<CMultiAction>(MAX_SWIPE_DISTANCE, sensitivity, timeout);
auto edge_ptr = edge.get();
auto edge_drag_begin = std::make_unique<OnCompleteAction>(std::move(edge), [=, this]() {
auto origin_edges = this->find_swipe_edges(m_sGestureState.get_center().origin);

if (origin_edges == 0) {
return;
}
auto direction = edge_ptr->target_direction;
auto gesture = DragGesture{DragGestureType::EDGE_SWIPE, direction, edge_ptr->finger_count, origin_edges};
this->activeDragGesture = this->handleDragGesture(gesture) ? std::optional(gesture) : std::nullopt;
});
auto edge_release = std::make_unique<wf::touch::touch_action_t>(1, false);

// TODO do I really need this:
// edge->set_move_tolerance(SWIPE_INCORRECT_DRAG_TOLERANCE * *sensitivity);
Expand All @@ -261,16 +273,14 @@ void IGestureManager::addEdgeSwipeGesture(const float* sensitivity, const int64_
// TODO make this adjustable:
edge_release->set_duration(GESTURE_BASE_DURATION * 1.5 * *sensitivity);

auto edge_ptr = edge.get();

std::vector<std::unique_ptr<wf::touch::gesture_action_t>> edge_swipe_actions;
edge_swipe_actions.emplace_back(std::move(edge));
edge_swipe_actions.emplace_back(std::move(edge_drag_begin));
edge_swipe_actions.emplace_back(std::move(edge_release));

auto ack = [edge_ptr, this]() {
auto origin_edges = find_swipe_edges(m_sGestureState.get_center().origin);

if (!origin_edges) {
if (origin_edges == 0) {
return;
}
auto direction = edge_ptr->target_direction;
Expand Down
3 changes: 3 additions & 0 deletions src/gestures/Gestures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum class CompletedGestureType {
enum class DragGestureType {
SWIPE,
LONG_PRESS,
EDGE_SWIPE,
};

enum TouchGestureDirection {
Expand Down Expand Up @@ -52,6 +53,8 @@ struct DragGesture {
GestureDirection direction;
int finger_count;

GestureDirection edge_origin;

std::string to_string() const;
};

Expand Down
14 changes: 14 additions & 0 deletions src/gestures/test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,17 @@ TEST_CASE("Edge Swipe: Fail check at the end for not starting swipe from an edge
const ExpectResult expected_result = {ExpectResultType::CHECK_PROGRESS, 1.0};
ProcessEvents(gm, expected_result, events);
}

TEST_CASE("Edge Swipe Drag: begin") {
std::cout << " ==== stdout:" << std::endl;
auto gm = CMockGestureManager::newDragHandler();
gm.addEdgeSwipeGesture(&SENSITIVITY, &LONG_PRESS_DELAY);

const std::vector<TouchEvent> events{
{wf::touch::EVENT_TYPE_TOUCH_DOWN, 100, 0, {5, 300}},
{wf::touch::EVENT_TYPE_MOTION, 150, 0, {250, 300}},
{wf::touch::EVENT_TYPE_MOTION, 200, 0, {455, 300}},
};
const ExpectResult expected_result = {ExpectResultType::DRAG_TRIGGERED, 1.0};
ProcessEvents(gm, expected_result, events);
}
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers", SConfigValue{.intValue = 3});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_edge", SConfigValue{.strValue = "d"});
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});
Expand Down

0 comments on commit 60bf0c0

Please sign in to comment.