mirror of
https://github.com/hyprwm/Hyprland
synced 2025-12-20 05:50:15 +01:00
input: add per-device scroll-factor (#11241)
This commit is contained in:
parent
78e86d879f
commit
127aab8159
16 changed files with 593 additions and 22 deletions
|
|
@ -98,3 +98,4 @@ protocolnew("staging/pointer-warp" "pointer-warp-v1" false)
|
||||||
protocolnew("stable/xdg-shell" "xdg-shell" false)
|
protocolnew("stable/xdg-shell" "xdg-shell" false)
|
||||||
|
|
||||||
clientNew("pointer-warp" PROTOS "pointer-warp-v1" "xdg-shell")
|
clientNew("pointer-warp" PROTOS "pointer-warp-v1" "xdg-shell")
|
||||||
|
clientNew("pointer-scroll" PROTOS "xdg-shell")
|
||||||
|
|
|
||||||
318
hyprtester/clients/pointer-scroll.cpp
Normal file
318
hyprtester/clients/pointer-scroll.cpp
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
#include <cstring>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <print>
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
#include <pointer-warp-v1.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
#include <hyprutils/os/FileDescriptor.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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// last delta
|
||||||
|
float lastScrollDelta = -1.F;
|
||||||
|
bool writeDelta = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::ofstream logfile;
|
||||||
|
|
||||||
|
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);
|
||||||
|
logfile << text << std::endl;
|
||||||
|
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...));
|
||||||
|
logfile << text << std::endl;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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) {
|
||||||
|
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-pointer-scroll";
|
||||||
|
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("pointer-scroll test client");
|
||||||
|
state.xdgToplevel->sendSetAppId("pointer-scroll");
|
||||||
|
|
||||||
|
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->setAxis([&](CCWlPointer* p, uint32_t time, wl_pointer_axis axis, wl_fixed_t delta) {
|
||||||
|
debugLog("axis: ax {} delta {}", (int)axis, wl_fixed_to_double(delta));
|
||||||
|
|
||||||
|
if (state.writeDelta) {
|
||||||
|
clientLog("{:.2f}", wl_fixed_to_double(delta));
|
||||||
|
state.writeDelta = false;
|
||||||
|
state.lastScrollDelta = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.lastScrollDelta = wl_fixed_to_double(delta);
|
||||||
|
state.writeDelta = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return last delta after axis
|
||||||
|
static void parseRequest(SWlState& state, std::string req) {
|
||||||
|
if (!state.writeDelta) {
|
||||||
|
state.writeDelta = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientLog("{:.2f}", state.lastScrollDelta);
|
||||||
|
state.writeDelta = false;
|
||||||
|
state.lastScrollDelta = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
logfile.open("pointer-scroll.txt", std::ios::trunc);
|
||||||
|
|
||||||
|
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);
|
||||||
|
logfile.flush();
|
||||||
|
logfile.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <src/layout/IHyprLayout.hpp>
|
#include <src/layout/IHyprLayout.hpp>
|
||||||
#include <src/managers/LayoutManager.hpp>
|
#include <src/managers/LayoutManager.hpp>
|
||||||
#include <src/managers/input/InputManager.hpp>
|
#include <src/managers/input/InputManager.hpp>
|
||||||
|
#include <src/managers/PointerManager.hpp>
|
||||||
#include <src/managers/input/trackpad/TrackpadGestures.hpp>
|
#include <src/managers/input/trackpad/TrackpadGestures.hpp>
|
||||||
#include <src/Compositor.hpp>
|
#include <src/Compositor.hpp>
|
||||||
#undef private
|
#undef private
|
||||||
|
|
@ -88,9 +89,38 @@ class CTestKeyboard : public IKeyboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_isVirtual;
|
bool m_isVirtual = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CTestMouse : public IPointer {
|
||||||
|
public:
|
||||||
|
static SP<CTestMouse> create(bool isVirtual) {
|
||||||
|
auto maus = SP<CTestMouse>(new CTestMouse());
|
||||||
|
maus->m_self = maus;
|
||||||
|
maus->m_isVirtual = isVirtual;
|
||||||
|
maus->m_deviceName = "test-mouse";
|
||||||
|
maus->m_hlName = "test-mouse";
|
||||||
|
return maus;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isVirtual() {
|
||||||
|
return m_isVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SP<Aquamarine::IPointer> aq() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
m_events.destroy.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isVirtual = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
SP<CTestMouse> g_mouse;
|
||||||
|
|
||||||
static SDispatchResult pressAlt(std::string in) {
|
static SDispatchResult pressAlt(std::string in) {
|
||||||
g_pInputManager->m_lastMods = in == "1" ? HL_MODIFIER_ALT : 0;
|
g_pInputManager->m_lastMods = in == "1" ? HL_MODIFIER_ALT : 0;
|
||||||
|
|
||||||
|
|
@ -173,6 +203,23 @@ static SDispatchResult vkb(std::string in) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDispatchResult scroll(std::string in) {
|
||||||
|
int by;
|
||||||
|
try {
|
||||||
|
by = std::stoi(in);
|
||||||
|
} catch (...) { return SDispatchResult{.success = false, .error = "invalid input"}; }
|
||||||
|
|
||||||
|
Debug::log(LOG, "tester: scrolling by {}", by);
|
||||||
|
|
||||||
|
g_mouse->m_pointerEvents.axis.emit(IPointer::SAxisEvent{
|
||||||
|
.delta = by,
|
||||||
|
.deltaDiscrete = 120,
|
||||||
|
.mouse = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
PHANDLE = handle;
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
|
@ -181,10 +228,16 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:vkb", ::vkb);
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:vkb", ::vkb);
|
||||||
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:alt", ::pressAlt);
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:alt", ::pressAlt);
|
||||||
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:gesture", ::simulateGesture);
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:gesture", ::simulateGesture);
|
||||||
|
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:scroll", ::scroll);
|
||||||
|
|
||||||
|
// init mouse
|
||||||
|
g_mouse = CTestMouse::create(false);
|
||||||
|
g_pInputManager->newMouse(g_mouse);
|
||||||
|
|
||||||
return {"hyprtestplugin", "hyprtestplugin", "Vaxry", "1.0"};
|
return {"hyprtestplugin", "hyprtestplugin", "Vaxry", "1.0"};
|
||||||
}
|
}
|
||||||
|
|
||||||
APICALL EXPORT void PLUGIN_EXIT() {
|
APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
;
|
g_mouse->destroy();
|
||||||
|
g_mouse.reset();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
145
hyprtester/src/tests/clients/pointer-scroll.cpp
Normal file
145
hyprtester/src/tests/clients/pointer-scroll.cpp
Normal file
|
|
@ -0,0 +1,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:{} 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-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 scrollmouse 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);
|
||||||
|
|
@ -23,7 +23,7 @@ struct SClient {
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ret;
|
static int ret = 0;
|
||||||
|
|
||||||
static bool startClient(SClient& client) {
|
static bool startClient(SClient& client) {
|
||||||
client.proc = makeShared<CProcess>(binaryDir + "/pointer-warp", std::vector<std::string>{});
|
client.proc = makeShared<CProcess>(binaryDir + "/pointer-warp", std::vector<std::string>{});
|
||||||
|
|
@ -174,7 +174,10 @@ static bool test() {
|
||||||
|
|
||||||
stopClient(client);
|
stopClient(client);
|
||||||
|
|
||||||
return true;
|
NLog::log("{}Reloading the config", Colors::YELLOW);
|
||||||
|
OK(getFromSocket("/reload"));
|
||||||
|
|
||||||
|
return !ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_CLIENT_TEST_FN(test);
|
REGISTER_CLIENT_TEST_FN(test);
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,11 @@ animations {
|
||||||
animation = workspacesOut, 1, 1.94, almostLinear, fade
|
animation = workspacesOut, 1, 1.94, almostLinear, fade
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device {
|
||||||
|
name = test-mouse-1
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
|
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
|
||||||
# "Smart gaps" / "No gaps when only"
|
# "Smart gaps" / "No gaps when only"
|
||||||
# uncomment all if you wish to use that.
|
# uncomment all if you wish to use that.
|
||||||
|
|
@ -213,6 +218,10 @@ device {
|
||||||
sensitivity = -0.5
|
sensitivity = -0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug {
|
||||||
|
disable_logs = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
### KEYBINDINGS ###
|
### KEYBINDINGS ###
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ in
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
install pointer-warp -t $out/bin
|
install pointer-warp -t $out/bin
|
||||||
|
install pointer-scroll -t $out/bin
|
||||||
'';
|
'';
|
||||||
|
|
||||||
cmakeBuildType = "Debug";
|
cmakeBuildType = "Debug";
|
||||||
|
|
|
||||||
|
|
@ -810,6 +810,7 @@ CConfigManager::CConfigManager() {
|
||||||
m_config->addSpecialConfigValue("device", "scroll_button", Hyprlang::INT{0});
|
m_config->addSpecialConfigValue("device", "scroll_button", Hyprlang::INT{0});
|
||||||
m_config->addSpecialConfigValue("device", "scroll_button_lock", Hyprlang::INT{0});
|
m_config->addSpecialConfigValue("device", "scroll_button_lock", Hyprlang::INT{0});
|
||||||
m_config->addSpecialConfigValue("device", "scroll_points", {STRVAL_EMPTY});
|
m_config->addSpecialConfigValue("device", "scroll_points", {STRVAL_EMPTY});
|
||||||
|
m_config->addSpecialConfigValue("device", "scroll_factor", Hyprlang::FLOAT{-1});
|
||||||
m_config->addSpecialConfigValue("device", "transform", Hyprlang::INT{-1});
|
m_config->addSpecialConfigValue("device", "transform", Hyprlang::INT{-1});
|
||||||
m_config->addSpecialConfigValue("device", "output", {STRVAL_EMPTY});
|
m_config->addSpecialConfigValue("device", "output", {STRVAL_EMPTY});
|
||||||
m_config->addSpecialConfigValue("device", "enabled", Hyprlang::INT{1}); // only for mice, touchpads, and touchdevices
|
m_config->addSpecialConfigValue("device", "enabled", Hyprlang::INT{1}); // only for mice, touchpads, and touchdevices
|
||||||
|
|
@ -1335,13 +1336,18 @@ Hyprlang::CConfigValue* CConfigManager::getConfigValueSafeDevice(const std::stri
|
||||||
|
|
||||||
const auto VAL = m_config->getSpecialConfigValuePtr("device", val.c_str(), dev.c_str());
|
const auto VAL = m_config->getSpecialConfigValuePtr("device", val.c_str(), dev.c_str());
|
||||||
|
|
||||||
if ((!VAL || !VAL->m_bSetByUser) && !fallback.empty()) {
|
if ((!VAL || !VAL->m_bSetByUser) && !fallback.empty())
|
||||||
return m_config->getConfigValuePtr(fallback.c_str());
|
return m_config->getConfigValuePtr(fallback.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
return VAL;
|
return VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CConfigManager::deviceConfigExplicitlySet(const std::string& dev, const std::string& val) {
|
||||||
|
const auto VAL = m_config->getSpecialConfigValuePtr("device", val.c_str(), dev.c_str());
|
||||||
|
|
||||||
|
return VAL && VAL->m_bSetByUser;
|
||||||
|
}
|
||||||
|
|
||||||
int CConfigManager::getDeviceInt(const std::string& dev, const std::string& v, const std::string& fallback) {
|
int CConfigManager::getDeviceInt(const std::string& dev, const std::string& v, const std::string& fallback) {
|
||||||
return std::any_cast<Hyprlang::INT>(getConfigValueSafeDevice(dev, v, fallback)->getValue());
|
return std::any_cast<Hyprlang::INT>(getConfigValueSafeDevice(dev, v, fallback)->getValue());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,7 @@ class CConfigManager {
|
||||||
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
|
bool deviceConfigExplicitlySet(const std::string&, const std::string&);
|
||||||
bool deviceConfigExists(const std::string&);
|
bool deviceConfigExists(const std::string&);
|
||||||
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
|
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
|
||||||
bool shouldBlurLS(const std::string&);
|
bool shouldBlurLS(const std::string&);
|
||||||
|
|
|
||||||
|
|
@ -722,10 +722,11 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
|
||||||
R"#( {{
|
R"#( {{
|
||||||
"address": "0x{:x}",
|
"address": "0x{:x}",
|
||||||
"name": "{}",
|
"name": "{}",
|
||||||
"defaultSpeed": {:.5f}
|
"defaultSpeed": {:.5f},
|
||||||
|
"scrollFactor": {:.2f}
|
||||||
}},)#",
|
}},)#",
|
||||||
rc<uintptr_t>(m.get()), escapeJSONStrings(m->m_hlName),
|
rc<uintptr_t>(m.get()), escapeJSONStrings(m->m_hlName),
|
||||||
m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f);
|
m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f, m->m_scrollFactor.value_or(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
trimTrailingComma(result);
|
trimTrailingComma(result);
|
||||||
|
|
@ -826,8 +827,9 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
|
||||||
result += "mice:\n";
|
result += "mice:\n";
|
||||||
|
|
||||||
for (auto const& m : g_pInputManager->m_pointers) {
|
for (auto const& m : g_pInputManager->m_pointers) {
|
||||||
result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", rc<uintptr_t>(m.get()), m->m_hlName,
|
result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n\t\t\tscroll factor: {:.2f}\n", rc<uintptr_t>(m.get()), m->m_hlName,
|
||||||
(m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f));
|
(m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f),
|
||||||
|
m->m_scrollFactor.value_or(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
result += "\n\nKeyboards:\n";
|
result += "\n\nKeyboards:\n";
|
||||||
|
|
|
||||||
|
|
@ -1249,6 +1249,14 @@ float CWindow::getScrollTouchpad() {
|
||||||
return m_windowData.scrollTouchpad.valueOr(*PTOUCHPADSCROLLFACTOR);
|
return m_windowData.scrollTouchpad.valueOr(*PTOUCHPADSCROLLFACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWindow::isScrollMouseOverridden() {
|
||||||
|
return m_windowData.scrollMouse.hasValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWindow::isScrollTouchpadOverridden() {
|
||||||
|
return m_windowData.scrollTouchpad.hasValue();
|
||||||
|
}
|
||||||
|
|
||||||
bool CWindow::canBeTorn() {
|
bool CWindow::canBeTorn() {
|
||||||
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
|
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
|
||||||
return m_windowData.tearing.valueOr(m_tearingHint) && *PTEARING;
|
return m_windowData.tearing.valueOr(m_tearingHint) && *PTEARING;
|
||||||
|
|
|
||||||
|
|
@ -363,6 +363,8 @@ class CWindow {
|
||||||
int getRealBorderSize();
|
int getRealBorderSize();
|
||||||
float getScrollMouse();
|
float getScrollMouse();
|
||||||
float getScrollTouchpad();
|
float getScrollTouchpad();
|
||||||
|
bool isScrollMouseOverridden();
|
||||||
|
bool isScrollTouchpadOverridden();
|
||||||
void updateWindowData();
|
void updateWindowData();
|
||||||
void updateWindowData(const struct SWorkspaceRule&);
|
void updateWindowData(const struct SWorkspaceRule&);
|
||||||
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
|
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
|
||||||
|
|
|
||||||
|
|
@ -108,11 +108,12 @@ class IPointer : public IHID {
|
||||||
CSignalT<SHoldEndEvent> holdEnd;
|
CSignalT<SHoldEndEvent> holdEnd;
|
||||||
} m_pointerEvents;
|
} m_pointerEvents;
|
||||||
|
|
||||||
bool m_connected = false; // means connected to the cursor
|
bool m_connected = false; // means connected to the cursor
|
||||||
std::string m_boundOutput = "";
|
std::string m_boundOutput = "";
|
||||||
bool m_flipX = false; // decide to invert horizontal movement
|
bool m_flipX = false; // decide to invert horizontal movement
|
||||||
bool m_flipY = false; // decide to invert vertical movement
|
bool m_flipY = false; // decide to invert vertical movement
|
||||||
bool m_isTouchpad = false;
|
bool m_isTouchpad = false;
|
||||||
|
std::optional<float> m_scrollFactor = {};
|
||||||
|
|
||||||
WP<IPointer> m_self;
|
WP<IPointer> m_self;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -919,8 +919,8 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||||
PROTO::idle->onActivity();
|
PROTO::idle->onActivity();
|
||||||
});
|
});
|
||||||
|
|
||||||
listener->axis = pointer->m_pointerEvents.axis.listen([](const IPointer::SAxisEvent& event) {
|
listener->axis = pointer->m_pointerEvents.axis.listen([weak = WP<IPointer>(pointer)](const IPointer::SAxisEvent& event) {
|
||||||
g_pInputManager->onMouseWheel(event);
|
g_pInputManager->onMouseWheel(event, weak.lock());
|
||||||
PROTO::idle->onActivity();
|
PROTO::idle->onActivity();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -835,7 +835,7 @@ void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) {
|
||||||
m_clickBehavior = CLICKMODE_DEFAULT;
|
m_clickBehavior = CLICKMODE_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
|
void CInputManager::onMouseWheel(IPointer::SAxisEvent e, SP<IPointer> pointer) {
|
||||||
static auto POFFWINDOWAXIS = CConfigValue<Hyprlang::INT>("input:off_window_axis_events");
|
static auto POFFWINDOWAXIS = CConfigValue<Hyprlang::INT>("input:off_window_axis_events");
|
||||||
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
|
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
|
||||||
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
|
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
|
||||||
|
|
@ -845,7 +845,10 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
|
||||||
const bool ISTOUCHPADSCROLL = *PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER;
|
const bool ISTOUCHPADSCROLL = *PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER;
|
||||||
auto factor = ISTOUCHPADSCROLL ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR;
|
auto factor = ISTOUCHPADSCROLL ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR;
|
||||||
|
|
||||||
const auto EMAP = std::unordered_map<std::string, std::any>{{"event", e}};
|
if (pointer && pointer->m_scrollFactor.has_value())
|
||||||
|
factor = *pointer->m_scrollFactor;
|
||||||
|
|
||||||
|
const auto EMAP = std::unordered_map<std::string, std::any>{{"event", e}};
|
||||||
EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP);
|
EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP);
|
||||||
|
|
||||||
if (e.mouse)
|
if (e.mouse)
|
||||||
|
|
@ -888,7 +891,11 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
|
||||||
if (*PFOLLOWMOUSE == 1 && PCURRWINDOW && PWINDOW != PCURRWINDOW)
|
if (*PFOLLOWMOUSE == 1 && PCURRWINDOW && PWINDOW != PCURRWINDOW)
|
||||||
simulateMouseMovement();
|
simulateMouseMovement();
|
||||||
}
|
}
|
||||||
factor = ISTOUCHPADSCROLL ? PWINDOW->getScrollTouchpad() : PWINDOW->getScrollMouse();
|
|
||||||
|
if (!ISTOUCHPADSCROLL && PWINDOW->isScrollMouseOverridden())
|
||||||
|
factor = PWINDOW->getScrollMouse();
|
||||||
|
else if (ISTOUCHPADSCROLL && PWINDOW->isScrollTouchpadOverridden())
|
||||||
|
factor = PWINDOW->getScrollTouchpad();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1117,6 +1124,14 @@ void CInputManager::newVirtualMouse(SP<CVirtualPointerV1Resource> mouse) {
|
||||||
Debug::log(LOG, "New virtual mouse created");
|
Debug::log(LOG, "New virtual mouse created");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CInputManager::newMouse(SP<IPointer> mouse) {
|
||||||
|
m_pointers.emplace_back(mouse);
|
||||||
|
|
||||||
|
setupMouse(mouse);
|
||||||
|
|
||||||
|
Debug::log(LOG, "New mouse created, pointer Hypr: {:x}", rc<uintptr_t>(mouse.get()));
|
||||||
|
}
|
||||||
|
|
||||||
void CInputManager::newMouse(SP<Aquamarine::IPointer> mouse) {
|
void CInputManager::newMouse(SP<Aquamarine::IPointer> mouse) {
|
||||||
const auto PMOUSE = m_pointers.emplace_back(CMouse::create(mouse));
|
const auto PMOUSE = m_pointers.emplace_back(CMouse::create(mouse));
|
||||||
|
|
||||||
|
|
@ -1172,6 +1187,11 @@ void CInputManager::setPointerConfigs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_pConfigManager->deviceConfigExplicitlySet(devname, "scroll_factor"))
|
||||||
|
m->m_scrollFactor = std::clamp(g_pConfigManager->getDeviceFloat(devname, "scroll_factor", "input:scroll_factor"), 0.F, 100.F);
|
||||||
|
else
|
||||||
|
m->m_scrollFactor = std::nullopt;
|
||||||
|
|
||||||
if (m->aq() && m->aq()->getLibinputHandle()) {
|
if (m->aq() && m->aq()->getLibinputHandle()) {
|
||||||
const auto LIBINPUTDEV = m->aq()->getLibinputHandle();
|
const auto LIBINPUTDEV = m->aq()->getLibinputHandle();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,13 +90,14 @@ class CInputManager {
|
||||||
void onMouseMoved(IPointer::SMotionEvent);
|
void onMouseMoved(IPointer::SMotionEvent);
|
||||||
void onMouseWarp(IPointer::SMotionAbsoluteEvent);
|
void onMouseWarp(IPointer::SMotionAbsoluteEvent);
|
||||||
void onMouseButton(IPointer::SButtonEvent);
|
void onMouseButton(IPointer::SButtonEvent);
|
||||||
void onMouseWheel(IPointer::SAxisEvent);
|
void onMouseWheel(IPointer::SAxisEvent, SP<IPointer> pointer = nullptr);
|
||||||
void onKeyboardKey(const IKeyboard::SKeyEvent&, SP<IKeyboard>);
|
void onKeyboardKey(const IKeyboard::SKeyEvent&, SP<IKeyboard>);
|
||||||
void onKeyboardMod(SP<IKeyboard>);
|
void onKeyboardMod(SP<IKeyboard>);
|
||||||
|
|
||||||
void newKeyboard(SP<IKeyboard>);
|
void newKeyboard(SP<IKeyboard>);
|
||||||
void newKeyboard(SP<Aquamarine::IKeyboard>);
|
void newKeyboard(SP<Aquamarine::IKeyboard>);
|
||||||
void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>);
|
void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>);
|
||||||
|
void newMouse(SP<IPointer>);
|
||||||
void newMouse(SP<Aquamarine::IPointer>);
|
void newMouse(SP<Aquamarine::IPointer>);
|
||||||
void newVirtualMouse(SP<CVirtualPointerV1Resource>);
|
void newVirtualMouse(SP<CVirtualPointerV1Resource>);
|
||||||
void newTouchDevice(SP<Aquamarine::ITouch>);
|
void newTouchDevice(SP<Aquamarine::ITouch>);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue