From 2be309de1df5e4262175fbcc58e6dd8de4e0e6d3 Mon Sep 17 00:00:00 2001 From: JS Deck Date: Mon, 4 Aug 2025 16:29:39 -0300 Subject: virtualkeyboard: Add options to skip releasing pressed keys on close and to skip sharing key states (#11214) --- src/managers/KeybindManager.cpp | 8 +- src/managers/SeatManager.cpp | 18 ++++- src/managers/input/InputManager.cpp | 92 +++++++++++++++++----- src/managers/input/InputManager.hpp | 10 ++- .../permissions/DynamicPermissionManager.cpp | 45 +---------- 5 files changed, 103 insertions(+), 70 deletions(-) (limited to 'src/managers') diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d9b2bc1f..27b6f4b9 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -457,7 +457,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { if (handleInternalKeybinds(internalKeysym)) return false; - const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); + const auto MODS = g_pInputManager->getModsFromAllKBs(); m_timeLastMs = e.timeMs; m_lastCode = KEYCODE; @@ -515,7 +515,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { } bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { - const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); + const auto MODS = g_pInputManager->getModsFromAllKBs(); static auto PDELAY = CConfigValue("binds:scroll_event_delay"); @@ -546,7 +546,7 @@ bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { } bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { - const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); + const auto MODS = g_pInputManager->getModsFromAllKBs(); bool suppressEvent = false; @@ -2454,7 +2454,7 @@ SDispatchResult CKeybindManager::pass(std::string regexp) { g_pSeatManager->setPointerFocus(PWINDOW->m_wlSurface->resource(), {1, 1}); } - g_pSeatManager->sendKeyboardMods(g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0); + g_pSeatManager->sendKeyboardMods(g_pInputManager->getModsFromAllKBs(), 0, 0, 0); if (g_pKeybindManager->m_passPressed == 1) { if (g_pKeybindManager->m_lastCode != 0) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 76217238..67752e2a 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -11,7 +11,11 @@ #include "../managers/HookSystemManager.hpp" #include "wlr-layer-shell-unstable-v1.hpp" #include +#include #include +#include + +using namespace Hyprutils::Utils; CSeatManager::CSeatManager() { m_listeners.newSeatResource = PROTO::seat->m_events.newSeatResource.listen([this](const auto& resource) { onNewSeatResource(resource); }); @@ -136,6 +140,18 @@ void CSeatManager::setKeyboardFocus(SP surf) { return; } + wl_array keys; + wl_array_init(&keys); + CScopeGuard x([&keys] { wl_array_release(&keys); }); + + const auto& PRESSED = g_pInputManager->getKeysFromAllKBs(); + static_assert(std::is_same_v::value_type, uint32_t>, "Element type different from keycode type uint32_t"); + + const auto PRESSEDARRSIZE = PRESSED.size() * sizeof(uint32_t); + const auto PKEYS = wl_array_add(&keys, PRESSEDARRSIZE); + if (PKEYS) + memcpy(PKEYS, PRESSED.data(), PRESSEDARRSIZE); + auto client = surf->client(); for (auto const& r : m_seatResources | std::views::reverse) { if (r->resource->client() != client) @@ -146,7 +162,7 @@ void CSeatManager::setKeyboardFocus(SP surf) { if (!k) continue; - k->sendEnter(surf); + k->sendEnter(surf, &keys); k->sendMods(m_keyboard->m_modifiersState.depressed, m_keyboard->m_modifiersState.latched, m_keyboard->m_modifiersState.locked, m_keyboard->m_modifiersState.group); } } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 6c23c493..cbb4c3cc 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -39,6 +39,7 @@ #include "../../managers/permissions/DynamicPermissionManager.hpp" #include "../../helpers/time/Time.hpp" +#include "../../helpers/MiscFunctions.hpp" #include @@ -931,6 +932,14 @@ Vector2D CInputManager::getMouseCoordsInternal() { return g_pPointerManager->position(); } +void CInputManager::newKeyboard(SP keeb) { + const auto PNEWKEYBOARD = m_keyboards.emplace_back(keeb); + + setupKeyboard(PNEWKEYBOARD); + + Debug::log(LOG, "New keyboard created, pointers Hypr: {:x}", (uintptr_t)PNEWKEYBOARD.get()); +} + void CInputManager::newKeyboard(SP keyboard) { const auto PNEWKEYBOARD = m_keyboards.emplace_back(CKeyboard::create(keyboard)); @@ -1398,18 +1407,36 @@ void CInputManager::onKeyboardKey(const IKeyboard::SKeyEvent& event, SPisVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard); + const auto IME = m_relay.m_inputMethod.lock(); + const bool HASIME = IME && IME->hasGrab(); + const bool USEIME = HASIME && !DISALLOWACTION; + const auto EMAP = std::unordered_map{{"keyboard", pKeyboard}, {"event", event}}; EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP); - bool passEvent = DISALLOWACTION || g_pKeybindManager->onKeyEvent(event, pKeyboard); + bool passEvent = DISALLOWACTION; - if (passEvent) { - const auto IME = m_relay.m_inputMethod.lock(); + if (!DISALLOWACTION) + passEvent = g_pKeybindManager->onKeyEvent(event, pKeyboard); - if (IME && IME->hasGrab() && !DISALLOWACTION) { + if (passEvent) { + if (USEIME) { IME->setKeyboard(pKeyboard); IME->sendKey(event.timeMs, event.keycode, event.state); } else { + const auto PRESSED = shareKeyFromAllKBs(event.keycode, event.state == WL_KEYBOARD_KEY_STATE_PRESSED); + const auto CONTAINS = std::ranges::contains(m_pressed, event.keycode); + + if (CONTAINS && PRESSED) + return; + if (!CONTAINS && !PRESSED) + return; + + if (CONTAINS) + std::erase(m_pressed, event.keycode); + else + m_pressed.emplace_back(event.keycode); + g_pSeatManager->setKeyboard(pKeyboard); g_pSeatManager->sendKeyboardKey(event.timeMs, event.keycode, event.state); } @@ -1424,10 +1451,9 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard); - const auto ALLMODS = accumulateModsFromAllKBs(); - - auto MODS = pKeyboard->m_modifiersState; - MODS.depressed = ALLMODS; + auto MODS = pKeyboard->m_modifiersState; + const auto ALLMODS = shareModsFromAllKBs(MODS.depressed); + MODS.depressed = ALLMODS; const auto IME = m_relay.m_inputMethod.lock(); @@ -1437,6 +1463,7 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { } else { g_pSeatManager->setKeyboard(pKeyboard); g_pSeatManager->sendKeyboardMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); + m_lastMods = MODS.depressed; } updateKeyboardsLeds(pKeyboard); @@ -1457,9 +1484,9 @@ bool CInputManager::shouldIgnoreVirtualKeyboard(SP pKeyboard) { if (!pKeyboard->isVirtual()) return false; - CVirtualKeyboard* vk = (CVirtualKeyboard*)pKeyboard.get(); + auto client = pKeyboard->getClient(); - return !pKeyboard || (!m_relay.m_inputMethod.expired() && m_relay.m_inputMethod->grabClient() == vk->getClient()); + return !pKeyboard || (client && !m_relay.m_inputMethod.expired() && m_relay.m_inputMethod->grabClient() == client); } void CInputManager::refocus() { @@ -1564,11 +1591,45 @@ void CInputManager::updateCapabilities() { m_capabilities = caps; } -uint32_t CInputManager::accumulateModsFromAllKBs() { +const std::vector& CInputManager::getKeysFromAllKBs() { + return m_pressed; +} + +uint32_t CInputManager::getModsFromAllKBs() { + return m_lastMods; +} + +bool CInputManager::shareKeyFromAllKBs(uint32_t key, bool pressed) { + bool finalState = pressed; - uint32_t finalMask = 0; + if (finalState) + return finalState; for (auto const& kb : m_keyboards) { + if (!kb->shareStates()) + continue; + + if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) + continue; + + if (!kb->m_enabled) + continue; + + const bool PRESSED = kb->getPressed(key); + if (PRESSED) + return PRESSED; + } + + return finalState; +} + +uint32_t CInputManager::shareModsFromAllKBs(uint32_t depressed) { + uint32_t finalMask = depressed; + + for (auto const& kb : m_keyboards) { + if (!kb->shareStates()) + continue; + if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) continue; @@ -1751,13 +1812,6 @@ void CInputManager::unsetCursorImage() { restoreCursorIconToApp(); } -std::string CInputManager::deviceNameToInternalString(std::string in) { - std::ranges::replace(in, ' ', '-'); - std::ranges::replace(in, '\n', '-'); - std::ranges::transform(in, in.begin(), ::tolower); - return in; -} - std::string CInputManager::getNameForNewDevice(std::string internalName) { auto proposedNewName = deviceNameToInternalString(internalName); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 1696dd0a..73a0dc48 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -94,6 +94,7 @@ class CInputManager { void onKeyboardKey(const IKeyboard::SKeyEvent&, SP); void onKeyboardMod(SP); + void newKeyboard(SP); void newKeyboard(SP); void newVirtualKeyboard(SP); void newMouse(SP); @@ -185,7 +186,8 @@ class CInputManager { CInputMethodRelay m_relay; // for shared mods - uint32_t accumulateModsFromAllKBs(); + const std::vector& getKeysFromAllKBs(); + uint32_t getModsFromAllKBs(); // for virtual keyboards: whether we should respect them as normal ones bool shouldIgnoreVirtualKeyboard(SP); @@ -194,7 +196,6 @@ class CInputManager { void setCursorImageUntilUnset(std::string); void unsetCursorImage(); - std::string deviceNameToInternalString(std::string); std::string getNameForNewDevice(std::string); void releaseAllMouseButtons(); @@ -305,6 +306,11 @@ class CInputManager { uint32_t accumulatedScroll = 0; } m_scrollWheelState; + bool shareKeyFromAllKBs(uint32_t key, bool pressed); + uint32_t shareModsFromAllKBs(uint32_t depressed); + std::vector m_pressed; + uint32_t m_lastMods = 0; + friend class CKeybindManager; friend class CWLSurface; }; diff --git a/src/managers/permissions/DynamicPermissionManager.cpp b/src/managers/permissions/DynamicPermissionManager.cpp index 235336b7..2f4690fc 100644 --- a/src/managers/permissions/DynamicPermissionManager.cpp +++ b/src/managers/permissions/DynamicPermissionManager.cpp @@ -2,10 +2,9 @@ #include "DynamicPermissionManager.hpp" #include #include -#include -#include #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" +#include "../../helpers/MiscFunctions.hpp" #include using namespace Hyprutils::String; @@ -76,48 +75,6 @@ static const char* specialPidToString(eSpecialPidTypes type) { } } -static std::expected binaryNameForPid(pid_t pid) { - if (pid <= 0) - return std::unexpected("No pid for client"); - -#if defined(KERN_PROC_PATHNAME) - int mib[] = { - CTL_KERN, -#if defined(__NetBSD__) - KERN_PROC_ARGS, - pid, - KERN_PROC_PATHNAME, -#else - KERN_PROC, - KERN_PROC_PATHNAME, - pid, -#endif - }; - u_int miblen = sizeof(mib) / sizeof(mib[0]); - char exe[PATH_MAX] = "/nonexistent"; - size_t sz = sizeof(exe); - sysctl(mib, miblen, &exe, &sz, NULL, 0); - std::string path = exe; -#else - std::string path = std::format("/proc/{}/exe", (uint64_t)pid); -#endif - std::error_code ec; - - std::string fullPath = std::filesystem::canonical(path, ec); - - if (ec) - return std::unexpected("canonical failed"); - - return fullPath; -} - -static std::expected binaryNameForWlClient(wl_client* client) { - pid_t pid = 0; - wl_client_get_credentials(client, &pid, nullptr, nullptr); - - return binaryNameForPid(pid); -} - void CDynamicPermissionManager::clearConfigPermissions() { std::erase_if(m_rules, [](const auto& e) { return e->m_source == PERMISSION_RULE_SOURCE_CONFIG; }); } -- cgit v1.2.3