input: Add fully configurable trackpad gestures (#11490)
Adds configurable trackpad gestures
This commit is contained in:
parent
378e130f14
commit
81bf4eccba
60 changed files with 2518 additions and 940 deletions
221
src/managers/input/trackpad/TrackpadGestures.cpp
Normal file
221
src/managers/input/trackpad/TrackpadGestures.cpp
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#include "TrackpadGestures.hpp"
|
||||
|
||||
#include "../InputManager.hpp"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
void CTrackpadGestures::clearGestures() {
|
||||
m_gestures.clear();
|
||||
}
|
||||
|
||||
eTrackpadGestureDirection CTrackpadGestures::dirForString(const std::string_view& s) {
|
||||
std::string lc = std::string{s};
|
||||
std::ranges::transform(lc, lc.begin(), ::tolower);
|
||||
|
||||
if (lc == "swipe")
|
||||
return TRACKPAD_GESTURE_DIR_SWIPE;
|
||||
if (lc == "left" || lc == "l")
|
||||
return TRACKPAD_GESTURE_DIR_LEFT;
|
||||
if (lc == "right" || lc == "r")
|
||||
return TRACKPAD_GESTURE_DIR_RIGHT;
|
||||
if (lc == "up" || lc == "u" || lc == "top" || lc == "t")
|
||||
return TRACKPAD_GESTURE_DIR_UP;
|
||||
if (lc == "down" || lc == "d" || lc == "bottom" || lc == "b")
|
||||
return TRACKPAD_GESTURE_DIR_DOWN;
|
||||
if (lc == "horizontal" || lc == "horiz")
|
||||
return TRACKPAD_GESTURE_DIR_HORIZONTAL;
|
||||
if (lc == "vertical" || lc == "vert")
|
||||
return TRACKPAD_GESTURE_DIR_VERTICAL;
|
||||
if (lc == "pinch")
|
||||
return TRACKPAD_GESTURE_DIR_PINCH;
|
||||
if (lc == "pinchin" || lc == "zoomin")
|
||||
return TRACKPAD_GESTURE_DIR_PINCH_IN;
|
||||
if (lc == "pinchout" || lc == "zoomout")
|
||||
return TRACKPAD_GESTURE_DIR_PINCH_OUT;
|
||||
|
||||
return TRACKPAD_GESTURE_DIR_NONE;
|
||||
}
|
||||
|
||||
const char* CTrackpadGestures::stringForDir(eTrackpadGestureDirection dir) {
|
||||
switch (dir) {
|
||||
case TRACKPAD_GESTURE_DIR_HORIZONTAL: return "HORIZONTAL";
|
||||
case TRACKPAD_GESTURE_DIR_VERTICAL: return "VERTICAL";
|
||||
case TRACKPAD_GESTURE_DIR_LEFT: return "LEFT";
|
||||
case TRACKPAD_GESTURE_DIR_RIGHT: return "RIGHT";
|
||||
case TRACKPAD_GESTURE_DIR_UP: return "UP";
|
||||
case TRACKPAD_GESTURE_DIR_DOWN: return "DOWN";
|
||||
case TRACKPAD_GESTURE_DIR_SWIPE: return "SWIPE";
|
||||
case TRACKPAD_GESTURE_DIR_PINCH: return "PINCH";
|
||||
case TRACKPAD_GESTURE_DIR_PINCH_IN: return "PINCH_IN";
|
||||
case TRACKPAD_GESTURE_DIR_PINCH_OUT: return "PINCH_OUT";
|
||||
default: return "ERROR";
|
||||
}
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
std::expected<void, std::string> CTrackpadGestures::addGesture(UP<ITrackpadGesture>&& gesture, size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask,
|
||||
float deltaScale) {
|
||||
for (const auto& g : m_gestures) {
|
||||
if (g->fingerCount != fingerCount)
|
||||
continue;
|
||||
|
||||
if (g->modMask != modMask)
|
||||
continue;
|
||||
|
||||
eTrackpadGestureDirection axis = TRACKPAD_GESTURE_DIR_NONE;
|
||||
switch (direction) {
|
||||
case TRACKPAD_GESTURE_DIR_UP:
|
||||
case TRACKPAD_GESTURE_DIR_DOWN:
|
||||
case TRACKPAD_GESTURE_DIR_VERTICAL: axis = TRACKPAD_GESTURE_DIR_VERTICAL; break;
|
||||
case TRACKPAD_GESTURE_DIR_LEFT:
|
||||
case TRACKPAD_GESTURE_DIR_RIGHT:
|
||||
case TRACKPAD_GESTURE_DIR_HORIZONTAL: axis = TRACKPAD_GESTURE_DIR_HORIZONTAL; break;
|
||||
case TRACKPAD_GESTURE_DIR_SWIPE: axis = TRACKPAD_GESTURE_DIR_SWIPE; break;
|
||||
case TRACKPAD_GESTURE_DIR_PINCH:
|
||||
case TRACKPAD_GESTURE_DIR_PINCH_IN:
|
||||
case TRACKPAD_GESTURE_DIR_PINCH_OUT: axis = TRACKPAD_GESTURE_DIR_PINCH; break;
|
||||
default: TRACKPAD_GESTURE_DIR_NONE; break;
|
||||
}
|
||||
|
||||
if (g->direction == axis || g->direction == direction ||
|
||||
((axis == TRACKPAD_GESTURE_DIR_VERTICAL || axis == TRACKPAD_GESTURE_DIR_HORIZONTAL) && g->direction == TRACKPAD_GESTURE_DIR_SWIPE)) {
|
||||
return std::unexpected(
|
||||
std::format("Gesture will be overshadowed by a previous gesture. Previous {} shadows new {}", stringForDir(g->direction), stringForDir(direction)));
|
||||
}
|
||||
}
|
||||
|
||||
m_gestures.emplace_back(makeShared<CTrackpadGestures::SGestureData>(std::move(gesture), fingerCount, modMask, direction, deltaScale));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CTrackpadGestures::gestureBegin(const IPointer::SSwipeBeginEvent& e) {
|
||||
if (m_activeGesture) {
|
||||
Debug::log(ERR, "CTrackpadGestures::gestureBegin (swipe) but m_activeGesture is already present");
|
||||
return;
|
||||
}
|
||||
|
||||
m_gestureFindFailed = false;
|
||||
|
||||
// nothing here. We need to wait for the first update to determine the delta.
|
||||
}
|
||||
|
||||
void CTrackpadGestures::gestureUpdate(const IPointer::SSwipeUpdateEvent& e) {
|
||||
if (m_gestureFindFailed)
|
||||
return;
|
||||
|
||||
// 5 was chosen because I felt like that's a good number.
|
||||
if (!m_activeGesture && (std::abs(e.delta.x) < 5 && std::abs(e.delta.y) < 5)) {
|
||||
Debug::log(TRACE, "CTrackpadGestures::gestureUpdate (swipe): gesture delta too small to start considering, waiting");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_activeGesture) {
|
||||
// try to find a gesture that matches our current state
|
||||
|
||||
auto direction = TRACKPAD_GESTURE_DIR_NONE;
|
||||
auto axis = std::abs(e.delta.x) > std::abs(e.delta.y) ? TRACKPAD_GESTURE_DIR_HORIZONTAL : TRACKPAD_GESTURE_DIR_VERTICAL;
|
||||
|
||||
if (axis == TRACKPAD_GESTURE_DIR_HORIZONTAL)
|
||||
direction = e.delta.x < 0 ? TRACKPAD_GESTURE_DIR_LEFT : TRACKPAD_GESTURE_DIR_RIGHT;
|
||||
else
|
||||
direction = e.delta.y < 0 ? TRACKPAD_GESTURE_DIR_UP : TRACKPAD_GESTURE_DIR_DOWN;
|
||||
|
||||
const auto MODS = g_pInputManager->getModsFromAllKBs();
|
||||
|
||||
for (const auto& g : m_gestures) {
|
||||
if (g->direction != axis && g->direction != direction && g->direction != TRACKPAD_GESTURE_DIR_SWIPE)
|
||||
continue;
|
||||
|
||||
if (g->fingerCount != e.fingers)
|
||||
continue;
|
||||
|
||||
if (g->modMask != MODS)
|
||||
continue;
|
||||
|
||||
m_activeGesture = g;
|
||||
g->currentDirection = g->gesture->isDirectionSensitive() ? g->direction : direction;
|
||||
m_activeGesture->gesture->begin({.swipe = &e, .direction = direction, .scale = g->deltaScale});
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_activeGesture) {
|
||||
m_gestureFindFailed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_activeGesture->gesture->update({.swipe = &e, .direction = m_activeGesture->currentDirection, .scale = m_activeGesture->deltaScale});
|
||||
}
|
||||
|
||||
void CTrackpadGestures::gestureEnd(const IPointer::SSwipeEndEvent& e) {
|
||||
if (!m_activeGesture)
|
||||
return;
|
||||
|
||||
m_activeGesture->gesture->end({.swipe = &e, .direction = m_activeGesture->direction, .scale = m_activeGesture->deltaScale});
|
||||
|
||||
m_activeGesture.reset();
|
||||
}
|
||||
|
||||
void CTrackpadGestures::gestureBegin(const IPointer::SPinchBeginEvent& e) {
|
||||
if (m_activeGesture) {
|
||||
Debug::log(ERR, "CTrackpadGestures::gestureBegin (pinch) but m_activeGesture is already present");
|
||||
return;
|
||||
}
|
||||
|
||||
m_gestureFindFailed = false;
|
||||
|
||||
// nothing here. We need to wait for the first update to determine the delta.
|
||||
}
|
||||
|
||||
void CTrackpadGestures::gestureUpdate(const IPointer::SPinchUpdateEvent& e) {
|
||||
if (m_gestureFindFailed)
|
||||
return;
|
||||
|
||||
// 0.1 was chosen because I felt like that's a good number.
|
||||
if (!m_activeGesture && std::abs(e.scale - 1.F) < 0.1) {
|
||||
Debug::log(TRACE, "CTrackpadGestures::gestureUpdate (pinch): gesture delta too small to start considering, waiting");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_activeGesture) {
|
||||
// try to find a gesture that matches our current state
|
||||
|
||||
auto direction = e.scale < 1.F ? TRACKPAD_GESTURE_DIR_PINCH_OUT : TRACKPAD_GESTURE_DIR_PINCH_IN;
|
||||
auto axis = TRACKPAD_GESTURE_DIR_PINCH;
|
||||
|
||||
const auto MODS = g_pInputManager->getModsFromAllKBs();
|
||||
|
||||
for (const auto& g : m_gestures) {
|
||||
if (g->direction != axis && g->direction != direction)
|
||||
continue;
|
||||
|
||||
if (g->fingerCount != e.fingers)
|
||||
continue;
|
||||
|
||||
if (g->modMask != MODS)
|
||||
continue;
|
||||
|
||||
m_activeGesture = g;
|
||||
g->currentDirection = g->gesture->isDirectionSensitive() ? g->direction : direction;
|
||||
m_activeGesture->gesture->begin({.pinch = &e, .direction = direction});
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_activeGesture) {
|
||||
m_gestureFindFailed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_activeGesture->gesture->update({.pinch = &e, .direction = m_activeGesture->currentDirection});
|
||||
}
|
||||
|
||||
void CTrackpadGestures::gestureEnd(const IPointer::SPinchEndEvent& e) {
|
||||
if (!m_activeGesture)
|
||||
return;
|
||||
|
||||
m_activeGesture->gesture->end({.pinch = &e, .direction = m_activeGesture->direction});
|
||||
|
||||
m_activeGesture.reset();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue