From 127aab815908ecbd3db4d23f127d2e96b79855f9 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 2 Sep 2025 13:16:43 +0200 Subject: input: add per-device scroll-factor (#11241) --- src/config/ConfigManager.cpp | 10 ++++++++-- src/config/ConfigManager.hpp | 1 + src/debug/HyprCtl.cpp | 10 ++++++---- src/desktop/Window.cpp | 8 ++++++++ src/desktop/Window.hpp | 2 ++ src/devices/IPointer.hpp | 15 ++++++++------- src/managers/PointerManager.cpp | 4 ++-- src/managers/input/InputManager.cpp | 26 +++++++++++++++++++++++--- src/managers/input/InputManager.hpp | 3 ++- 9 files changed, 60 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 9277b89b..16183498 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -810,6 +810,7 @@ CConfigManager::CConfigManager() { m_config->addSpecialConfigValue("device", "scroll_button", 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_factor", Hyprlang::FLOAT{-1}); m_config->addSpecialConfigValue("device", "transform", Hyprlang::INT{-1}); m_config->addSpecialConfigValue("device", "output", {STRVAL_EMPTY}); 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()); - if ((!VAL || !VAL->m_bSetByUser) && !fallback.empty()) { + if ((!VAL || !VAL->m_bSetByUser) && !fallback.empty()) return m_config->getConfigValuePtr(fallback.c_str()); - } 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) { return std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue()); } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index fe1adc50..cff146f3 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -210,6 +210,7 @@ class CConfigManager { float getDeviceFloat(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 = ""); + bool deviceConfigExplicitlySet(const std::string&, const std::string&); bool deviceConfigExists(const std::string&); Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback); bool shouldBlurLS(const std::string&); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a9388789..8598b1f6 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -722,10 +722,11 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque R"#( {{ "address": "0x{:x}", "name": "{}", - "defaultSpeed": {:.5f} + "defaultSpeed": {:.5f}, + "scrollFactor": {:.2f} }},)#", rc(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); @@ -826,8 +827,9 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque result += "mice:\n"; 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(m.get()), m->m_hlName, - (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f)); + result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n\t\t\tscroll factor: {:.2f}\n", rc(m.get()), m->m_hlName, + (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"; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 3c952005..78f12a11 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1249,6 +1249,14 @@ float CWindow::getScrollTouchpad() { 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() { static auto PTEARING = CConfigValue("general:allow_tearing"); return m_windowData.tearing.valueOr(m_tearingHint) && *PTEARING; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index e58d4fb6..9d94baea 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -363,6 +363,8 @@ class CWindow { int getRealBorderSize(); float getScrollMouse(); float getScrollTouchpad(); + bool isScrollMouseOverridden(); + bool isScrollTouchpadOverridden(); void updateWindowData(); void updateWindowData(const struct SWorkspaceRule&); void onBorderAngleAnimEnd(WP pav); diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index e5d76344..197ba123 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -108,11 +108,12 @@ class IPointer : public IHID { CSignalT holdEnd; } m_pointerEvents; - bool m_connected = false; // means connected to the cursor - std::string m_boundOutput = ""; - bool m_flipX = false; // decide to invert horizontal movement - bool m_flipY = false; // decide to invert vertical movement - bool m_isTouchpad = false; - - WP m_self; + bool m_connected = false; // means connected to the cursor + std::string m_boundOutput = ""; + bool m_flipX = false; // decide to invert horizontal movement + bool m_flipY = false; // decide to invert vertical movement + bool m_isTouchpad = false; + std::optional m_scrollFactor = {}; + + WP m_self; }; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 093c751d..aeabe412 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -919,8 +919,8 @@ void CPointerManager::attachPointer(SP pointer) { PROTO::idle->onActivity(); }); - listener->axis = pointer->m_pointerEvents.axis.listen([](const IPointer::SAxisEvent& event) { - g_pInputManager->onMouseWheel(event); + listener->axis = pointer->m_pointerEvents.axis.listen([weak = WP(pointer)](const IPointer::SAxisEvent& event) { + g_pInputManager->onMouseWheel(event, weak.lock()); PROTO::idle->onActivity(); }); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 5224f940..5e844bec 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -835,7 +835,7 @@ void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) { m_clickBehavior = CLICKMODE_DEFAULT; } -void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { +void CInputManager::onMouseWheel(IPointer::SAxisEvent e, SP pointer) { static auto POFFWINDOWAXIS = CConfigValue("input:off_window_axis_events"); static auto PINPUTSCROLLFACTOR = CConfigValue("input:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue("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; auto factor = ISTOUCHPADSCROLL ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR; - const auto EMAP = std::unordered_map{{"event", e}}; + if (pointer && pointer->m_scrollFactor.has_value()) + factor = *pointer->m_scrollFactor; + + const auto EMAP = std::unordered_map{{"event", e}}; EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP); if (e.mouse) @@ -888,7 +891,11 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { if (*PFOLLOWMOUSE == 1 && PCURRWINDOW && PWINDOW != PCURRWINDOW) 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 mouse) { Debug::log(LOG, "New virtual mouse created"); } +void CInputManager::newMouse(SP mouse) { + m_pointers.emplace_back(mouse); + + setupMouse(mouse); + + Debug::log(LOG, "New mouse created, pointer Hypr: {:x}", rc(mouse.get())); +} + void CInputManager::newMouse(SP 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()) { const auto LIBINPUTDEV = m->aq()->getLibinputHandle(); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 56751cf5..60ff49ef 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -90,13 +90,14 @@ class CInputManager { void onMouseMoved(IPointer::SMotionEvent); void onMouseWarp(IPointer::SMotionAbsoluteEvent); void onMouseButton(IPointer::SButtonEvent); - void onMouseWheel(IPointer::SAxisEvent); + void onMouseWheel(IPointer::SAxisEvent, SP pointer = nullptr); void onKeyboardKey(const IKeyboard::SKeyEvent&, SP); void onKeyboardMod(SP); void newKeyboard(SP); void newKeyboard(SP); void newVirtualKeyboard(SP); + void newMouse(SP); void newMouse(SP); void newVirtualMouse(SP); void newTouchDevice(SP); -- cgit v1.2.3