mirror of
https://github.com/hyprwm/Hyprland
synced 2025-12-24 19:10:04 +01:00
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) {
|
||||
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);
|
||||
|
|
@ -272,4 +272,4 @@ APICALL EXPORT void PLUGIN_EXIT() {
|
|||
g_mouse.reset();
|
||||
g_keyboard->destroy();
|
||||
g_keyboard.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include <filesystem>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <thread>
|
||||
#include "../../shared.hpp"
|
||||
#include "../../hyprctlCompat.hpp"
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -394,6 +407,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);
|
||||
|
||||
|
|
@ -414,6 +462,8 @@ static bool test() {
|
|||
testShortcutRepeat();
|
||||
testShortcutRepeatKeyRelease();
|
||||
|
||||
testSubmap();
|
||||
|
||||
clearFlag();
|
||||
return !ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,6 +297,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 ###
|
||||
##############################
|
||||
|
|
|
|||
|
|
@ -2630,7 +2630,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.";
|
||||
}
|
||||
|
|
@ -3011,12 +3011,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 {};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../desktop/WindowRule.hpp"
|
||||
#include "../managers/XWaylandManager.hpp"
|
||||
#include "../managers/KeybindManager.hpp"
|
||||
|
||||
#include <hyprlang.hpp>
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 += "]";
|
||||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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 {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
|
|
@ -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;
|
||||
|
|
@ -63,7 +71,7 @@ struct SPressedKeyWithMods {
|
|||
uint32_t keycode = 0;
|
||||
uint32_t modmaskAtPressTime = 0;
|
||||
bool sent = false;
|
||||
std::string submapAtPress = "";
|
||||
SSubmap submapAtPress = {};
|
||||
Vector2D mousePosAtPress = {};
|
||||
};
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue