Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions hyprtester/plugin/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
#include <src/includes.hpp>
#include <sstream>
#include <any>
#include <cmath>

#define private public
#include <src/managers/input/InputManager.hpp>
#include <src/managers/PointerManager.hpp>
#include <src/managers/input/trackpad/TrackpadGestures.hpp>
#include <src/helpers/Monitor.hpp>
#include <src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp>
#include <src/desktop/rule/layerRule/LayerRuleEffectContainer.hpp>
#include <src/desktop/rule/windowRule/WindowRuleApplicator.hpp>
Expand All @@ -17,6 +19,7 @@
#undef private

#include <hyprutils/utils/ScopeGuard.hpp>
#include <hyprutils/string/Numeric.hpp>
#include <hyprutils/string/VarList.hpp>
using namespace Hyprutils::Utils;
using namespace Hyprutils::String;
Expand Down Expand Up @@ -156,6 +159,96 @@ static SDispatchResult simulateGesture(std::string in) {
return {.success = true};
}

static SDispatchResult pinchUpdate(std::string in) {
CVarList data(in);
uint32_t fingers = 2;
double scale = 1.0;
Vector2D delta = {};
double rotation{};

if (data.size() < 2)
return {.success = false, .error = "invalid input"};

if (const auto n = strToNumber<uint32_t>(data[0]); n)
fingers = n.value();
else
return {.success = false, .error = "invalid input"};

if (const auto n = strToNumber<double>(data[1]); n)
scale = n.value();
else
return {.success = false, .error = "invalid input"};

if (data.size() > 2) {
if (const auto n = strToNumber<double>(data[2]); n)
delta.x = n.value();
else
return {.success = false, .error = "invalid input"};
}

if (data.size() > 3) {
if (const auto n = strToNumber<double>(data[3]); n)
delta.y = n.value();
else
return {.success = false, .error = "invalid input"};
}

if (data.size() > 4) {
if (const auto n = strToNumber<double>(data[4]); n)
rotation = n.value();
else
return {.success = false, .error = "invalid input"};
}

g_pTrackpadGestures->gestureUpdate(IPointer::SPinchUpdateEvent{
.fingers = fingers,
.delta = delta,
.scale = scale,
.rotation = rotation,
});

return {};
}

static SDispatchResult pinchEnd(std::string in) {
g_pTrackpadGestures->gestureEnd(IPointer::SPinchEndEvent{});

return {};
}

static SDispatchResult expectCursorZoom(std::string in) {
CVarList data(in);
float expected = 1.F;
float delta = 0.01F;

if (data.size() < 1)
return {.success = false, .error = "invalid input"};

if (const auto n = strToNumber<float>(data[0]); n)
expected = n.value();
else
return {.success = false, .error = "invalid input"};

if (data.size() > 1) {
if (const auto n = strToNumber<float>(data[1]); n)
delta = n.value();
else
return {.success = false, .error = "invalid input"};
}

const auto PMONITOR = g_pCompositor->getMonitorFromVector(g_pInputManager->getMouseCoordsInternal());

if (!PMONITOR)
return {.success = false, .error = "No monitor under cursor"};

const auto actual = PMONITOR->m_cursorZoom->value();

if (std::abs(actual - expected) > delta)
return {.success = false, .error = std::format("Expected cursor zoom {} ± {}, got {}", expected, delta, actual)};

return {};
}

static SDispatchResult vkb(std::string in) {
auto tkb0 = CTestKeyboard::create(false);
auto tkb1 = CTestKeyboard::create(false);
Expand Down Expand Up @@ -375,6 +468,32 @@ static int luaGesture(lua_State* L) {
return luaResult(L, ::simulateGesture(std::format("{},{}", direction, fingers)));
}

static int luaPinchUpdate(lua_State* L) {
std::string in = std::format("{},{}", (int)luaL_checkinteger(L, 1), (double)luaL_checknumber(L, 2));

if (lua_gettop(L) > 2)
in += std::format(",{}", (double)luaL_checknumber(L, 3));
if (lua_gettop(L) > 3)
in += std::format(",{}", (double)luaL_checknumber(L, 4));
if (lua_gettop(L) > 4)
in += std::format(",{}", (double)luaL_checknumber(L, 5));

return luaResult(L, ::pinchUpdate(in));
}

static int luaPinchEnd(lua_State* L) {
return luaResult(L, ::pinchEnd(""));
}

static int luaExpectCursorZoom(lua_State* L) {
const auto expected = (double)luaL_checknumber(L, 1);

if (lua_gettop(L) > 1)
return luaResult(L, ::expectCursorZoom(std::format("{},{}", expected, (double)luaL_checknumber(L, 2))));

return luaResult(L, ::expectCursorZoom(std::format("{}", expected)));
}

static int luaScroll(lua_State* L) {
return luaResult(L, ::scroll(std::to_string((double)luaL_checknumber(L, 1))));
}
Expand Down Expand Up @@ -425,6 +544,9 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
addLuaFn("vkb", ::luaVkb);
addLuaFn("alt", ::luaAlt);
addLuaFn("gesture", ::luaGesture);
addLuaFn("pinch_update", ::luaPinchUpdate);
addLuaFn("pinch_end", ::luaPinchEnd);
addLuaFn("expect_cursor_zoom", ::luaExpectCursorZoom);
addLuaFn("scroll", ::luaScroll);
addLuaFn("click", ::luaClick);
addLuaFn("keybind", ::luaKeybind);
Expand Down
38 changes: 38 additions & 0 deletions hyprtester/src/tests/main/gestures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
#include <chrono>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
#include <hyprutils/string/Numeric.hpp>
#include <csignal>
#include <cerrno>
#include "../shared.hpp"

using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
using namespace Hyprutils::String;

#define UP CUniquePointer
#define SP CSharedPointer
Expand Down Expand Up @@ -178,4 +180,40 @@ TEST_CASE(gestures) {

OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
}
const std::string cursorPosBeforePinch = getFromSocket("/cursorpos");

OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 500, y = 500 })"));
OK(getFromSocket("/eval hl.config({ cursor = { zoom_factor = 1 } })"));
OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1, 0.01)"));

OK(getFromSocket("/eval hl.plugin.test.pinch_update(2, 1.2)"));
OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1.2, 0.01)"));
OK(getFromSocket("/eval hl.plugin.test.pinch_update(2, 1.6)"));
OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1.6, 0.01)"));
OK(getFromSocket("/eval hl.plugin.test.pinch_end()"));
OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1.6, 0.01)"));

OK(getFromSocket("/eval hl.plugin.test.pinch_update(2, 0.64)"));
OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1, 0.01)"));
OK(getFromSocket("/eval hl.plugin.test.pinch_end()"));
OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1, 0.01)"));

const auto comma = cursorPosBeforePinch.find(',');

if (comma != std::string::npos) {
auto xSv = std::string_view(cursorPosBeforePinch).substr(0, comma);
auto ySv = std::string_view(cursorPosBeforePinch).substr(comma + 1);
while (!xSv.empty() && xSv.front() == ' ')
xSv.remove_prefix(1);
while (!ySv.empty() && ySv.front() == ' ')
ySv.remove_prefix(1);

const auto x = strToNumber<int>(xSv);
const auto y = strToNumber<int>(ySv);

if (!x || !y)
FAIL_TEST("Failed to restore cursor pos");

OK(getFromSocket(std::format("/dispatch hl.dsp.cursor.move({{ x = {}, y = {} }})", x.value(), y.value())));
}
}
2 changes: 2 additions & 0 deletions hyprtester/src/tests/main/groups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ TEST_CASE(groups) {

NLog::log("{}Disable autogrouping", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ group = { auto_group = false } })"));
OK(getFromSocket("/eval hl.config({ dwindle = { force_split = 2 } })"));
Comment thread
vaxerski marked this conversation as resolved.

NLog::log("{}Spawn kittyProcC", Colors::YELLOW);
auto kittyProcC = Tests::spawnKitty();
Expand All @@ -206,6 +207,7 @@ TEST_CASE(groups) {
EXPECT_COUNT_STRING(str, "at: 22,22", 2);
}

OK(getFromSocket("/eval hl.config({ dwindle = { force_split = 0 } })"));
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'left' })"));
OK(getFromSocket("/dispatch hl.dsp.group.active({ index = 1 })"));
OK(getFromSocket("/eval hl.config({ group = { auto_group = true } })"));
Expand Down
1 change: 1 addition & 0 deletions hyprtester/test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,6 @@ hl.gesture({ fingers = 5, direction = "left", action = function() hl.dispatch(hl
hl.gesture({ fingers = 5, direction = "right", action = function() hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "t", window = "activewindow" })) end })
hl.gesture({ fingers = 4, direction = "right", action = function() hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "return", window = "activewindow" })) end })
hl.gesture({ fingers = 4, direction = "left", action = function() hl.dispatch(hl.dsp.cursor.move_to_corner({ corner = 1, window = "activewindow" })) end })
hl.gesture({ fingers = 2, direction = "pinch", action = "cursorZoom", zoom_level = "1", mode = "live" })

hl.gesture({ fingers = 2, direction = "right", action = "float", disable_inhibit = true })
21 changes: 18 additions & 3 deletions src/helpers/MonitorZoomController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,27 @@
#include "desktop/DesktopTypes.hpp"
#include "render/Renderer.hpp"

void CMonitorZoomController::pinAnchor(const Vector2D& anchor) {
m_pinnedAnchor = anchor;
m_anchorPinned = true;
}

void CMonitorZoomController::clearAnchor() {
m_anchorPinned = false;
}

Vector2D CMonitorZoomController::getAnchor(const PHLMONITORREF& monitor) {
if (m_anchorPinned)
return m_pinnedAnchor;

return g_pInputManager->getMouseCoordsInternal() - monitor->m_position;
}

void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData) {
const auto m = m_renderData.pMonitor;
auto monbox = CBox(0, 0, m->m_size.x, m->m_size.y);
const auto ZOOM = g_pHyprRenderer->m_renderData.mouseZoomFactor;
const auto MOUSE = g_pInputManager->getMouseCoordsInternal() - m->m_position;
const auto MOUSE = getAnchor(m);

if (m_lastZoomLevel != ZOOM) {
if (m_resetCameraState) {
Expand Down Expand Up @@ -83,8 +99,7 @@ void CMonitorZoomController::applyZoomTransform(CBox& monbox, const Render::SRen
if (*PZOOMDETACHEDCAMERA && !INITANIM)
zoomWithDetachedCamera(monbox, m_renderData);
else {
const auto ZOOMCENTER =
g_pHyprRenderer->m_renderData.mouseZoomUseMouse ? (g_pInputManager->getMouseCoordsInternal() - m->m_position) * m->m_scale : m->m_transformedSize / 2.f;
const auto ZOOMCENTER = g_pHyprRenderer->m_renderData.mouseZoomUseMouse ? getAnchor(m) * m->m_scale : m->m_transformedSize / 2.f;

monbox.translate(-ZOOMCENTER).scale(ZOOM).translate(*PZOOMRIGID ? m->m_transformedSize / 2.0 : ZOOMCENTER);
}
Expand Down
15 changes: 11 additions & 4 deletions src/helpers/MonitorZoomController.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "./math/Math.hpp"
#include "../desktop/DesktopTypes.hpp"

namespace Render {
struct SRenderData;
Expand All @@ -10,12 +11,18 @@ class CMonitorZoomController {
public:
bool m_resetCameraState = true;

void pinAnchor(const Vector2D& anchor);
void clearAnchor();

void applyZoomTransform(CBox& monbox, const Render::SRenderData& m_renderData);

private:
void zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData);
void zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData);
Vector2D getAnchor(const PHLMONITORREF& monitor);

CBox m_camera;
float m_lastZoomLevel = 1.0f;
bool m_padCamEdges = true;
CBox m_camera;
Vector2D m_pinnedAnchor = {};
float m_lastZoomLevel = 1.0f;
bool m_padCamEdges = true;
bool m_anchorPinned = false;
};
57 changes: 52 additions & 5 deletions src/managers/input/trackpad/gestures/CursorZoomGesture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,40 @@

#include "../../../../Compositor.hpp"
#include "../../../../helpers/Monitor.hpp"
#include "../../../../managers/input/InputManager.hpp"
#include <hyprutils/string/Numeric.hpp>

CCursorZoomTrackpadGesture::CCursorZoomTrackpadGesture(const std::string& first, const std::string& second) {
try {
m_zoomValue = std::stof(first);
} catch (...) { ; }
if (const auto n = Hyprutils::String::strToNumber<float>(first); n)
m_zoomValue = n.value();

if (second == "mult")
m_mode = MODE_MULT;
else if (second == "live")
m_mode = MODE_LIVE;
}

void CCursorZoomTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) {
ITrackpadGesture::begin(e);

if (m_mode == MODE_LIVE) {
if (!e.pinch)
return;

m_monitor = g_pCompositor->getMonitorFromCursor();
if (!m_monitor)
return;

const auto PMONITOR = m_monitor.lock();
if (!PMONITOR)
return;

m_zoomBegin = std::clamp(PMONITOR->m_cursorZoom->value(), 1.0F, 100.0F);
PMONITOR->m_cursorZoom->setValueAndWarp(m_zoomBegin);
PMONITOR->m_zoomController.pinAnchor(g_pInputManager->getMouseCoordsInternal() - PMONITOR->m_position);
return;
}

if (m_mode == MODE_TOGGLE)
m_zoomed = !m_zoomed;

Expand All @@ -25,9 +46,35 @@ void CCursorZoomTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureB
*m->m_cursorZoom = m_zoomed ? m_zoomValue : *PZOOMFACTOR;
break;
case MODE_MULT: *m->m_cursorZoom = std::clamp(m->m_cursorZoom->goal() * m_zoomValue, 1.0F, 100.0F); break;
case MODE_LIVE: break;
}
}
}

void CCursorZoomTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) {}
void CCursorZoomTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) {}
void CCursorZoomTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) {
if (m_mode != MODE_LIVE || !m_monitor || !e.pinch)
return;

const auto PMONITOR = m_monitor.lock();
if (!PMONITOR)
return;

auto zoom = std::clamp(m_zoomBegin * static_cast<float>(e.pinch->scale), 1.0F, 100.0F);

if (zoom < 1.05F)
zoom = 1.0F;

PMONITOR->m_cursorZoom->setValueAndWarp(zoom);
}

void CCursorZoomTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) {
if (m_mode != MODE_LIVE || !m_monitor)
return;

const auto PMONITOR = m_monitor.lock();
if (!PMONITOR)
return;

PMONITOR->m_zoomController.clearAnchor();
m_monitor.reset();
}
Loading
Loading