summaryrefslogtreecommitdiff
path: root/hyprtester/src/tests/clients/pointer-scroll.cpp
blob: 2ea93a14cbc10fc712322947208f4efdaf2281cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#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>

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) {
    client.proc = makeShared<CProcess>(binaryDir + "/pointer-scroll", 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]);

    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-scroll 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:{} no_anim 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-scroll client", Colors::RED, ret);
        return false;
    }

    NLog::log("{}Started pointer-scroll 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();
}

static int getLastDelta(SClient& client) {
    std::string cmd = "hypr";
    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 received      = std::string{client.readBuf.data()};
    received.pop_back();

    try {
        return std::stoi(received);
    } catch (...) { return -1; }
}

static bool sendScroll(int delta) {
    return getFromSocket(std::format("/dispatch plugin:test:scroll {}", delta)) == "ok";
}

static bool test() {
    SClient client;

    if (!startClient(client))
        return false;

    EXPECT(getFromSocket("/keyword input:emulate_discrete_scroll 0"), "ok");

    EXPECT(sendScroll(10), true);
    EXPECT(getLastDelta(client), 10);

    EXPECT(getFromSocket("/keyword input:scroll_factor 2"), "ok");
    EXPECT(sendScroll(10), true);
    EXPECT(getLastDelta(client), 20);

    EXPECT(getFromSocket("r/keyword device[test-mouse-1]:scroll_factor 3"), "ok");
    EXPECT(sendScroll(10), true);
    EXPECT(getLastDelta(client), 30);

    EXPECT(getFromSocket("r/dispatch setprop active scroll_mouse 4"), "ok");
    EXPECT(sendScroll(10), true);
    EXPECT(getLastDelta(client), 40);

    stopClient(client);

    NLog::log("{}Reloading the config", Colors::YELLOW);
    OK(getFromSocket("/reload"));

    return !ret;
}

REGISTER_CLIENT_TEST_FN(test);