keybinds: add inhibiting gestures under shortcut inhibitors (#12692)

This commit is contained in:
ArchSav 2025-12-30 23:45:56 +11:00 committed by GitHub
parent ea444c35bb
commit f8464866eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 530 additions and 21 deletions

View file

@ -96,7 +96,9 @@ endfunction()
protocolnew("staging/pointer-warp" "pointer-warp-v1" false)
protocolnew("stable/xdg-shell" "xdg-shell" false)
protocolnew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false)
clientNew("pointer-warp" PROTOS "pointer-warp-v1" "xdg-shell")
clientNew("pointer-scroll" PROTOS "xdg-shell")
clientNew("child-window" PROTOS "xdg-shell")
clientNew("child-window" PROTOS "xdg-shell")
clientNew("shortcut-inhibitor" PROTOS "xdg-shell" "keyboard-shortcuts-inhibit-unstable-v1")

View file

@ -0,0 +1,297 @@
#include <sys/poll.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <print>
#include <wayland-client.h>
#include <wayland.hpp>
#include <xdg-shell.hpp>
#include <keyboard-shortcuts-inhibit-unstable-v1.hpp>
#include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/math/Vector2D.hpp>
using Hyprutils::Math::Vector2D;
using namespace Hyprutils::Memory;
struct SWlState {
wl_display* display;
CSharedPointer<CCWlRegistry> registry;
// protocols
CSharedPointer<CCWlCompositor> wlCompositor;
CSharedPointer<CCWlSeat> wlSeat;
CSharedPointer<CCWlShm> wlShm;
CSharedPointer<CCXdgWmBase> xdgShell;
CSharedPointer<CCZwpKeyboardShortcutsInhibitManagerV1> inhibitManager;
// shm/buffer stuff
CSharedPointer<CCWlShmPool> shmPool;
CSharedPointer<CCWlBuffer> shmBuf;
int shmFd;
size_t shmBufSize;
bool xrgb8888_support = false;
// surface/toplevel stuff
CSharedPointer<CCWlSurface> surf;
CSharedPointer<CCXdgSurface> xdgSurf;
CSharedPointer<CCXdgToplevel> xdgToplevel;
Vector2D geom;
// pointer
CSharedPointer<CCWlPointer> pointer;
uint32_t enterSerial;
// shortcut inhibiting
CSharedPointer<CCZwpKeyboardShortcutsInhibitorV1> inhibitor;
};
static bool debug, started, shouldExit;
template <typename... Args>
//NOLINTNEXTLINE
static void clientLog(std::format_string<Args...> fmt, Args&&... args) {
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
std::println("{}", text);
std::fflush(stdout);
}
template <typename... Args>
//NOLINTNEXTLINE
static void debugLog(std::format_string<Args...> fmt, Args&&... args) {
std::string text = std::vformat(fmt.get(), std::make_format_args(args...));
if (!debug)
return;
std::println("{}", text);
std::fflush(stdout);
}
static bool bindRegistry(SWlState& state) {
state.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(state.display));
state.registry->setGlobal([&](CCWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
const std::string NAME = name;
if (NAME == "wl_compositor") {
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
state.wlCompositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_compositor_interface, 6));
} else if (NAME == "wl_shm") {
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
state.wlShm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_shm_interface, 1));
} else if (NAME == "wl_seat") {
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
state.wlSeat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &wl_seat_interface, 9));
} else if (NAME == "xdg_wm_base") {
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
state.xdgShell = makeShared<CCXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &xdg_wm_base_interface, 1));
} else if (NAME == "zwp_keyboard_shortcuts_inhibit_manager_v1") {
debugLog(" > binding to global: {} (version {}) with id {}", name, version, id);
state.inhibitManager = makeShared<CCZwpKeyboardShortcutsInhibitManagerV1>(
(wl_proxy*)wl_registry_bind((wl_registry*)state.registry->resource(), id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1));
}
});
state.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t id) { debugLog("Global {} removed", id); });
wl_display_roundtrip(state.display);
if (!state.wlCompositor || !state.wlShm || !state.wlSeat || !state.xdgShell || !state.inhibitManager) {
clientLog("Failed to get protocols from Hyprland");
return false;
}
return true;
}
static bool createShm(SWlState& state, Vector2D geom) {
if (!state.xrgb8888_support)
return false;
size_t stride = geom.x * 4;
size_t size = geom.y * stride;
if (!state.shmPool) {
const char* name = "/wl-shm-shortcut-inhibitor";
state.shmFd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (state.shmFd < 0)
return false;
if (shm_unlink(name) < 0 || ftruncate(state.shmFd, size) < 0) {
close(state.shmFd);
return false;
}
state.shmPool = makeShared<CCWlShmPool>(state.wlShm->sendCreatePool(state.shmFd, size));
if (!state.shmPool->resource()) {
close(state.shmFd);
state.shmFd = -1;
state.shmPool.reset();
return false;
}
state.shmBufSize = size;
} else if (size > state.shmBufSize) {
if (ftruncate(state.shmFd, size) < 0) {
close(state.shmFd);
state.shmFd = -1;
state.shmPool.reset();
return false;
}
state.shmPool->sendResize(size);
state.shmBufSize = size;
}
auto buf = makeShared<CCWlBuffer>(state.shmPool->sendCreateBuffer(0, geom.x, geom.y, stride, WL_SHM_FORMAT_XRGB8888));
if (!buf->resource())
return false;
if (state.shmBuf) {
state.shmBuf->sendDestroy();
state.shmBuf.reset();
}
state.shmBuf = buf;
return true;
}
static bool setupToplevel(SWlState& state) {
state.wlShm->setFormat([&](CCWlShm* p, uint32_t format) {
if (format == WL_SHM_FORMAT_XRGB8888)
state.xrgb8888_support = true;
});
state.xdgShell->setPing([&](CCXdgWmBase* p, uint32_t serial) { state.xdgShell->sendPong(serial); });
state.surf = makeShared<CCWlSurface>(state.wlCompositor->sendCreateSurface());
if (!state.surf->resource())
return false;
state.xdgSurf = makeShared<CCXdgSurface>(state.xdgShell->sendGetXdgSurface(state.surf->resource()));
if (!state.xdgSurf->resource())
return false;
state.xdgToplevel = makeShared<CCXdgToplevel>(state.xdgSurf->sendGetToplevel());
if (!state.xdgToplevel->resource())
return false;
state.xdgToplevel->setClose([&](CCXdgToplevel* p) { exit(0); });
state.xdgToplevel->setConfigure([&](CCXdgToplevel* p, int32_t w, int32_t h, wl_array* arr) {
state.geom = {1280, 720};
if (!createShm(state, state.geom))
exit(-1);
});
state.xdgSurf->setConfigure([&](CCXdgSurface* p, uint32_t serial) {
if (!state.shmBuf)
debugLog("xdgSurf configure but no buf made yet?");
state.xdgSurf->sendSetWindowGeometry(0, 0, state.geom.x, state.geom.y);
state.surf->sendAttach(state.shmBuf.get(), 0, 0);
state.surf->sendCommit();
state.xdgSurf->sendAckConfigure(serial);
if (!started) {
started = true;
clientLog("started");
}
});
state.xdgToplevel->sendSetTitle("shortcut-inhibitor test client");
state.xdgToplevel->sendSetAppId("shortcut-inhibitor");
state.surf->sendAttach(nullptr, 0, 0);
state.surf->sendCommit();
return true;
}
static bool setupSeat(SWlState& state) {
state.pointer = makeShared<CCWlPointer>(state.wlSeat->sendGetPointer());
if (!state.pointer->resource())
return false;
state.pointer->setEnter([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf, wl_fixed_t x, wl_fixed_t y) {
debugLog("Got pointer enter event, serial {}, x {}, y {}", serial, x, y);
state.enterSerial = serial;
});
state.pointer->setLeave([&](CCWlPointer* p, uint32_t serial, wl_proxy* surf) { debugLog("Got pointer leave event, serial {}", serial); });
state.pointer->setMotion([&](CCWlPointer* p, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { debugLog("Got pointer motion event, serial {}, x {}, y {}", serial, x, y); });
return true;
}
static void parseRequest(SWlState& state, std::string req) {
if (req.starts_with("on")) {
state.inhibitor = makeShared<CCZwpKeyboardShortcutsInhibitorV1>(state.inhibitManager->sendInhibitShortcuts(state.surf->resource(), state.wlSeat->resource()));
state.inhibitor->setActive([&](CCZwpKeyboardShortcutsInhibitorV1* inhibitorV1) { clientLog("inhibiting"); });
state.inhibitor->setInactive([&](CCZwpKeyboardShortcutsInhibitorV1* inhibitorV1) { clientLog("inhibit disabled by compositor"); });
} else if (req.starts_with("off")) {
state.inhibitor->sendDestroy();
state.inhibitor.reset();
shouldExit = true;
clientLog("inhibit disabled by request");
}
}
int main(int argc, char** argv) {
if (argc != 1 && argc != 2)
clientLog("Only the \"--debug\" switch is allowed, it turns on debug logs.");
if (argc == 2 && std::string{argv[1]} == "--debug")
debug = true;
SWlState state;
// WAYLAND_DISPLAY env should be set to the correct one
state.display = wl_display_connect(nullptr);
if (!state.display) {
clientLog("Failed to connect to wayland display");
return -1;
}
if (!bindRegistry(state) || !setupSeat(state) || !setupToplevel(state))
return -1;
std::array<char, 1024> readBuf;
readBuf.fill(0);
wl_display_flush(state.display);
struct pollfd fds[2] = {{.fd = wl_display_get_fd(state.display), .events = POLLIN | POLLOUT}, {.fd = STDIN_FILENO, .events = POLLIN}};
while (!shouldExit && poll(fds, 2, 0) != -1) {
if (fds[0].revents & POLLIN) {
wl_display_flush(state.display);
if (wl_display_prepare_read(state.display) == 0) {
wl_display_read_events(state.display);
wl_display_dispatch_pending(state.display);
} else
wl_display_dispatch(state.display);
int ret = 0;
do {
ret = wl_display_dispatch_pending(state.display);
wl_display_flush(state.display);
} while (ret > 0);
}
if (fds[1].revents & POLLIN) {
ssize_t bytesRead = read(fds[1].fd, readBuf.data(), 1023);
if (bytesRead == -1)
continue;
readBuf[bytesRead] = 0;
parseRequest(state, std::string{readBuf.data()});
}
}
wl_display* display = state.display;
state = {};
wl_display_disconnect(display);
return 0;
}

View file

@ -0,0 +1,180 @@
#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include "../shared.hpp"
#include "tests.hpp"
#include "build.hpp"
#include <hyprutils/os/FileDescriptor.hpp>
#include <hyprutils/os/Process.hpp>
#include <sys/poll.h>
#include <csignal>
#include <thread>
#include <filesystem>
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define SP CSharedPointer
struct SClient {
SP<CProcess> proc;
std::array<char, 1024> readBuf;
CFileDescriptor readFd, writeFd;
struct pollfd fds;
};
static int ret = 0;
static bool startClient(SClient& client) {
Tests::killAllWindows();
client.proc = makeShared<CProcess>(binaryDir + "/shortcut-inhibitor", std::vector<std::string>{});
client.proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
int pipeFds1[2], pipeFds2[2];
if (pipe(pipeFds1) != 0 || pipe(pipeFds2) != 0) {
NLog::log("{}Unable to open pipe to client", Colors::RED);
return false;
}
client.writeFd = CFileDescriptor(pipeFds1[1]);
client.proc->setStdinFD(pipeFds1[0]);
client.readFd = CFileDescriptor(pipeFds2[0]);
client.proc->setStdoutFD(pipeFds2[1]);
const int COUNT_BEFORE = Tests::windowCount();
client.proc->runAsync();
close(pipeFds1[0]);
close(pipeFds2[1]);
client.fds = {.fd = client.readFd.get(), .events = POLLIN};
if (poll(&client.fds, 1, 1000) != 1 || !(client.fds.revents & POLLIN)) {
NLog::log("{}shortcut-inhibitor client failed poll", Colors::RED);
return false;
}
client.readBuf.fill(0);
if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1) {
NLog::log("{}shortcut-inhibitor client read failed", Colors::RED);
return false;
}
std::string ret = std::string{client.readBuf.data()};
if (ret.find("started") == std::string::npos) {
NLog::log("{}Failed to start shortcut-inhibitor client, read {}", Colors::RED, ret);
return false;
}
// wait for window to appear
int counter = 0;
while (Tests::processAlive(client.proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
counter++;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (counter > 50) {
NLog::log("{}shortcut-inhibitor client took too long to open", Colors::RED);
return false;
}
}
if (!Tests::processAlive(client.proc->pid())) {
NLog::log("{}shortcut-inhibitor client not alive", Colors::RED);
return false;
}
if (getFromSocket(std::format("/dispatch focuswindow pid:{}", client.proc->pid())) != "ok") {
NLog::log("{}Failed to focus shortcut-inhibitor client", Colors::RED, ret);
return false;
}
std::string command = "on\n";
if (write(client.writeFd.get(), command.c_str(), command.length()) == -1) {
NLog::log("{}shortcut-inhibitor client write failed", Colors::RED);
return false;
}
client.readBuf.fill(0);
if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1)
return false;
ret = std::string{client.readBuf.data()};
if (ret.find("inhibiting") == std::string::npos) {
NLog::log("{}shortcut-inhibitor client didn't return inhibiting", Colors::RED);
return false;
}
NLog::log("{}Started shortcut-inhibitor client", Colors::YELLOW);
return true;
}
static void stopClient(SClient& client) {
std::string cmd = "off\n";
write(client.writeFd.get(), cmd.c_str(), cmd.length());
kill(client.proc->pid(), SIGKILL);
client.proc.reset();
}
static std::string flagFile = "/tmp/hyprtester-keybinds.txt";
static bool checkFlag() {
bool exists = std::filesystem::exists(flagFile);
std::filesystem::remove(flagFile);
return exists;
}
static bool attemptCheckFlag(int attempts, int intervalMs) {
for (int i = 0; i < attempts; i++) {
if (checkFlag())
return true;
std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs));
}
return false;
}
static bool test() {
SClient client;
if (!startClient(client))
return false;
NLog::log("{}Testing keybinds", Colors::GREEN);
//basic keybind test
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/keyword bind SUPER,Y,exec,touch " + flagFile), "ok");
OK(getFromSocket("/dispatch plugin:test:keybind 1,7,29"));
EXPECT(attemptCheckFlag(20, 50), false);
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
//keybind bypass flag test
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/keyword bindp SUPER,Y,exec,touch " + flagFile), "ok");
OK(getFromSocket("/dispatch plugin:test:keybind 1,7,29"));
EXPECT(attemptCheckFlag(20, 50), true);
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
NLog::log("{}Testing gestures", Colors::GREEN);
//basic gesture test
OK(getFromSocket("/dispatch plugin:test:gesture right,3"));
EXPECT_NOT_CONTAINS(getFromSocket("/activewindow"), "floating: 1");
//gesture bypass flag test
OK(getFromSocket("/dispatch plugin:test:gesture right,2"));
EXPECT_CONTAINS(getFromSocket("/activewindow"), "floating: 1");
stopClient(client);
NLog::log("{}Reloading the config", Colors::YELLOW);
OK(getFromSocket("/reload"));
return !ret;
}
REGISTER_CLIENT_TEST_FN(test);

View file

@ -398,3 +398,5 @@ gesture = 5, left, dispatcher, sendshortcut, , i, activewindow
gesture = 5, right, dispatcher, sendshortcut, , t, activewindow
gesture = 4, right, dispatcher, sendshortcut, , return, activewindow
gesture = 4, left, dispatcher, movecursortocorner, 1
gesturep = 2, right, float

View file

@ -224,6 +224,7 @@ in
${optionalString withTests ''
install hyprtester/pointer-warp -t $out/bin
install hyprtester/pointer-scroll -t $out/bin
install hyprtester/shortcut-inhibitor -t $out/bin
install hyprland_gtests -t $out/bin
install hyprtester/child-window -t $out/bin
''}

View file

@ -868,7 +868,7 @@ CConfigManager::CConfigManager() {
m_config->registerHandler(&::handleSubmap, "submap", {false});
m_config->registerHandler(&::handlePlugin, "plugin", {false});
m_config->registerHandler(&::handlePermission, "permission", {false});
m_config->registerHandler(&::handleGesture, "gesture", {false});
m_config->registerHandler(&::handleGesture, "gesture", {true});
m_config->registerHandler(&::handleEnv, "env", {true});
// pluginza
@ -2845,9 +2845,17 @@ std::optional<std::string> CConfigManager::handleGesture(const std::string& comm
if (direction == TRACKPAD_GESTURE_DIR_NONE)
return std::format("Invalid direction: {}", data[1]);
int startDataIdx = 2;
uint32_t modMask = 0;
float deltaScale = 1.F;
int startDataIdx = 2;
uint32_t modMask = 0;
float deltaScale = 1.F;
bool disableInhibit = false;
for (const auto arg : command.substr(7)) {
switch (arg) {
case 'p': disableInhibit = true; break;
default: return "gesture: invalid flag";
}
}
while (true) {
@ -2870,23 +2878,26 @@ std::optional<std::string> CConfigManager::handleGesture(const std::string& comm
if (data[startDataIdx] == "dispatcher")
result = g_pTrackpadGestures->addGesture(makeUnique<CDispatcherTrackpadGesture>(std::string{data[startDataIdx + 1]}, data.join(",", startDataIdx + 2)), fingerCount,
direction, modMask, deltaScale);
direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "workspace")
result = g_pTrackpadGestures->addGesture(makeUnique<CWorkspaceSwipeGesture>(), fingerCount, direction, modMask, deltaScale);
result = g_pTrackpadGestures->addGesture(makeUnique<CWorkspaceSwipeGesture>(), fingerCount, direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "resize")
result = g_pTrackpadGestures->addGesture(makeUnique<CResizeTrackpadGesture>(), fingerCount, direction, modMask, deltaScale);
result = g_pTrackpadGestures->addGesture(makeUnique<CResizeTrackpadGesture>(), fingerCount, direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "move")
result = g_pTrackpadGestures->addGesture(makeUnique<CMoveTrackpadGesture>(), fingerCount, direction, modMask, deltaScale);
result = g_pTrackpadGestures->addGesture(makeUnique<CMoveTrackpadGesture>(), fingerCount, direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "special")
result = g_pTrackpadGestures->addGesture(makeUnique<CSpecialWorkspaceGesture>(std::string{data[startDataIdx + 1]}), fingerCount, direction, modMask, deltaScale);
result =
g_pTrackpadGestures->addGesture(makeUnique<CSpecialWorkspaceGesture>(std::string{data[startDataIdx + 1]}), fingerCount, direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "close")
result = g_pTrackpadGestures->addGesture(makeUnique<CCloseTrackpadGesture>(), fingerCount, direction, modMask, deltaScale);
result = g_pTrackpadGestures->addGesture(makeUnique<CCloseTrackpadGesture>(), fingerCount, direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "float")
result = g_pTrackpadGestures->addGesture(makeUnique<CFloatTrackpadGesture>(std::string{data[startDataIdx + 1]}), fingerCount, direction, modMask, deltaScale);
result =
g_pTrackpadGestures->addGesture(makeUnique<CFloatTrackpadGesture>(std::string{data[startDataIdx + 1]}), fingerCount, direction, modMask, deltaScale, disableInhibit);
else if (data[startDataIdx] == "fullscreen")
result = g_pTrackpadGestures->addGesture(makeUnique<CFullscreenTrackpadGesture>(std::string{data[startDataIdx + 1]}), fingerCount, direction, modMask, deltaScale);
result = g_pTrackpadGestures->addGesture(makeUnique<CFullscreenTrackpadGesture>(std::string{data[startDataIdx + 1]}), fingerCount, direction, modMask, deltaScale,
disableInhibit);
else if (data[startDataIdx] == "unset")
result = g_pTrackpadGestures->removeGesture(fingerCount, direction, modMask, deltaScale);
result = g_pTrackpadGestures->removeGesture(fingerCount, direction, modMask, deltaScale, disableInhibit);
else
return std::format("Invalid gesture: {}", data[startDataIdx]);

View file

@ -1,6 +1,8 @@
#include "TrackpadGestures.hpp"
#include "../InputManager.hpp"
#include "../../../config/ConfigValue.hpp"
#include "../../../protocols/ShortcutsInhibit.hpp"
#include <ranges>
@ -54,7 +56,7 @@ const char* CTrackpadGestures::stringForDir(eTrackpadGestureDirection dir) {
}
std::expected<void, std::string> CTrackpadGestures::addGesture(UP<ITrackpadGesture>&& gesture, size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask,
float deltaScale) {
float deltaScale, bool disableInhibit) {
for (const auto& g : m_gestures) {
if (g->fingerCount != fingerCount)
continue;
@ -84,14 +86,16 @@ std::expected<void, std::string> CTrackpadGestures::addGesture(UP<ITrackpadGestu
}
}
m_gestures.emplace_back(makeShared<CTrackpadGestures::SGestureData>(std::move(gesture), fingerCount, modMask, direction, deltaScale));
m_gestures.emplace_back(makeShared<CTrackpadGestures::SGestureData>(std::move(gesture), fingerCount, modMask, direction, deltaScale, disableInhibit));
return {};
}
std::expected<void, std::string> CTrackpadGestures::removeGesture(size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale) {
const auto IT = std::ranges::find_if(
m_gestures, [&](const auto& g) { return g->fingerCount == fingerCount && g->direction == direction && g->modMask == modMask && g->deltaScale == deltaScale; });
std::expected<void, std::string> CTrackpadGestures::removeGesture(size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale,
bool disableInhibit) {
const auto IT = std::ranges::find_if(m_gestures, [&](const auto& g) {
return g->fingerCount == fingerCount && g->direction == direction && g->modMask == modMask && g->deltaScale == deltaScale && g->disableInhibit == disableInhibit;
});
if (IT == m_gestures.end())
return std::unexpected("Can't remove a non-existent gesture");
@ -114,6 +118,8 @@ void CTrackpadGestures::gestureBegin(const IPointer::SSwipeBeginEvent& e) {
}
void CTrackpadGestures::gestureUpdate(const IPointer::SSwipeUpdateEvent& e) {
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
if (m_gestureFindFailed)
return;
@ -148,6 +154,9 @@ void CTrackpadGestures::gestureUpdate(const IPointer::SSwipeUpdateEvent& e) {
if (g->modMask != MODS)
continue;
if (PROTO::shortcutsInhibit->isInhibited() && !*PDISABLEINHIBIT && !g->disableInhibit)
continue;
m_activeGesture = g;
g->currentDirection = g->gesture->isDirectionSensitive() ? g->direction : direction;
m_activeGesture->gesture->begin({.swipe = &e, .direction = direction, .scale = g->deltaScale});
@ -184,6 +193,8 @@ void CTrackpadGestures::gestureBegin(const IPointer::SPinchBeginEvent& e) {
}
void CTrackpadGestures::gestureUpdate(const IPointer::SPinchUpdateEvent& e) {
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
if (m_gestureFindFailed)
return;
@ -211,6 +222,9 @@ void CTrackpadGestures::gestureUpdate(const IPointer::SPinchUpdateEvent& e) {
if (g->modMask != MODS)
continue;
if (PROTO::shortcutsInhibit->isInhibited() && !*PDISABLEINHIBIT && !g->disableInhibit)
continue;
m_activeGesture = g;
g->currentDirection = g->gesture->isDirectionSensitive() ? g->direction : direction;
m_activeGesture->gesture->begin({.pinch = &e, .direction = direction});

View file

@ -11,8 +11,9 @@
class CTrackpadGestures {
public:
void clearGestures();
std::expected<void, std::string> addGesture(UP<ITrackpadGesture>&& gesture, size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale);
std::expected<void, std::string> removeGesture(size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale);
std::expected<void, std::string> addGesture(UP<ITrackpadGesture>&& gesture, size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale,
bool disableInhibit);
std::expected<void, std::string> removeGesture(size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale, bool disableInhibit);
void gestureBegin(const IPointer::SSwipeBeginEvent& e);
void gestureUpdate(const IPointer::SSwipeUpdateEvent& e);
@ -32,6 +33,7 @@ class CTrackpadGestures {
uint32_t modMask = 0;
eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE; // configured dir
float deltaScale = 1.F;
bool disableInhibit = false;
eTrackpadGestureDirection currentDirection = TRACKPAD_GESTURE_DIR_NONE; // actual dir of that select swipe
};