Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions hyprtester/plugin/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ static SDispatchResult vkb(std::string in) {
}

static SDispatchResult scroll(std::string in) {
int by;
double by;
try {
by = std::stoi(in);
by = std::stod(in);
} catch (...) { return SDispatchResult{.success = false, .error = "invalid input"}; }

Debug::log(LOG, "tester: scrolling by {}", by);
Expand Down Expand Up @@ -272,4 +272,4 @@ APICALL EXPORT void PLUGIN_EXIT() {
g_mouse.reset();
g_keyboard->destroy();
g_keyboard.reset();
}
}
52 changes: 51 additions & 1 deletion hyprtester/src/tests/main/keybinds.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <filesystem>
#include <linux/input-event-codes.h>
#include <thread>
#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
Expand All @@ -11,7 +12,19 @@ using namespace Hyprutils::Memory;
static int ret = 0;
static std::string flagFile = "/tmp/hyprtester-keybinds.txt";

static void clearFlag() {
// Because i don't feel like changing someone elses code.
enum eKeyboardModifierIndex : uint8_t {
MOD_SHIFT = 1,
MOD_CAPS,
MOD_CTRL,
MOD_ALT,
MOD_MOD2,
MOD_MOD3,
MOD_META,
MOD_MOD5
};

static void clearFlag() {
std::filesystem::remove(flagFile);
}

Expand Down Expand Up @@ -393,6 +406,41 @@ static void testShortcutRepeatKeyRelease() {
Tests::killAllWindows();
}

static void testSubmap() {
const auto press = [](const uint32_t key, const uint32_t mod = 0) {
// +8 because udev -> XKB keycode.
getFromSocket("/dispatch plugin:test:keybind 1," + std::to_string(mod) + "," + std::to_string(key + 8));
getFromSocket("/dispatch plugin:test:keybind 0," + std::to_string(mod) + "," + std::to_string(key + 8));
};

NLog::log("{}Testing submaps", Colors::GREEN);
// submap 1 no resets
press(KEY_U, MOD_META);
EXPECT_CONTAINS(getFromSocket("/submap"), "submap1");
press(KEY_O);
Tests::waitUntilWindowsN(1);
EXPECT_CONTAINS(getFromSocket("/submap"), "submap1");
// submap 2 resets to submap 1
press(KEY_U);
EXPECT_CONTAINS(getFromSocket("/submap"), "submap2");
press(KEY_O);
Tests::waitUntilWindowsN(2);
EXPECT_CONTAINS(getFromSocket("/submap"), "submap1");
// submap 3 resets to default
press(KEY_I);
EXPECT_CONTAINS(getFromSocket("/submap"), "submap3");
press(KEY_O);
Tests::waitUntilWindowsN(3);
EXPECT_CONTAINS(getFromSocket("/submap"), "default");
// submap 1 reset via keybind
press(KEY_U, MOD_META);
EXPECT_CONTAINS(getFromSocket("/submap"), "submap1");
press(KEY_P);
EXPECT_CONTAINS(getFromSocket("/submap"), "default");

Tests::killAllWindows();
}

static bool test() {
NLog::log("{}Testing keybinds", Colors::GREEN);

Expand All @@ -413,6 +461,8 @@ static bool test() {
testShortcutRepeat();
testShortcutRepeatKeyRelease();

testSubmap();

clearFlag();
return !ret;
}
Expand Down
17 changes: 17 additions & 0 deletions hyprtester/test.conf
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,23 @@ bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous

bind = $mainMod, u, submap, submap1

submap = submap1
bind = , u, submap, submap2
bind = , i, submap, submap3
bind = , o, exec, $terminal
bind = , p, submap, reset

submap = submap2, submap1
bind = , o, exec, $terminal

submap = submap3, reset
bind = , o, exec, $terminal

submap = reset


##############################
### WINDOWS AND WORKSPACES ###
##############################
Expand Down
12 changes: 5 additions & 7 deletions src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2628,7 +2628,7 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
if ((!KEY.empty()) || multiKey) {
SParsedKey parsedKey = parseKey(KEY);

if (parsedKey.catchAll && m_currentSubmap.empty()) {
if (parsedKey.catchAll && m_currentSubmap.name.empty()) {
Debug::log(ERR, "Catchall not allowed outside of submap!");
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
}
Expand Down Expand Up @@ -3009,12 +3009,10 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
return {};
}

std::optional<std::string> CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
if (submap == "reset")
m_currentSubmap = "";
else
m_currentSubmap = submap;

std::optional<std::string> CConfigManager::handleSubmap(const std::string&, const std::string& submap) {
const auto SUBMAP = CConstVarList(submap);
m_currentSubmap.name = (SUBMAP[0] == "reset") ? "" : SUBMAP[0];
m_currentSubmap.reset = SUBMAP[1];
return {};
}

Expand Down
3 changes: 2 additions & 1 deletion src/config/ConfigManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "../helpers/memory/Memory.hpp"
#include "../desktop/WindowRule.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../managers/KeybindManager.hpp"

#include <hyprlang.hpp>

Expand Down Expand Up @@ -307,7 +308,7 @@ class CConfigManager {

Hyprutils::Animation::CAnimationConfigTree m_animationTree;

std::string m_currentSubmap = ""; // For storing the current keybind submap
SSubmap m_currentSubmap;

std::vector<SExecRequestedRule> m_execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty

Expand Down
8 changes: 4 additions & 4 deletions src/debug/HyprCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request
ret += "d";

ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb->modmask,
kb->submap, kb->key, kb->keycode, kb->catchAll, kb->description, kb->handler, kb->arg);
kb->submap.name, kb->key, kb->keycode, kb->catchAll, kb->description, kb->handler, kb->arg);
}
} else {
// json
Expand All @@ -1026,8 +1026,8 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request
"arg": "{}"
}},)#",
kb->locked ? "true" : "false", kb->mouse ? "true" : "false", kb->release ? "true" : "false", kb->repeat ? "true" : "false", kb->longPress ? "true" : "false",
kb->nonConsuming ? "true" : "false", kb->hasDescription ? "true" : "false", kb->modmask, escapeJSONStrings(kb->submap), escapeJSONStrings(kb->key), kb->keycode,
kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg));
kb->nonConsuming ? "true" : "false", kb->hasDescription ? "true" : "false", kb->modmask, escapeJSONStrings(kb->submap.name), escapeJSONStrings(kb->key),
kb->keycode, kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg));
}
trimTrailingComma(ret);
ret += "]";
Expand Down Expand Up @@ -1962,7 +1962,7 @@ static std::string getDescriptions(eHyprCtlOutputFormat format, std::string requ
}

static std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
std::string submap = g_pKeybindManager->getCurrentSubmap();
std::string submap = g_pKeybindManager->getCurrentSubmap().name;
if (submap.empty())
submap = "default";

Expand Down
14 changes: 8 additions & 6 deletions src/managers/KeybindManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SP<SKeybind> keybind) {
return mkKeysymSetMatches(keybind->sMkKeys, m_mkKeys);
}

std::string CKeybindManager::getCurrentSubmap() {
SSubmap CKeybindManager::getCurrentSubmap() {
return m_currentSelectedSubmap;
}

Expand Down Expand Up @@ -795,6 +795,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
found = true; // don't process keybinds on submap change.
break;
}
if (k->handler != "submap" && !k->submap.reset.empty())
setSubmap(k->submap.reset);
}

if (pressed && k->repeat) {
Expand Down Expand Up @@ -2390,19 +2392,19 @@ SDispatchResult CKeybindManager::toggleSwallow(std::string args) {

SDispatchResult CKeybindManager::setSubmap(std::string submap) {
if (submap == "reset" || submap.empty()) {
m_currentSelectedSubmap = "";
m_currentSelectedSubmap.name = "";
Debug::log(LOG, "Reset active submap to the default one.");
g_pEventManager->postEvent(SHyprIPCEvent{"submap", ""});
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap);
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap.name);
return {};
}

for (const auto& k : g_pKeybindManager->m_keybinds) {
if (k->submap == submap) {
m_currentSelectedSubmap = submap;
if (k->submap.name == submap) {
m_currentSelectedSubmap.name = submap;
Debug::log(LOG, "Changed keybind submap to {}", submap);
g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap});
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap);
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap.name);
return {};
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/managers/KeybindManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ class IKeyboard;

enum eMouseBindMode : int8_t;

struct SSubmap {
std::string name = "";
std::string reset = "";
bool operator==(const SSubmap& other) const {
return name == other.name;
}
};

struct SKeybind {
std::string key = "";
std::set<xkb_keysym_t> sMkKeys = {};
Expand All @@ -27,7 +35,7 @@ struct SKeybind {
std::string handler = "";
std::string arg = "";
bool locked = false;
std::string submap = "";
SSubmap submap = {};
std::string description = "";
bool release = false;
bool repeat = false;
Expand Down Expand Up @@ -63,7 +71,7 @@ struct SPressedKeyWithMods {
uint32_t keycode = 0;
uint32_t modmaskAtPressTime = 0;
bool sent = false;
std::string submapAtPress = "";
SSubmap submapAtPress = {};
Vector2D mousePosAtPress = {};
};

Expand Down Expand Up @@ -98,7 +106,7 @@ class CKeybindManager {
uint32_t keycodeToModifier(xkb_keycode_t);
void clearKeybinds();
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
std::string getCurrentSubmap();
SSubmap getCurrentSubmap();

std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_dispatchers;

Expand All @@ -117,7 +125,7 @@ class CKeybindManager {
private:
std::vector<SPressedKeyWithMods> m_pressedKeys;

inline static std::string m_currentSelectedSubmap = "";
inline static SSubmap m_currentSelectedSubmap = {};

std::vector<WP<SKeybind>> m_activeKeybinds;
WP<SKeybind> m_lastLongPressKeybind;
Expand Down
Loading