mirror of
https://github.com/hyprwm/Hyprland
synced 2025-12-28 04:30:06 +01:00
virtualkeyboard: Add options to skip releasing pressed keys on close and to skip sharing key states (#11214)
This commit is contained in:
parent
6491bb4fb7
commit
2be309de1d
23 changed files with 416 additions and 137 deletions
|
|
@ -8,9 +8,13 @@
|
|||
#include <src/config/ConfigDescriptions.hpp>
|
||||
#include <src/layout/IHyprLayout.hpp>
|
||||
#include <src/managers/LayoutManager.hpp>
|
||||
#include <src/managers/input/InputManager.hpp>
|
||||
#include <src/Compositor.hpp>
|
||||
#undef private
|
||||
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
using namespace Hyprutils::Utils;
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
// Do NOT change this function.
|
||||
|
|
@ -48,11 +52,95 @@ static SDispatchResult snapMove(std::string in) {
|
|||
return {};
|
||||
}
|
||||
|
||||
class CTestKeyboard : public IKeyboard {
|
||||
public:
|
||||
static SP<CTestKeyboard> create(bool isVirtual) {
|
||||
auto keeb = SP<CTestKeyboard>(new CTestKeyboard());
|
||||
keeb->m_self = keeb;
|
||||
keeb->m_isVirtual = isVirtual;
|
||||
keeb->m_shareStates = !isVirtual;
|
||||
return keeb;
|
||||
}
|
||||
|
||||
virtual bool isVirtual() {
|
||||
return m_isVirtual;
|
||||
}
|
||||
|
||||
virtual SP<Aquamarine::IKeyboard> aq() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void sendKey(uint32_t key, bool pressed) {
|
||||
auto event = IKeyboard::SKeyEvent{
|
||||
.timeMs = static_cast<uint32_t>(Time::millis(Time::steadyNow())),
|
||||
.keycode = key,
|
||||
.state = pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||
};
|
||||
updatePressed(event.keycode, pressed);
|
||||
m_keyboardEvents.key.emit(event);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
m_events.destroy.emit();
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_isVirtual;
|
||||
};
|
||||
|
||||
static SDispatchResult vkb(std::string in) {
|
||||
auto tkb0 = CTestKeyboard::create(false);
|
||||
auto tkb1 = CTestKeyboard::create(false);
|
||||
auto vkb0 = CTestKeyboard::create(true);
|
||||
|
||||
g_pInputManager->newKeyboard(tkb0);
|
||||
g_pInputManager->newKeyboard(tkb1);
|
||||
g_pInputManager->newKeyboard(vkb0);
|
||||
|
||||
CScopeGuard x([&] {
|
||||
tkb0->destroy();
|
||||
tkb1->destroy();
|
||||
vkb0->destroy();
|
||||
});
|
||||
|
||||
const auto& PRESSED = g_pInputManager->getKeysFromAllKBs();
|
||||
const uint32_t TESTKEY = 1;
|
||||
|
||||
tkb0->sendKey(TESTKEY, true);
|
||||
if (!std::ranges::contains(PRESSED, TESTKEY)) {
|
||||
return {
|
||||
.success = false,
|
||||
.error = "Expected pressed key not found",
|
||||
};
|
||||
}
|
||||
|
||||
tkb1->sendKey(TESTKEY, true);
|
||||
tkb0->sendKey(TESTKEY, false);
|
||||
if (!std::ranges::contains(PRESSED, TESTKEY)) {
|
||||
return {
|
||||
.success = false,
|
||||
.error = "Expected pressed key not found (kb share state)",
|
||||
};
|
||||
}
|
||||
|
||||
vkb0->sendKey(TESTKEY, true);
|
||||
tkb1->sendKey(TESTKEY, false);
|
||||
if (std::ranges::contains(PRESSED, TESTKEY)) {
|
||||
return {
|
||||
.success = false,
|
||||
.error = "Expected released key found in pressed (vkb no share state)",
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
PHANDLE = handle;
|
||||
|
||||
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:test", ::test);
|
||||
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:snapmove", ::snapMove);
|
||||
HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:test:vkb", ::vkb);
|
||||
|
||||
return {"hyprtestplugin", "hyprtestplugin", "Vaxry", "1.0"};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,9 @@ int main(int argc, char** argv, char** envp) {
|
|||
NLog::log("{}running plugin test", Colors::YELLOW);
|
||||
EXPECT(testPlugin(), true);
|
||||
|
||||
NLog::log("{}running vkb test from plugin", Colors::YELLOW);
|
||||
EXPECT(testVkb(), true);
|
||||
|
||||
// kill hyprland
|
||||
NLog::log("{}dispatching exit", Colors::YELLOW);
|
||||
getFromSocket("/dispatch exit");
|
||||
|
|
|
|||
|
|
@ -19,3 +19,13 @@ bool testPlugin() {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testVkb() {
|
||||
const auto RESPONSE = getFromSocket("/dispatch plugin:test:vkb");
|
||||
|
||||
if (RESPONSE != "ok") {
|
||||
NLog::log("{}Vkb tests failed, tests returned:\n{}{}", Colors::RED, Colors::RESET, RESPONSE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
bool testPlugin();
|
||||
bool testPlugin();
|
||||
bool testVkb();
|
||||
|
|
|
|||
|
|
@ -676,6 +676,23 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
|||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
|
|
@ -1150,6 +1167,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
|||
.type = CONFIG_OPTION_BOOL,
|
||||
.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.",
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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] {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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; });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class CVirtualKeyboardV1Resource {
|
|||
SP<CZwpVirtualKeyboardV1> m_resource;
|
||||
|
||||
void releasePressed();
|
||||
void destroy();
|
||||
|
||||
bool m_hasKeymap = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue