summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJS Deck <jsdeckerido@gmail.com>2025-08-04 16:29:39 -0300
committerGitHub <noreply@github.com>2025-08-04 21:29:39 +0200
commit2be309de1df5e4262175fbcc58e6dd8de4e0e6d3 (patch)
tree866629ba5a4b9b45d8720383e4332726444f3566 /src
parent6491bb4fb7c7e86d9168a104d5b87ace4e1b978d (diff)
virtualkeyboard: Add options to skip releasing pressed keys on close and to skip sharing key states (#11214)
Diffstat (limited to 'src')
-rw-r--r--src/config/ConfigDescriptions.hpp23
-rw-r--r--src/config/ConfigManager.cpp5
-rw-r--r--src/debug/HyprCtl.cpp2
-rw-r--r--src/devices/IKeyboard.cpp37
-rw-r--r--src/devices/IKeyboard.hpp19
-rw-r--r--src/devices/Keyboard.cpp5
-rw-r--r--src/devices/VirtualKeyboard.cpp10
-rw-r--r--src/devices/VirtualKeyboard.hpp2
-rw-r--r--src/helpers/MiscFunctions.cpp52
-rw-r--r--src/helpers/MiscFunctions.hpp45
-rw-r--r--src/managers/KeybindManager.cpp8
-rw-r--r--src/managers/SeatManager.cpp18
-rw-r--r--src/managers/input/InputManager.cpp92
-rw-r--r--src/managers/input/InputManager.hpp10
-rw-r--r--src/managers/permissions/DynamicPermissionManager.cpp45
-rw-r--r--src/protocols/VirtualKeyboard.cpp51
-rw-r--r--src/protocols/VirtualKeyboard.hpp1
-rw-r--r--src/protocols/core/Seat.cpp21
-rw-r--r--src/protocols/core/Seat.hpp3
19 files changed, 313 insertions, 136 deletions
diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp
index 852a86d0..aeff3906 100644
--- a/src/config/ConfigDescriptions.hpp
+++ b/src/config/ConfigDescriptions.hpp
@@ -677,6 +677,23 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
},
/*
+ * input:virtualkeyboard:
+ */
+
+ SConfigOptionDescription{
+ .value = "input:virtualkeyboard:share_states",
+ .description = "Unify key down states and modifier states with other keyboards",
+ .type = CONFIG_OPTION_BOOL,
+ .data = SConfigOptionDescription::SBoolData{false},
+ },
+ SConfigOptionDescription{
+ .value = "input:virtualkeyboard:release_pressed_on_close",
+ .description = "Release all pressed keys by virtual keyboard on close.",
+ .type = CONFIG_OPTION_BOOL,
+ .data = SConfigOptionDescription::SBoolData{false},
+ },
+
+ /*
* input:tablet:
*/
@@ -1151,6 +1168,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
+ .value = "misc:name_vk_after_proc",
+ .description = "Name virtual keyboards after the processes that create them. E.g. /usr/bin/fcitx5 will have hl-virtual-keyboard-fcitx5.",
+ .type = CONFIG_OPTION_BOOL,
+ .data = SConfigOptionDescription::SBoolData{true},
+ },
+ SConfigOptionDescription{
.value = "misc:always_follow_on_dnd",
.description = "Will make mouse focus follow the mouse when drag and dropping. Recommended to leave it enabled, especially for people using focus follows mouse at 0.",
.type = CONFIG_OPTION_BOOL,
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index d49add0e..337682dc 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -473,6 +473,7 @@ CConfigManager::CConfigManager() {
registerConfigVar("misc:vrr", Hyprlang::INT{0});
registerConfigVar("misc:mouse_move_enables_dpms", Hyprlang::INT{0});
registerConfigVar("misc:key_press_enables_dpms", Hyprlang::INT{0});
+ registerConfigVar("misc:name_vk_after_proc", Hyprlang::INT{1});
registerConfigVar("misc:always_follow_on_dnd", Hyprlang::INT{1});
registerConfigVar("misc:layers_hog_keyboard_focus", Hyprlang::INT{1});
registerConfigVar("misc:animate_manual_resizes", Hyprlang::INT{0});
@@ -662,6 +663,8 @@ CConfigManager::CConfigManager() {
registerConfigVar("input:touchdevice:transform", Hyprlang::INT{-1});
registerConfigVar("input:touchdevice:output", {"[[Auto]]"});
registerConfigVar("input:touchdevice:enabled", Hyprlang::INT{1});
+ registerConfigVar("input:virtualkeyboard:share_states", Hyprlang::INT{0});
+ registerConfigVar("input:virtualkeyboard:release_pressed_on_close", Hyprlang::INT{0});
registerConfigVar("input:tablet:transform", Hyprlang::INT{0});
registerConfigVar("input:tablet:output", {STRVAL_EMPTY});
registerConfigVar("input:tablet:region_position", Hyprlang::VEC2{0, 0});
@@ -797,6 +800,8 @@ CConfigManager::CConfigManager() {
m_config->addSpecialConfigValue("device", "flip_y", Hyprlang::INT{0}); // only for touchpads
m_config->addSpecialConfigValue("device", "drag_3fg", Hyprlang::INT{0}); // only for touchpads
m_config->addSpecialConfigValue("device", "keybinds", Hyprlang::INT{1}); // enable/disable keybinds
+ m_config->addSpecialConfigValue("device", "share_states", Hyprlang::INT{0}); // only for virtualkeyboards
+ m_config->addSpecialConfigValue("device", "release_pressed_on_close", Hyprlang::INT{0}); // only for virtualkeyboards
m_config->addSpecialCategory("monitorv2", {.key = "output"});
m_config->addSpecialConfigValue("monitorv2", "disabled", Hyprlang::INT{0});
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 7cdd8ac0..cec41087 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -1342,7 +1342,7 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri
}
return result.empty() ? "ok" : result;
} else {
- auto k = std::ranges::find_if(g_pInputManager->m_keyboards, [&](const auto& other) { return other->m_hlName == g_pInputManager->deviceNameToInternalString(KB); });
+ auto k = std::ranges::find_if(g_pInputManager->m_keyboards, [&](const auto& other) { return other->m_hlName == deviceNameToInternalString(KB); });
if (k == g_pInputManager->m_keyboards.end())
return "device not found";
diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp
index 89ad8c16..0a22eb6e 100644
--- a/src/devices/IKeyboard.cpp
+++ b/src/devices/IKeyboard.cpp
@@ -378,19 +378,6 @@ bool IKeyboard::updateModifiersState() {
}
void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
-
- const auto contains = std::ranges::find(m_pressedXKB, xkbKey) != m_pressedXKB.end();
-
- if (contains && pressed)
- return;
- if (!contains && !pressed)
- return;
-
- if (contains)
- std::erase(m_pressedXKB, xkbKey);
- else
- m_pressedXKB.emplace_back(xkbKey);
-
xkb_state_update_key(m_xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) {
@@ -405,3 +392,27 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
});
}
}
+
+bool IKeyboard::updatePressed(uint32_t key, bool pressed) {
+ const auto contains = getPressed(key);
+
+ if (contains && pressed)
+ return false;
+ if (!contains && !pressed)
+ return false;
+
+ if (contains)
+ std::erase(m_pressed, key);
+ else
+ m_pressed.emplace_back(key);
+
+ return true;
+}
+
+bool IKeyboard::getPressed(uint32_t key) {
+ return std::ranges::contains(m_pressed, key);
+}
+
+bool IKeyboard::shareStates() {
+ return m_shareStates;
+}
diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp
index 25a7efd1..f4fb667b 100644
--- a/src/devices/IKeyboard.hpp
+++ b/src/devices/IKeyboard.hpp
@@ -24,10 +24,13 @@ enum eKeyboardModifiers {
class IKeyboard : public IHID {
public:
virtual ~IKeyboard();
- virtual uint32_t getCapabilities();
- virtual eHIDType getType();
- virtual bool isVirtual() = 0;
- virtual SP<Aquamarine::IKeyboard> aq() = 0;
+ virtual uint32_t getCapabilities();
+ virtual eHIDType getType();
+ virtual bool isVirtual() = 0;
+ virtual wl_client* getClient() {
+ return nullptr;
+ };
+ virtual SP<Aquamarine::IKeyboard> aq() = 0;
struct SKeyEvent {
uint32_t timeMs = 0;
@@ -73,6 +76,8 @@ class IKeyboard : public IHID {
bool updateModifiersState(); // rets whether changed
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD();
+ bool getPressed(uint32_t key);
+ bool shareStates();
bool m_active = false;
bool m_enabled = true;
@@ -118,5 +123,9 @@ class IKeyboard : public IHID {
private:
void clearManuallyAllocd();
- std::vector<uint32_t> m_pressedXKB;
+ std::vector<uint32_t> m_pressed;
+
+ protected:
+ bool updatePressed(uint32_t key, bool pressed);
+ bool m_shareStates = true;
};
diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp
index 9ce37e6b..80f76c17 100644
--- a/src/devices/Keyboard.cpp
+++ b/src/devices/Keyboard.cpp
@@ -29,13 +29,16 @@ CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : m_keyboard(keeb) {
});
m_listeners.key = keeb->events.key.listen([this](const Aquamarine::IKeyboard::SKeyEvent& event) {
+ const auto UPDATED = updatePressed(event.key, event.pressed);
+
m_keyboardEvents.key.emit(SKeyEvent{
.timeMs = event.timeMs,
.keycode = event.key,
.state = event.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
});
- updateXkbStateWithKey(event.key + 8, event.pressed);
+ if (UPDATED)
+ updateXkbStateWithKey(event.key + 8, event.pressed);
});
m_listeners.modifiers = keeb->events.modifiers.listen([this] {
diff --git a/src/devices/VirtualKeyboard.cpp b/src/devices/VirtualKeyboard.cpp
index ea21a22b..97b7626a 100644
--- a/src/devices/VirtualKeyboard.cpp
+++ b/src/devices/VirtualKeyboard.cpp
@@ -1,6 +1,8 @@
#include "VirtualKeyboard.hpp"
#include "../defines.hpp"
#include "../protocols/VirtualKeyboard.hpp"
+#include "../config/ConfigManager.hpp"
+#include <wayland-server-protocol.h>
SP<CVirtualKeyboard> CVirtualKeyboard::create(SP<CVirtualKeyboardV1Resource> keeb) {
SP<CVirtualKeyboard> pKeeb = SP<CVirtualKeyboard>(new CVirtualKeyboard(keeb));
@@ -19,7 +21,10 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : m_key
m_events.destroy.emit();
});
- m_listeners.key = keeb_->m_events.key.listen([this](const auto& event) { m_keyboardEvents.key.emit(event); });
+ m_listeners.key = keeb_->m_events.key.listen([this](const auto& event) {
+ updatePressed(event.keycode, event.state == WL_KEYBOARD_KEY_STATE_PRESSED);
+ m_keyboardEvents.key.emit(event);
+ });
m_listeners.modifiers = keeb_->m_events.modifiers.listen([this](const SModifiersEvent& event) {
updateModifiers(event.depressed, event.latched, event.locked, event.group);
m_keyboardEvents.modifiers.emit(SModifiersEvent{
@@ -39,7 +44,8 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : m_key
m_keyboardEvents.keymap.emit(event);
});
- m_deviceName = keeb_->m_name;
+ m_deviceName = keeb_->m_name;
+ m_shareStates = g_pConfigManager->getDeviceInt(m_deviceName, "share_states", "input:virtualkeyboard:share_states");
}
bool CVirtualKeyboard::isVirtual() {
diff --git a/src/devices/VirtualKeyboard.hpp b/src/devices/VirtualKeyboard.hpp
index 05e0a255..a0783d93 100644
--- a/src/devices/VirtualKeyboard.hpp
+++ b/src/devices/VirtualKeyboard.hpp
@@ -11,7 +11,7 @@ class CVirtualKeyboard : public IKeyboard {
virtual bool isVirtual();
virtual SP<Aquamarine::IKeyboard> aq();
- wl_client* getClient();
+ virtual wl_client* getClient();
private:
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
index 90383ca5..721855fd 100644
--- a/src/helpers/MiscFunctions.cpp
+++ b/src/helpers/MiscFunctions.cpp
@@ -876,3 +876,55 @@ bool isNvidiaDriverVersionAtLeast(int threshold) {
return driverMajor >= threshold;
}
+
+std::expected<std::string, std::string> binaryNameForWlClient(wl_client* client) {
+ if (!client)
+ return std::unexpected("client unknown");
+
+ pid_t pid = 0;
+ wl_client_get_credentials(client, &pid, nullptr, nullptr);
+
+ return binaryNameForPid(pid);
+}
+
+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;
+}
+
+std::string deviceNameToInternalString(std::string in) {
+ std::ranges::replace(in, ' ', '-');
+ std::ranges::replace(in, '\n', '-');
+ std::ranges::transform(in, in.begin(), ::tolower);
+ return in;
+}
diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp
index f361313b..8e507b6b 100644
--- a/src/helpers/MiscFunctions.hpp
+++ b/src/helpers/MiscFunctions.hpp
@@ -19,27 +19,30 @@ struct SWorkspaceIDName {
std::string name;
};
-std::string absolutePath(const std::string&, const std::string&);
-std::string escapeJSONStrings(const std::string& str);
-bool isDirection(const std::string&);
-bool isDirection(const char&);
-SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
-std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
-float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
-void logSystemInfo();
-std::string execAndGet(const char*);
-int64_t getPPIDof(int64_t pid);
-std::expected<int64_t, std::string> configStringToInt(const std::string&);
-Vector2D configStringToVector2D(const std::string&);
-std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
-double normalizeAngleRad(double ang);
-std::vector<SCallstackFrameInfo> getBacktrace();
-void throwError(const std::string& err);
-bool envEnabled(const std::string& env);
-Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len);
-bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr);
-float stringToPercentage(const std::string& VALUE, const float REL);
-bool isNvidiaDriverVersionAtLeast(int threshold);
+std::string absolutePath(const std::string&, const std::string&);
+std::string escapeJSONStrings(const std::string& str);
+bool isDirection(const std::string&);
+bool isDirection(const char&);
+SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
+std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
+float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
+void logSystemInfo();
+std::string execAndGet(const char*);
+int64_t getPPIDof(int64_t pid);
+std::expected<int64_t, std::string> configStringToInt(const std::string&);
+Vector2D configStringToVector2D(const std::string&);
+std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
+double normalizeAngleRad(double ang);
+std::vector<SCallstackFrameInfo> getBacktrace();
+void throwError(const std::string& err);
+bool envEnabled(const std::string& env);
+Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len);
+bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr);
+float stringToPercentage(const std::string& VALUE, const float REL);
+bool isNvidiaDriverVersionAtLeast(int threshold);
+std::expected<std::string, std::string> binaryNameForWlClient(wl_client* client);
+std::expected<std::string, std::string> binaryNameForPid(pid_t pid);
+std::string deviceNameToInternalString(std::string in);
template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
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<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)
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 <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);
}
}
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 <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 (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<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 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<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;
};
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 <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; });
}
diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp
index 7512f9bd..3dc15d83 100644
--- a/src/protocols/VirtualKeyboard.cpp
+++ b/src/protocols/VirtualKeyboard.cpp
@@ -1,23 +1,42 @@
#include "VirtualKeyboard.hpp"
+#include <filesystem>
#include <sys/mman.h>
+#include "../config/ConfigValue.hpp"
+#include "../config/ConfigManager.hpp"
#include "../devices/IKeyboard.hpp"
#include "../helpers/time/Time.hpp"
+#include "../helpers/MiscFunctions.hpp"
using namespace Hyprutils::OS;
+static std::string virtualKeyboardNameForWlClient(wl_client* client) {
+ std::string name = "hl-virtual-keyboard";
+
+ static auto PVKNAMEPROC = CConfigValue<Hyprlang::INT>("misc:name_vk_after_proc");
+ if (!*PVKNAMEPROC)
+ return name;
+
+ name += "-";
+ const auto CLIENTNAME = binaryNameForWlClient(client);
+ if (CLIENTNAME.has_value()) {
+ const auto PATH = std::filesystem::path(CLIENTNAME.value());
+ if (PATH.has_filename()) {
+ const auto FILENAME = PATH.filename();
+ const auto NAME = deviceNameToInternalString(FILENAME);
+ name += NAME;
+ return name;
+ }
+ }
+
+ name += "unknown";
+ return name;
+}
+
CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1> resource_) : m_resource(resource_) {
if UNLIKELY (!good())
return;
- m_resource->setDestroy([this](CZwpVirtualKeyboardV1* r) {
- releasePressed();
- m_events.destroy.emit();
- PROTO::virtualKeyboard->destroyResource(this);
- });
- m_resource->setOnDestroy([this](CZwpVirtualKeyboardV1* r) {
- releasePressed();
- m_events.destroy.emit();
- PROTO::virtualKeyboard->destroyResource(this);
- });
+ m_resource->setDestroy([this](CZwpVirtualKeyboardV1* r) { destroy(); });
+ m_resource->setOnDestroy([this](CZwpVirtualKeyboardV1* r) { destroy(); });
m_resource->setKey([this](CZwpVirtualKeyboardV1* r, uint32_t timeMs, uint32_t key, uint32_t state) {
if UNLIKELY (!m_hasKeymap) {
@@ -31,7 +50,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
.state = (wl_keyboard_key_state)state,
});
- const bool CONTAINS = std::ranges::find(m_pressed, key) != m_pressed.end();
+ const bool CONTAINS = std::ranges::contains(m_pressed, key);
if (state && !CONTAINS)
m_pressed.emplace_back(key);
else if (!state && CONTAINS)
@@ -88,7 +107,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
xkb_context_unref(xkbContext);
});
- m_name = "hl-virtual-keyboard";
+ m_name = virtualKeyboardNameForWlClient(resource_->client());
}
CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() {
@@ -115,6 +134,14 @@ void CVirtualKeyboardV1Resource::releasePressed() {
m_pressed.clear();
}
+void CVirtualKeyboardV1Resource::destroy() {
+ const auto RELEASEPRESSED = g_pConfigManager->getDeviceInt(m_name, "release_pressed_on_close", "input:virtualkeyboard:release_pressed_on_close");
+ if (RELEASEPRESSED)
+ releasePressed();
+ m_events.destroy.emit();
+ PROTO::virtualKeyboard->destroyResource(this);
+}
+
CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp
index c601c0fb..1ff9f161 100644
--- a/src/protocols/VirtualKeyboard.hpp
+++ b/src/protocols/VirtualKeyboard.hpp
@@ -30,6 +30,7 @@ class CVirtualKeyboardV1Resource {
SP<CZwpVirtualKeyboardV1> m_resource;
void releasePressed();
+ void destroy();
bool m_hasKeymap = false;
diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp
index 53123abe..8aa2f36a 100644
--- a/src/protocols/core/Seat.cpp
+++ b/src/protocols/core/Seat.cpp
@@ -305,8 +305,14 @@ CWLKeyboardResource::CWLKeyboardResource(SP<CWlKeyboard> resource_, SP<CWLSeatRe
sendKeymap(g_pSeatManager->m_keyboard.lock());
repeatInfo(g_pSeatManager->m_keyboard->m_repeatRate, g_pSeatManager->m_keyboard->m_repeatDelay);
- if (g_pSeatManager->m_state.keyboardFocus && g_pSeatManager->m_state.keyboardFocus->client() == m_resource->client())
- sendEnter(g_pSeatManager->m_state.keyboardFocus.lock());
+ if (g_pSeatManager->m_state.keyboardFocus && g_pSeatManager->m_state.keyboardFocus->client() == m_resource->client()) {
+ wl_array keys;
+ wl_array_init(&keys);
+
+ sendEnter(g_pSeatManager->m_state.keyboardFocus.lock(), &keys);
+
+ wl_array_release(&keys);
+ }
}
bool CWLKeyboardResource::good() {
@@ -334,7 +340,9 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) {
m_resource->sendKeymap(format, fd.get(), size);
}
-void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) {
+void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface, wl_array* keys) {
+ ASSERT(keys);
+
if (!m_owner || m_currentSurface == surface || !surface->getResource()->resource())
return;
@@ -351,12 +359,7 @@ void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) {
m_currentSurface = surface;
m_listeners.destroySurface = surface->m_events.destroy.listen([this] { sendLeave(); });
- wl_array arr;
- wl_array_init(&arr);
-
- m_resource->sendEnter(g_pSeatManager->nextSerial(m_owner.lock()), surface->getResource().get(), &arr);
-
- wl_array_release(&arr);
+ m_resource->sendEnter(g_pSeatManager->nextSerial(m_owner.lock()), surface->getResource().get(), keys);
}
void CWLKeyboardResource::sendLeave() {
diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp
index 0c14e52a..8b8f6004 100644
--- a/src/protocols/core/Seat.hpp
+++ b/src/protocols/core/Seat.hpp
@@ -12,6 +12,7 @@
#include <cstdint>
#include "../WaylandProtocol.hpp"
#include <wayland-server-protocol.h>
+#include <wayland-util.h>
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../helpers/math/Math.hpp"
@@ -104,7 +105,7 @@ class CWLKeyboardResource {
bool good();
void sendKeymap(SP<IKeyboard> keeb);
- void sendEnter(SP<CWLSurfaceResource> surface);
+ void sendEnter(SP<CWLSurfaceResource> surface, wl_array* keys);
void sendLeave();
void sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state);
void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);