From b294aff4ecd506ec857c5b11447a01eb5da4bbea Mon Sep 17 00:00:00 2001 From: Philip Linde Date: Wed, 8 May 2019 02:55:23 +0200 Subject: [PATCH] Implement ratpoison-like prefix key - Run "prefix" to enter prefix mode. - Prefix mode is indicated by a flag in the tag bar. - While prefix mode is enabled, MODKEY becomes irrelevant 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..aaee36b 100644 --- a/config.def.h +++ b/config.def.h @@ -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 @@ -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 { @@ -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"; @@ -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, @@ -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 */ @@ -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]); @@ -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); } } @@ -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 @@ -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