diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 10299277..58db00e9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2171,6 +2171,7 @@ std::optional CConfigManager::handleBind(const std::string& command bool transparent = false; bool ignoreMods = false; bool multiKey = false; + bool longPress = false; bool hasDescription = false; bool dontInhibit = false; const auto BINDARGS = command.substr(4); @@ -2192,6 +2193,8 @@ std::optional CConfigManager::handleBind(const std::string& command ignoreMods = true; } else if (arg == 's') { multiKey = true; + } else if (arg == 'o') { + longPress = true; } else if (arg == 'd') { hasDescription = true; } else if (arg == 'p') { @@ -2201,8 +2204,8 @@ std::optional CConfigManager::handleBind(const std::string& command } } - if (release && repeat) - return "flags r and e are mutually exclusive"; + if ((longPress || release) && repeat) + return "flags e is mutually exclusive with r and o"; if (mouse && (repeat || release || locked)) return "flag m is exclusive"; @@ -2264,9 +2267,9 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid catchall, catchall keybinds are only allowed in submaps."; } - g_pKeybindManager->addKeybind(SKeybind{ - parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release, - repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit}); + g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, + COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release, repeat, longPress, + mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit}); } return {}; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6429e781..c5eba0a7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -843,6 +843,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "mouse": {}, "release": {}, "repeat": {}, + "longPress": {}, "non_consuming": {}, "has_description": {}, "modmask": {}, @@ -854,9 +855,9 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "dispatcher": "{}", "arg": "{}" }},)#", - kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false", - kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", - escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); + kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.longPress ? "true" : "false", + kb.nonConsuming ? "true" : "false", kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, + kb.catchAll ? "true" : "false", escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); } trimTrailingComma(ret); ret += "]"; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f2fdab53..b14637f7 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -13,6 +13,7 @@ #include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" +#include "eventLoop/EventLoopManager.hpp" #include #include @@ -130,9 +131,25 @@ CKeybindManager::CKeybindManager() { m_tScrollTimer.reset(); + m_pLongPressTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + if (!m_pLastLongPressKeybind || g_pSeatManager->keyboard.expired()) + return; + + const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(m_pLastLongPressKeybind->handler); + + Debug::log(LOG, "Long press timeout passed, calling dispatcher."); + DISPATCHER->second(m_pLastLongPressKeybind->arg); + }, + nullptr); + + g_pEventLoopManager->addTimer(m_pLongPressTimer); + static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { // clear cuz realloc'd - m_pActiveKeybind = nullptr; + m_pActiveKeybind = nullptr; + m_pLastLongPressKeybind = nullptr; m_vPressedSpecialBinds.clear(); }); } @@ -140,12 +157,17 @@ CKeybindManager::CKeybindManager() { CKeybindManager::~CKeybindManager() { if (m_pXKBTranslationState) xkb_state_unref(m_pXKBTranslationState); + if (m_pLongPressTimer && g_pEventLoopManager) { + g_pEventLoopManager->removeTimer(m_pLongPressTimer); + m_pLongPressTimer.reset(); + } } void CKeybindManager::addKeybind(SKeybind kb) { m_lKeybinds.push_back(kb); - m_pActiveKeybind = nullptr; + m_pActiveKeybind = nullptr; + m_pLastLongPressKeybind = nullptr; } void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { @@ -158,7 +180,8 @@ void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { } } - m_pActiveKeybind = nullptr; + m_pActiveKeybind = nullptr; + m_pLastLongPressKeybind = nullptr; } uint32_t CKeybindManager::stringToModMask(std::string mods) { @@ -409,6 +432,8 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { m_pActiveKeybind = nullptr; } + m_pLastLongPressKeybind = nullptr; + bool suppressEvent = false; if (e.state == WL_KEYBOARD_KEY_STATE_PRESSED) { @@ -705,6 +730,15 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP } } + if (k.longPress) { + const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); + + m_pLongPressTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay)); + m_pLastLongPressKeybind = &k; + + continue; + } + const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler); if (SPECIALTRIGGERED && !pressed) diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 24a09836..4a0af6e9 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -8,6 +8,7 @@ #include #include #include "../devices/IPointer.hpp" +#include "eventLoop/EventLoopTimer.hpp" class CInputManager; class CConfigManager; @@ -28,6 +29,7 @@ struct SKeybind { std::string description = ""; bool release = false; bool repeat = false; + bool longPress = false; bool mouse = false; bool nonConsuming = false; bool transparent = false; @@ -119,7 +121,8 @@ class CKeybindManager { inline static std::string m_szCurrentSelectedSubmap = ""; - SKeybind* m_pActiveKeybind = nullptr; + SKeybind * m_pActiveKeybind = nullptr, *m_pLastLongPressKeybind = nullptr; + SP m_pLongPressTimer; uint32_t m_uTimeLastMs = 0; uint32_t m_uLastCode = 0;