[hackers] [dwm][PATCH] ratpoison-like prefix key

From: Philip Linde <linde.philip_AT_gmail.com>
Date: Wed, 8 May 2019 22:21:09 +0200

- Run "prefix" to enter prefix mode.
- Prefix mode is indicated by a flag in the tag bar.
- While prefix mode is enabled, MODKEY is ignored in all bindings.
- Executing prefix while in prefix mode will send the keysym/mod
  combination of its argument to the active window.
- Executing any key-bound command while in prefix mode will exit prefix
  mode.
---
 config.def.h |  2 ++
 dwm.c        | 51 ++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..b14b678 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -94,6 +94,8 @@ static Key keys[] = {
 	TAGKEYS(                        XK_8,                      7)
 	TAGKEYS(                        XK_9,                      8)
 	{ MODKEY|ShiftMask,             XK_q,      quit,           {0} },
+	{ ControlMask,                  XK_t,      prefix,         {.c = { ControlMask, XK_t } } },
+	{ MODKEY,                       XK_Escape, noop,           {0} },
 };
 
 /* button definitions */
diff --git a/dwm.c b/dwm.c
index 4465af1..43714ae 100644
--- a/dwm.c
+++ b/dwm.c
_AT_@ -67,11 +67,17 @@ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms *
 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
        ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
 
+typedef struct {
+	unsigned int mod;
+	KeySym keysym;
+} Combo;
+
 typedef union {
 	int i;
 	unsigned int ui;
 	float f;
 	const void *v;
+	Combo c;
 } Arg;
 
 typedef struct {
_AT_@ -233,6 +239,8 @@ static int xerror(Display *dpy, XErrorEvent *ee);
 static int xerrordummy(Display *dpy, XErrorEvent *ee);
 static int xerrorstart(Display *dpy, XErrorEvent *ee);
 static void zoom(const Arg *arg);
+static void prefix(const Arg *arg);
+static void noop(const Arg *arg);
 
 /* variables */
 static const char broken[] = "broken";
_AT_@ -243,6 +251,7 @@ static int bh, blw = 0;      /* bar geometry */
 static int lrpad;            /* sum of left and right padding for text */
 static int (*xerrorxlib)(Display *, XErrorEvent *);
 static unsigned int numlockmask = 0;
+static unsigned int prefixmask = ~0;
 static void (*handler[LASTEvent]) (XEvent *) = {
 	[ButtonPress] = buttonpress,
 	[ClientMessage] = clientmessage,
_AT_@ -699,6 +708,7 @@ drawbar(Monitor *m)
 	int boxs = drw->fonts->h / 9;
 	int boxw = drw->fonts->h / 6 + 2;
 	unsigned int i, occ = 0, urg = 0;
+	char *prefixmode;
 	Client *c;
 
 	/* draw status first so it can be overdrawn by tags later */
_AT_@ -728,6 +738,9 @@ drawbar(Monitor *m)
 	drw_setscheme(drw, scheme[SchemeNorm]);
 	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
 
+	prefixmode = prefixmask == ~MODKEY ? "⚑" : " ";
+	x = drw_text(drw, x, 0, TEXTW(prefixmode), bh, lrpad / 2, prefixmode, 0);
+
 	if ((w = m->ww - sw - x) > bh) {
 		if (m->sel) {
 			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
_AT_@ -958,8 +971,8 @@ grabkeys(void)
 		for (i = 0; i < LENGTH(keys); i++)
 			if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
 				for (j = 0; j < LENGTH(modifiers); j++)
-					XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
-						True, GrabModeAsync, GrabModeAsync);
+					XGrabKey(dpy, code, (keys[i].mod & prefixmask) | modifiers[j],
+						root, True, GrabModeAsync, GrabModeAsync);
 	}
 }
 
_AT_@ -988,14 +1001,23 @@ keypress(XEvent *e)
 	unsigned int i;
 	KeySym keysym;
 	XKeyEvent *ev;
+	unsigned int prevmask;
 
+	prevmask = prefixmask;
 	ev = &e->xkey;
 	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
 	for (i = 0; i < LENGTH(keys); i++)
 		if (keysym == keys[i].keysym
-		&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+		&& CLEANMASK(keys[i].mod & prefixmask) == CLEANMASK(ev->state)
 		&& keys[i].func)
 			keys[i].func(&(keys[i].arg));
+
+	if (prevmask == prefixmask)
+		prefixmask = ~0;
+	if (prevmask != prefixmask) {
+		drawbar(selmon);
+		grabkeys();
+	}
 }
 
 void
_AT_@ -2124,6 +2146,29 @@ zoom(const Arg *arg)
 	pop(c);
 }
 
+void
+prefix(const Arg *arg)
+{
+	unsigned int keycode;
+	XEvent fwd = {0};
+
+	keycode = XKeysymToKeycode(dpy, arg->c.keysym);
+	if (selmon->sel && prefixmask == ~MODKEY) {
+		fwd.xkey.type = KeyPress;
+		fwd.xkey.display = dpy;
+		fwd.xkey.window = selmon->sel->win;
+		fwd.xkey.state = arg->c.mod;
+		fwd.xkey.time = CurrentTime;
+		fwd.xkey.keycode = keycode;
+		XSendEvent(dpy, selmon->sel->win, False, KeyPressMask, &fwd);
+	} else {
+		prefixmask = ~MODKEY;
+	}
+}
+
+void
+noop(const Arg *arg) { }
+
 int
 main(int argc, char *argv[])
 {
-- 
2.21.0
Received on Wed May 08 2019 - 22:21:09 CEST

This archive was generated by hypermail 2.3.0 : Wed May 08 2019 - 22:24:22 CEST