config: add automatic closing to submaps (#11760)
* Allow submaps to auto reset to parent.
* Really should be a stack instead.
If hyprlang would allow for { } i would be so happy.
* Fixed: Somewhat better way to do it..
Lets you define what submap you want to go to instead.
* squash! Fixed: Somewhat better way to do it..
* God i hate cf..
* Force clang-format on the whole thing..
* Removed {}.
* Added tests
Tests and reset fix.
This commit is contained in:
parent
6a01c399a9
commit
d599513d4a
8 changed files with 102 additions and 26 deletions
|
|
@ -205,9 +205,9 @@ static SDispatchResult vkb(std::string in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDispatchResult scroll(std::string in) {
|
static SDispatchResult scroll(std::string in) {
|
||||||
int by;
|
double by;
|
||||||
try {
|
try {
|
||||||
by = std::stoi(in);
|
by = std::stod(in);
|
||||||
} catch (...) { return SDispatchResult{.success = false, .error = "invalid input"}; }
|
} catch (...) { return SDispatchResult{.success = false, .error = "invalid input"}; }
|
||||||
|
|
||||||
Debug::log(LOG, "tester: scrolling by {}", by);
|
Debug::log(LOG, "tester: scrolling by {}", by);
|
||||||
|
|
@ -272,4 +272,4 @@ APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
g_mouse.reset();
|
g_mouse.reset();
|
||||||
g_keyboard->destroy();
|
g_keyboard->destroy();
|
||||||
g_keyboard.reset();
|
g_keyboard.reset();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <linux/input-event-codes.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "../../shared.hpp"
|
#include "../../shared.hpp"
|
||||||
#include "../../hyprctlCompat.hpp"
|
#include "../../hyprctlCompat.hpp"
|
||||||
|
|
@ -11,7 +12,19 @@ using namespace Hyprutils::Memory;
|
||||||
static int ret = 0;
|
static int ret = 0;
|
||||||
static std::string flagFile = "/tmp/hyprtester-keybinds.txt";
|
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);
|
std::filesystem::remove(flagFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,6 +407,41 @@ static void testShortcutRepeatKeyRelease() {
|
||||||
Tests::killAllWindows();
|
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() {
|
static bool test() {
|
||||||
NLog::log("{}Testing keybinds", Colors::GREEN);
|
NLog::log("{}Testing keybinds", Colors::GREEN);
|
||||||
|
|
||||||
|
|
@ -414,6 +462,8 @@ static bool test() {
|
||||||
testShortcutRepeat();
|
testShortcutRepeat();
|
||||||
testShortcutRepeatKeyRelease();
|
testShortcutRepeatKeyRelease();
|
||||||
|
|
||||||
|
testSubmap();
|
||||||
|
|
||||||
clearFlag();
|
clearFlag();
|
||||||
return !ret;
|
return !ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,23 @@ bindl = , XF86AudioPause, exec, playerctl play-pause
|
||||||
bindl = , XF86AudioPlay, exec, playerctl play-pause
|
bindl = , XF86AudioPlay, exec, playerctl play-pause
|
||||||
bindl = , XF86AudioPrev, exec, playerctl previous
|
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 ###
|
### WINDOWS AND WORKSPACES ###
|
||||||
##############################
|
##############################
|
||||||
|
|
|
||||||
|
|
@ -2630,7 +2630,7 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
||||||
if ((!KEY.empty()) || multiKey) {
|
if ((!KEY.empty()) || multiKey) {
|
||||||
SParsedKey parsedKey = parseKey(KEY);
|
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!");
|
Debug::log(ERR, "Catchall not allowed outside of submap!");
|
||||||
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
||||||
}
|
}
|
||||||
|
|
@ -3011,12 +3011,10 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
|
std::optional<std::string> CConfigManager::handleSubmap(const std::string&, const std::string& submap) {
|
||||||
if (submap == "reset")
|
const auto SUBMAP = CConstVarList(submap);
|
||||||
m_currentSubmap = "";
|
m_currentSubmap.name = (SUBMAP[0] == "reset") ? "" : SUBMAP[0];
|
||||||
else
|
m_currentSubmap.reset = SUBMAP[1];
|
||||||
m_currentSubmap = submap;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include "../helpers/memory/Memory.hpp"
|
#include "../helpers/memory/Memory.hpp"
|
||||||
#include "../desktop/WindowRule.hpp"
|
#include "../desktop/WindowRule.hpp"
|
||||||
#include "../managers/XWaylandManager.hpp"
|
#include "../managers/XWaylandManager.hpp"
|
||||||
|
#include "../managers/KeybindManager.hpp"
|
||||||
|
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
|
|
||||||
|
|
@ -307,7 +308,7 @@ class CConfigManager {
|
||||||
|
|
||||||
Hyprutils::Animation::CAnimationConfigTree m_animationTree;
|
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
|
std::vector<SExecRequestedRule> m_execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1000,7 +1000,7 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request
|
||||||
ret += "d";
|
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,
|
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 {
|
} else {
|
||||||
// json
|
// json
|
||||||
|
|
@ -1026,8 +1026,8 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request
|
||||||
"arg": "{}"
|
"arg": "{}"
|
||||||
}},)#",
|
}},)#",
|
||||||
kb->locked ? "true" : "false", kb->mouse ? "true" : "false", kb->release ? "true" : "false", kb->repeat ? "true" : "false", kb->longPress ? "true" : "false",
|
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->nonConsuming ? "true" : "false", kb->hasDescription ? "true" : "false", kb->modmask, escapeJSONStrings(kb->submap.name), escapeJSONStrings(kb->key),
|
||||||
kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg));
|
kb->keycode, kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg));
|
||||||
}
|
}
|
||||||
trimTrailingComma(ret);
|
trimTrailingComma(ret);
|
||||||
ret += "]";
|
ret += "]";
|
||||||
|
|
@ -1962,7 +1962,7 @@ static std::string getDescriptions(eHyprCtlOutputFormat format, std::string requ
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
|
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())
|
if (submap.empty())
|
||||||
submap = "default";
|
submap = "default";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,7 +643,7 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SP<SKeybind> keybind) {
|
||||||
return mkKeysymSetMatches(keybind->sMkKeys, m_mkKeys);
|
return mkKeysymSetMatches(keybind->sMkKeys, m_mkKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CKeybindManager::getCurrentSubmap() {
|
SSubmap CKeybindManager::getCurrentSubmap() {
|
||||||
return m_currentSelectedSubmap;
|
return m_currentSelectedSubmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -795,6 +795,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
|
||||||
found = true; // don't process keybinds on submap change.
|
found = true; // don't process keybinds on submap change.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (k->handler != "submap" && !k->submap.reset.empty())
|
||||||
|
setSubmap(k->submap.reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressed && k->repeat) {
|
if (pressed && k->repeat) {
|
||||||
|
|
@ -2390,19 +2392,19 @@ SDispatchResult CKeybindManager::toggleSwallow(std::string args) {
|
||||||
|
|
||||||
SDispatchResult CKeybindManager::setSubmap(std::string submap) {
|
SDispatchResult CKeybindManager::setSubmap(std::string submap) {
|
||||||
if (submap == "reset" || submap.empty()) {
|
if (submap == "reset" || submap.empty()) {
|
||||||
m_currentSelectedSubmap = "";
|
m_currentSelectedSubmap.name = "";
|
||||||
Debug::log(LOG, "Reset active submap to the default one.");
|
Debug::log(LOG, "Reset active submap to the default one.");
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"submap", ""});
|
g_pEventManager->postEvent(SHyprIPCEvent{"submap", ""});
|
||||||
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap);
|
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap.name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& k : g_pKeybindManager->m_keybinds) {
|
for (const auto& k : g_pKeybindManager->m_keybinds) {
|
||||||
if (k->submap == submap) {
|
if (k->submap.name == submap) {
|
||||||
m_currentSelectedSubmap = submap;
|
m_currentSelectedSubmap.name = submap;
|
||||||
Debug::log(LOG, "Changed keybind submap to {}", submap);
|
Debug::log(LOG, "Changed keybind submap to {}", submap);
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap});
|
g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap});
|
||||||
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap);
|
EMIT_HOOK_EVENT("submap", m_currentSelectedSubmap.name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,14 @@ class IKeyboard;
|
||||||
|
|
||||||
enum eMouseBindMode : int8_t;
|
enum eMouseBindMode : int8_t;
|
||||||
|
|
||||||
|
struct SSubmap {
|
||||||
|
std::string name = "";
|
||||||
|
std::string reset = "";
|
||||||
|
bool operator==(const SSubmap& other) const {
|
||||||
|
return name == other.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SKeybind {
|
struct SKeybind {
|
||||||
std::string key = "";
|
std::string key = "";
|
||||||
std::set<xkb_keysym_t> sMkKeys = {};
|
std::set<xkb_keysym_t> sMkKeys = {};
|
||||||
|
|
@ -27,7 +35,7 @@ struct SKeybind {
|
||||||
std::string handler = "";
|
std::string handler = "";
|
||||||
std::string arg = "";
|
std::string arg = "";
|
||||||
bool locked = false;
|
bool locked = false;
|
||||||
std::string submap = "";
|
SSubmap submap = {};
|
||||||
std::string description = "";
|
std::string description = "";
|
||||||
bool release = false;
|
bool release = false;
|
||||||
bool repeat = false;
|
bool repeat = false;
|
||||||
|
|
@ -63,7 +71,7 @@ struct SPressedKeyWithMods {
|
||||||
uint32_t keycode = 0;
|
uint32_t keycode = 0;
|
||||||
uint32_t modmaskAtPressTime = 0;
|
uint32_t modmaskAtPressTime = 0;
|
||||||
bool sent = false;
|
bool sent = false;
|
||||||
std::string submapAtPress = "";
|
SSubmap submapAtPress = {};
|
||||||
Vector2D mousePosAtPress = {};
|
Vector2D mousePosAtPress = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -98,7 +106,7 @@ class CKeybindManager {
|
||||||
uint32_t keycodeToModifier(xkb_keycode_t);
|
uint32_t keycodeToModifier(xkb_keycode_t);
|
||||||
void clearKeybinds();
|
void clearKeybinds();
|
||||||
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
|
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;
|
std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_dispatchers;
|
||||||
|
|
||||||
|
|
@ -117,7 +125,7 @@ class CKeybindManager {
|
||||||
private:
|
private:
|
||||||
std::vector<SPressedKeyWithMods> m_pressedKeys;
|
std::vector<SPressedKeyWithMods> m_pressedKeys;
|
||||||
|
|
||||||
inline static std::string m_currentSelectedSubmap = "";
|
inline static SSubmap m_currentSelectedSubmap = {};
|
||||||
|
|
||||||
std::vector<WP<SKeybind>> m_activeKeybinds;
|
std::vector<WP<SKeybind>> m_activeKeybinds;
|
||||||
WP<SKeybind> m_lastLongPressKeybind;
|
WP<SKeybind> m_lastLongPressKeybind;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue