sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit d166954782572f6ca3c36136c31b9e9e6e5efb2e
parent 648d2edf20bb3fb153660f48a27a03adfd121dea
Author: TUVIMEN <hexderm@gmail.com>
Date:   Fri,  6 Jun 2025 09:18:30 +0200

[dwm][patch][keysequence] Add new patch

Add patch that allows for defining sequential key bindings

Diffstat:
Adwm.suckless.org/patches/keysequence/index.md | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/keysequence/keysequence-20250606-0d6af14.diff | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 208 insertions(+), 0 deletions(-)

diff --git a/dwm.suckless.org/patches/keysequence/index.md b/dwm.suckless.org/patches/keysequence/index.md @@ -0,0 +1,50 @@ +keysequence +=========== + +Description +----------- + +This patch allows for defining sequential keybindings, for example `MOD+A W`. +This is done not through the `XGrabKey()` which is used for root bindings, +but by the `XGrabKeyboard()` so any key presses that are not defined will +stop the matching without passing them to programs. This behaviour is +less confusing. + +It defines new bindable function `keypress_other()` that as argument takes +a pointer to array of bindings. + + static Key keyseq_a[] = { + { 0, XK_t, setlayout, {.v = &layouts[0]}}, + { ShiftMask, XK_t, setlayout, {.v = &layouts[1]}}, + { MODKEY, XK_y, setlayout, {.v = &layouts[2]}}, + {0} + } + + static Key keys[] = { + { MODKEY, XK_a, keypress_other, {.v = keyseq_a}}, + {0} + } + +This assigns `MOD+a t`, `MOD+a T`, `MOD+a MOD+y` to changing layout, you can +nest bindings endlessly. + +Notice that now keybinding arrays are ended by `{0}` empty element, +this is necessary because `Arg` structure can take only pointer +sized elements, there's no place to specify size so it has to be +calculated while running. + +While typing sequence all events are ignored other than key presses +and mouse, moving mouse exits sequence. + +Save your hands! Don't make long sequences, stick to simple, easy to +access binding and use plain letters, realistically speaking you'll +use it for dmenu scripts, layout bindings, and other rarely used +commands. + +Download +-------- +* [keysequence-20250606-0d6af14.diff](keysequence-20250606-0d6af14.diff) + +Author +------ +* TUVIMEN <hexderm@gmail.com> diff --git a/dwm.suckless.org/patches/keysequence/keysequence-20250606-0d6af14.diff b/dwm.suckless.org/patches/keysequence/keysequence-20250606-0d6af14.diff @@ -0,0 +1,158 @@ +From 0d6af14efa1250631b081ad9d1f3aa0263221fd8 Mon Sep 17 00:00:00 2001 +From: TUVIMEN <hexderm@gmail.com> +Date: Fri, 6 Jun 2025 09:08:40 +0200 +Subject: [PATCH] [PATCH] 6.5 keysequence patch + +--- + config.def.h | 1 + + dwm.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 80 insertions(+), 7 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 9efa774..6104343 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -95,6 +95,7 @@ static const Key keys[] = { + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, ++ {0} + }; + + /* button definitions */ +diff --git a/dwm.c b/dwm.c +index f1d86b2..89a4bc5 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -28,6 +28,7 @@ + #include <stdlib.h> + #include <string.h> + #include <unistd.h> ++#include <time.h> + #include <sys/types.h> + #include <sys/wait.h> + #include <X11/cursorfont.h> +@@ -177,6 +178,7 @@ static void grabbuttons(Client *c, int focused); + static void grabkeys(void); + static void incnmaster(const Arg *arg); + static void keypress(XEvent *e); ++static void keypress_other(const Arg *arg); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); + static void mappingnotify(XEvent *e); +@@ -949,6 +951,13 @@ grabbuttons(Client *c, int focused) + } + } + ++static char ++key_not_empty(const Key *key) ++{ ++ static const Key empty = {0}; ++ return memcmp(key, &empty, sizeof(Key)) != 0; ++} ++ + void + grabkeys(void) + { +@@ -965,7 +974,7 @@ grabkeys(void) + if (!syms) + return; + for (k = start; k <= end; k++) +- for (i = 0; i < LENGTH(keys); i++) ++ for (i = 0; key_not_empty(keys+i); i++) + /* skip modifier codes, we do that ourselves */ + if (keys[i].keysym == syms[(k - start) * skip]) + for (j = 0; j < LENGTH(modifiers); j++) +@@ -996,8 +1005,8 @@ isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) + } + #endif /* XINERAMA */ + +-void +-keypress(XEvent *e) ++static void ++keypress_r(XEvent *e, const Key *keys) + { + unsigned int i; + KeySym keysym; +@@ -1005,11 +1014,74 @@ keypress(XEvent *e) + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); +- for (i = 0; i < LENGTH(keys); i++) ++ for (i = 0; key_not_empty(keys+i); i++) + if (keysym == keys[i].keysym +- && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) +- && keys[i].func) +- keys[i].func(&(keys[i].arg)); ++ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) ++ && keys[i].func) ++ keys[i].func(&(keys[i].arg)); ++} ++ ++static char ++grabkeyboard(void) //taken from dmenu ++{ ++ struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; ++ ++ /* try to grab keyboard, we may have to wait for another process to ungrab */ ++ for (int i = 0; i < 1000; i++) { ++ if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, ++ GrabModeAsync, CurrentTime) == GrabSuccess) ++ return 0; ++ nanosleep(&ts, NULL); ++ } ++ return 1; //failed ++} ++ ++static char ++keysym_is_modifier(KeySym s) ++{ ++ return (s == XK_Shift_L || ++ s == XK_Shift_R || ++ s == XK_Control_L || ++ s == XK_Control_R || ++ s == XK_Caps_Lock || ++ s == XK_Shift_Lock || ++ s == XK_Meta_L || ++ s == XK_Meta_R || ++ s == XK_Alt_L || ++ s == XK_Alt_R || ++ s == XK_Super_L || ++ s == XK_Super_R || ++ s == XK_Hyper_L || ++ s == XK_Hyper_R); ++} ++ ++void ++keypress_other(const Arg *arg) ++{ ++ if (grabkeyboard()) ++ return; ++ ++ XEvent ev; ++ while (!XNextEvent(dpy, &ev)) { ++ if (ev.type == ButtonPress) ++ break; ++ if (ev.type == KeyPress) { ++ KeySym keysym = XKeycodeToKeysym(dpy, (KeyCode)ev.xkey.keycode, 0); ++ if (keysym_is_modifier(keysym)) ++ continue; ++ keypress_r(&ev, (Key*)arg->v); ++ break; ++ } ++ } ++ ++ XUngrabKeyboard(dpy, CurrentTime); ++ grabkeys(); ++} ++ ++void ++keypress(XEvent *e) ++{ ++ keypress_r(e,keys); + } + + void +-- +2.49.0 +