- 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
@@ -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


Reply via email to