refactor chainkeys patch

This commit is contained in:
atourist
2026-10-02 11:06:30 -07:00
parent f974a35dab
commit de72d2bb3c
3 changed files with 228 additions and 145 deletions
+11 -2
View File
@@ -7,9 +7,18 @@ Mod+chain is pressed. A subsequent keypress will be matched against bindings
for that chain key. If it is configured the action will be triggered, otherwise
the keypress will be ignored.
To use chainkeys, append the key after the argument in the keybindings. Example usage:
```c
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
{ MODKEY, XKB_KEY_s, setmfact, {.f = -0.05f}, XKB_KEY_h },
{ MODKEY, XKB_KEY_s, setmfact, {.f = +0.05f}, XKB_KEY_l },
```
Here, `MODKEY+i` triggers incnmaster to decrease nmaster, while `MODKEY+s` triggers a chain. After triggering the chain, pressing `h` or `l` changes the monitor's mfact and resets the chain.
### Download
- [git branch](https://codeberg.org/bencc/dwl/src/branch/chainkeys)
- [2024-05-20](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/chainkeys/chainkeys.patch)
- [chainkeys.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/chainkeys/chainkeys.patch) Latest version, applies to main branch, tested on commit dwl/dwl@e2038450f2
- [chainkeys_2024-05-20.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/chainkeys/chainkeys_2024-05-20.patch) Legacy version from 2024-05-20
### Authors
- [atourist](https://codeberg.org/atourist)
- [Ben Collerson](https://codeberg.org/bencc)
+60 -143
View File
@@ -1,157 +1,74 @@
From 226e204ec7fb6d6840a984ef8e8ec1d2514e985f Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Tue, 2 Jan 2024 10:33:59 +1000
Subject: [PATCH] chainkeys
---
config.def.h | 62 ++++++++++++++++++++++++++--------------------------
dwl.c | 23 ++++++++++++++++++-
2 files changed, 53 insertions(+), 32 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8f498d2f..1c182547 100644
--- a/config.def.h
+++ b/config.def.h
@@ -105,10 +105,10 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
#define MODKEY WLR_MODIFIER_ALT
diff --git a/Makefile b/Makefile
index 8304245..836cb87 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
- -Wfloat-conversion
+ -Wfloat-conversion -Wno-missing-field-initializers
#define TAGKEYS(KEY,SKEY,TAG) \
- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
+ { MODKEY, -1, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL, -1, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, SKEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,-1,SKEY,toggletag, {.ui = 1 << TAG} }
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
@@ -119,30 +119,30 @@ static const char *menucmd[] = { "wmenu-run", NULL };
static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
- /* modifier key function argument */
- { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
- { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
- { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
- { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
- { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
- { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
- { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
- { MODKEY, XKB_KEY_Return, zoom, {0} },
- { MODKEY, XKB_KEY_Tab, view, {0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
- { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
- { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
- { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
- { MODKEY, XKB_KEY_space, setlayout, {0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
- { MODKEY, XKB_KEY_e, togglefullscreen, {0} },
- { MODKEY, XKB_KEY_0, view, {.ui = ~0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
- { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
- { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
+ /* modifier chain, key function argument */
+ { MODKEY, -1, XKB_KEY_p, spawn, {.v = menucmd} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY, -1, XKB_KEY_j, focusstack, {.i = +1} },
+ { MODKEY, -1, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY, -1, XKB_KEY_i, incnmaster, {.i = +1} },
+ { MODKEY, -1, XKB_KEY_d, incnmaster, {.i = -1} },
+ { MODKEY, -1, XKB_KEY_h, setmfact, {.f = -0.05f} },
+ { MODKEY, -1, XKB_KEY_l, setmfact, {.f = +0.05f} },
+ { MODKEY, -1, XKB_KEY_Return, zoom, {0} },
+ { MODKEY, -1, XKB_KEY_Tab, view, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_C, killclient, {0} },
+ { MODKEY, -1, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, -1, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, -1, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, -1, XKB_KEY_space, setlayout, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_space, togglefloating, {0} },
+ { MODKEY, -1, XKB_KEY_e, togglefullscreen, {0} },
+ { MODKEY, -1, XKB_KEY_0, view, {.ui = ~0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_parenright, tag, {.ui = ~0} },
+ { MODKEY, -1, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY, -1, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
@@ -152,14 +152,14 @@ static const Key keys[] = {
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_Q, quit, {0} },
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
- { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
+ { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,-1,XKB_KEY_Terminate_Server, quit, {0} },
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
* do not remove them.
*/
-#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
+#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,-1,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
};
# CFLAGS / LDFLAGS
PKGS = wayland-server xkbcommon libinput $(XLIBS)
diff --git a/dwl.c b/dwl.c
index bf763dfc..05e667f8 100644
index 216deb5..af011ea 100644
--- a/dwl.c
+++ b/dwl.c
@@ -143,6 +143,7 @@ typedef struct {
typedef struct {
uint32_t mod;
+ int chain;
@@ -166,6 +166,7 @@ typedef struct {
xkb_keysym_t keysym;
void (*func)(const Arg *);
const Arg arg;
@@ -353,6 +354,7 @@ static const char broken[] = "broken";
+ xkb_keysym_t chain;
} Key;
typedef struct {
@@ -378,6 +379,7 @@ static void zoom(const Arg *arg);
/* variables */
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
+static int chainkey = -1;
+static xkb_keysym_t chainkey = 0;
static Client *focused_client;
static struct wl_display *dpy;
static struct wlr_backend *backend;
static struct wlr_scene *scene;
@@ -1438,11 +1440,30 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
static struct wl_event_loop *event_loop;
@@ -1735,9 +1737,21 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
* processing.
*/
const Key *k;
+ if (chainkey) {
+ for (k = keys; k < END(keys); k++) {
+ if (chainkey == k->keysym && sym == k->chain) {
+ chainkey = 0;
+ return k;
+ }
+ }
+ chainkey = 0;
+ return NULL;
+ }
for (k = keys; k < END(keys); k++) {
if (CLEANMASK(mods) == CLEANMASK(k->mod)
- && sym == k->keysym && k->func) {
+ && sym == k->keysym
+ && chainkey == -1
+ && k->chain == -1
+ && k->func) {
k->func(&k->arg);
return 1;
}
+ else if (sym == k->keysym
+ && chainkey != -1
+ && k->chain == chainkey
+ && k->func) {
+ k->func(&k->arg);
+ chainkey = -1;
+ return 1;
+ }
+ else if (CLEANMASK(mods) == CLEANMASK(k->mod)
+ && k->chain == (int)sym
+ && chainkey == -1
+ && k->func) {
+ chainkey = sym;
+ return 1;
+ }
- if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->keysym && k->func)
+ if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->keysym && k->func) {
+ if (k->chain) chainkey = k->keysym;
return k;
+ }
}
+ chainkey = -1;
return 0;
return NULL;
}
--
2.43.0
@@ -1771,7 +1785,7 @@ keypress(struct wl_listener *listener, void *data)
const Key *key = keybinding(group->mods, group->keysyms[i]);
if (key) {
consumed[event->keycode] = 1;
- key->func(&key->arg);
+ if (!chainkey) key->func(&key->arg);
handled = 1;
break;
}
@@ -1827,7 +1841,7 @@ keyrepeat(void *data)
for (int i = 0; i < 2; i++) {
const Key *key = keybinding(group->mods, group->keysyms[i]);
if (key) {
- key->func(&key->arg);
+ if (!chainkey) key->func(&key->arg);
break;
}
}
@@ -0,0 +1,157 @@
From 226e204ec7fb6d6840a984ef8e8ec1d2514e985f Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Tue, 2 Jan 2024 10:33:59 +1000
Subject: [PATCH] chainkeys
---
config.def.h | 62 ++++++++++++++++++++++++++--------------------------
dwl.c | 23 ++++++++++++++++++-
2 files changed, 53 insertions(+), 32 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8f498d2f..1c182547 100644
--- a/config.def.h
+++ b/config.def.h
@@ -105,10 +105,10 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
#define MODKEY WLR_MODIFIER_ALT
#define TAGKEYS(KEY,SKEY,TAG) \
- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
- { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
+ { MODKEY, -1, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL, -1, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, SKEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,-1,SKEY,toggletag, {.ui = 1 << TAG} }
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
@@ -119,30 +119,30 @@ static const char *menucmd[] = { "wmenu-run", NULL };
static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
- /* modifier key function argument */
- { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
- { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
- { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
- { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
- { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
- { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
- { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
- { MODKEY, XKB_KEY_Return, zoom, {0} },
- { MODKEY, XKB_KEY_Tab, view, {0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
- { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
- { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
- { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
- { MODKEY, XKB_KEY_space, setlayout, {0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
- { MODKEY, XKB_KEY_e, togglefullscreen, {0} },
- { MODKEY, XKB_KEY_0, view, {.ui = ~0} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
- { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
- { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
+ /* modifier chain, key function argument */
+ { MODKEY, -1, XKB_KEY_p, spawn, {.v = menucmd} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY, -1, XKB_KEY_j, focusstack, {.i = +1} },
+ { MODKEY, -1, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY, -1, XKB_KEY_i, incnmaster, {.i = +1} },
+ { MODKEY, -1, XKB_KEY_d, incnmaster, {.i = -1} },
+ { MODKEY, -1, XKB_KEY_h, setmfact, {.f = -0.05f} },
+ { MODKEY, -1, XKB_KEY_l, setmfact, {.f = +0.05f} },
+ { MODKEY, -1, XKB_KEY_Return, zoom, {0} },
+ { MODKEY, -1, XKB_KEY_Tab, view, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_C, killclient, {0} },
+ { MODKEY, -1, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, -1, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, -1, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, -1, XKB_KEY_space, setlayout, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_space, togglefloating, {0} },
+ { MODKEY, -1, XKB_KEY_e, togglefullscreen, {0} },
+ { MODKEY, -1, XKB_KEY_0, view, {.ui = ~0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_parenright, tag, {.ui = ~0} },
+ { MODKEY, -1, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY, -1, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
@@ -152,14 +152,14 @@ static const Key keys[] = {
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
- { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, -1, XKB_KEY_Q, quit, {0} },
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
- { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
+ { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,-1,XKB_KEY_Terminate_Server, quit, {0} },
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
* do not remove them.
*/
-#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
+#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,-1,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
};
diff --git a/dwl.c b/dwl.c
index bf763dfc..05e667f8 100644
--- a/dwl.c
+++ b/dwl.c
@@ -143,6 +143,7 @@ typedef struct {
typedef struct {
uint32_t mod;
+ int chain;
xkb_keysym_t keysym;
void (*func)(const Arg *);
const Arg arg;
@@ -353,6 +354,7 @@ static const char broken[] = "broken";
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
+static int chainkey = -1;
static struct wl_display *dpy;
static struct wlr_backend *backend;
static struct wlr_scene *scene;
@@ -1438,11 +1440,30 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
const Key *k;
for (k = keys; k < END(keys); k++) {
if (CLEANMASK(mods) == CLEANMASK(k->mod)
- && sym == k->keysym && k->func) {
+ && sym == k->keysym
+ && chainkey == -1
+ && k->chain == -1
+ && k->func) {
k->func(&k->arg);
return 1;
}
+ else if (sym == k->keysym
+ && chainkey != -1
+ && k->chain == chainkey
+ && k->func) {
+ k->func(&k->arg);
+ chainkey = -1;
+ return 1;
+ }
+ else if (CLEANMASK(mods) == CLEANMASK(k->mod)
+ && k->chain == (int)sym
+ && chainkey == -1
+ && k->func) {
+ chainkey = sym;
+ return 1;
+ }
}
+ chainkey = -1;
return 0;
}
--
2.43.0