virtualkeyboard: Add options to skip releasing pressed keys on close and to skip sharing key states (#11214)

This commit is contained in:
JS Deck 2025-08-04 16:29:39 -03:00 committed by GitHub
parent 6491bb4fb7
commit 2be309de1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 416 additions and 137 deletions

View file

@ -457,7 +457,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> 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<IKeyboard> pKeyboard) {
}
bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
const auto MODS = g_pInputManager->getModsFromAllKBs();
static auto PDELAY = CConfigValue<Hyprlang::INT>("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)

View file

@ -11,7 +11,11 @@
#include "../managers/HookSystemManager.hpp"
#include "wlr-layer-shell-unstable-v1.hpp"
#include <algorithm>
#include <hyprutils/utils/ScopeGuard.hpp>
#include <ranges>
#include <cstring>
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<CWLSurfaceResource> 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<std::decay_t<decltype(PRESSED)>::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<CWLSurfaceResource> 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);
}
}

View file

@ -39,6 +39,7 @@
#include "../../managers/permissions/DynamicPermissionManager.hpp"
#include "../../helpers/time/Time.hpp"
#include "../../helpers/MiscFunctions.hpp"
#include <aquamarine/input/Input.hpp>
@ -931,6 +932,14 @@ Vector2D CInputManager::getMouseCoordsInternal() {
return g_pPointerManager->position();
}
void CInputManager::newKeyboard(SP<IKeyboard> 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<Aquamarine::IKeyboard> keyboard) {
const auto PNEWKEYBOARD = m_keyboards.emplace_back(CKeyboard::create(keyboard));
@ -1398,18 +1407,36 @@ void CInputManager::onKeyboardKey(const IKeyboard::SKeyEvent& event, SP<IKeyboar
const bool DISALLOWACTION = pKeyboard->isVirtual() && 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<std::string, std::any>{{"keyboard", pKeyboard}, {"event", event}};
EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP);
bool passEvent = DISALLOWACTION || g_pKeybindManager->onKeyEvent(event, pKeyboard);
bool passEvent = DISALLOWACTION;
if (!DISALLOWACTION)
passEvent = g_pKeybindManager->onKeyEvent(event, pKeyboard);
if (passEvent) {
const auto IME = m_relay.m_inputMethod.lock();
if (IME && IME->hasGrab() && !DISALLOWACTION) {
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<IKeyboard> 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<IKeyboard> 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<IKeyboard> 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<uint32_t>& CInputManager::getKeysFromAllKBs() {
return m_pressed;
}
uint32_t finalMask = 0;
uint32_t CInputManager::getModsFromAllKBs() {
return m_lastMods;
}
bool CInputManager::shareKeyFromAllKBs(uint32_t key, bool pressed) {
bool finalState = pressed;
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);

View file

@ -94,6 +94,7 @@ class CInputManager {
void onKeyboardKey(const IKeyboard::SKeyEvent&, SP<IKeyboard>);
void onKeyboardMod(SP<IKeyboard>);
void newKeyboard(SP<IKeyboard>);
void newKeyboard(SP<Aquamarine::IKeyboard>);
void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>);
void newMouse(SP<Aquamarine::IPointer>);
@ -185,7 +186,8 @@ class CInputManager {
CInputMethodRelay m_relay;
// for shared mods
uint32_t accumulateModsFromAllKBs();
const std::vector<uint32_t>& getKeysFromAllKBs();
uint32_t getModsFromAllKBs();
// for virtual keyboards: whether we should respect them as normal ones
bool shouldIgnoreVirtualKeyboard(SP<IKeyboard>);
@ -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<uint32_t> m_pressed;
uint32_t m_lastMods = 0;
friend class CKeybindManager;
friend class CWLSurface;
};

View file

@ -2,10 +2,9 @@
#include "DynamicPermissionManager.hpp"
#include <algorithm>
#include <wayland-server-core.h>
#include <expected>
#include <filesystem>
#include "../../Compositor.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../helpers/MiscFunctions.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
@ -76,48 +75,6 @@ static const char* specialPidToString(eSpecialPidTypes type) {
}
}
static std::expected<std::string, std::string> 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<std::string, std::string> 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; });
}