From ea42041f936d5810c5cfa45d6bece12dde2fd9b6 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:16:40 -0500 Subject: protocols: implement pointer-warp-v1 (#11469) --- hyprtester/src/tests/clients/pointer-warp.cpp | 180 ++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 hyprtester/src/tests/clients/pointer-warp.cpp (limited to 'hyprtester/src/tests/clients/pointer-warp.cpp') diff --git a/hyprtester/src/tests/clients/pointer-warp.cpp b/hyprtester/src/tests/clients/pointer-warp.cpp new file mode 100644 index 00000000..643da796 --- /dev/null +++ b/hyprtester/src/tests/clients/pointer-warp.cpp @@ -0,0 +1,180 @@ +#include "../../shared.hpp" +#include "../../hyprctlCompat.hpp" +#include "../shared.hpp" +#include "tests.hpp" +#include "build.hpp" + +#include +#include + +#include +#include +#include + +using namespace Hyprutils::OS; +using namespace Hyprutils::Memory; + +#define SP CSharedPointer + +struct SClient { + SP proc; + std::array readBuf; + CFileDescriptor readFd, writeFd; + struct pollfd fds; +}; + +static int ret; + +static bool startClient(SClient& client) { + client.proc = makeShared(binaryDir + "/pointer-warp", std::vector{}); + + 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]); + + 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)) + return false; + + client.readBuf.fill(0); + if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1) + return false; + + std::string ret = std::string{client.readBuf.data()}; + if (ret.find("started") == std::string::npos) { + NLog::log("{}Failed to start pointer-warp client, read {}", Colors::RED, ret); + return false; + } + + // wait for window to appear + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); + + if (getFromSocket(std::format("/dispatch setprop pid:{} noanim 1", client.proc->pid())) != "ok") { + NLog::log("{}Failed to disable animations for client window", Colors::RED, ret); + return false; + } + + if (getFromSocket(std::format("/dispatch focuswindow pid:{}", client.proc->pid())) != "ok") { + NLog::log("{}Failed to focus pointer-warp client", Colors::RED, ret); + return false; + } + + NLog::log("{}Started pointer-warp client", Colors::YELLOW); + + return true; +} + +static void stopClient(SClient& client) { + std::string cmd = "exit\n"; + write(client.writeFd.get(), cmd.c_str(), cmd.length()); + + kill(client.proc->pid(), SIGKILL); + client.proc.reset(); +} + +// format is like below +// "warp 20 20\n" would ask to warp cursor to x=20,y=20 in surface local coords +static bool sendWarp(SClient& client, int x, int y) { + std::string cmd = std::format("warp {} {}\n", x, y); + if ((size_t)write(client.writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length()) + return false; + + if (poll(&client.fds, 1, 1500) != 1 || !(client.fds.revents & POLLIN)) + return false; + ssize_t bytesRead = read(client.fds.fd, client.readBuf.data(), 1023); + if (bytesRead == -1) + return false; + + client.readBuf[bytesRead] = 0; + std::string recieved = std::string{client.readBuf.data()}; + recieved.pop_back(); + + return true; +} + +static bool isCursorPos(int x, int y) { + // TODO: add a better way to do this using test plugin? + std::string res = getFromSocket("/cursorpos"); + if (res == "error") { + NLog::log("{}Cursorpos err'd: {}", Colors::RED, res); + return false; + } + + auto it = res.find_first_of(' '); + if (res.at(it - 1) != ',') { + NLog::log("{}Cursorpos err'd: {}", Colors::RED, res); + return false; + } + + int cursorX = std::stoi(res.substr(0, it - 1)); + int cursorY = std::stoi(res.substr(it + 1)); + + // somehow this is always gives 1 less than surfbox->pos()?? + res = getFromSocket("/activewindow"); + it = res.find("at: ") + 4; + res = res.substr(it, res.find_first_of('\n', it) - it); + + it = res.find_first_of(','); + int clientX = cursorX - std::stoi(res.substr(0, it)) + 1; + int clientY = cursorY - std::stoi(res.substr(it + 1)) + 1; + + return clientX == x && clientY == y; +} + +static bool test() { + SClient client; + + if (!startClient(client)) + return false; + + EXPECT(sendWarp(client, 100, 100), true); + EXPECT(isCursorPos(100, 100), true); + + EXPECT(sendWarp(client, 0, 0), true); + EXPECT(isCursorPos(0, 0), true); + + EXPECT(sendWarp(client, 200, 200), true); + EXPECT(isCursorPos(200, 200), true); + + EXPECT(sendWarp(client, 100, -100), true); + EXPECT(isCursorPos(200, 200), true); + + EXPECT(sendWarp(client, 234, 345), true); + EXPECT(isCursorPos(234, 345), true); + + EXPECT(sendWarp(client, -1, -1), true); + EXPECT(isCursorPos(234, 345), true); + + EXPECT(sendWarp(client, 1, -1), true); + EXPECT(isCursorPos(234, 345), true); + + EXPECT(sendWarp(client, 13, 37), true); + EXPECT(isCursorPos(13, 37), true); + + EXPECT(sendWarp(client, -100, 100), true); + EXPECT(isCursorPos(13, 37), true); + + EXPECT(sendWarp(client, -1, 1), true); + EXPECT(isCursorPos(13, 37), true); + + stopClient(client); + + return true; +} + +REGISTER_CLIENT_TEST_FN(test); -- cgit v1.2.3