JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
buffer key presses between spawn and window open
authorJason Woofenden <jason@jasonwoof.com>
Sat, 18 Apr 2015 00:40:42 +0000 (20:40 -0400)
committerJason Woofenden <jason@jasonwoof.com>
Sat, 18 Apr 2015 00:40:42 +0000 (20:40 -0400)
dwm.c

diff --git a/dwm.c b/dwm.c
index 5e9b184..dc9f318 100644 (file)
--- a/dwm.c
+++ b/dwm.c
@@ -177,6 +177,7 @@ static long getstate(Window w);
 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
 static void grabbuttons(Client *c, Bool focused);
 static void grabkeys(void);
+static void grab_typing_keys(void);
 static void incnmaster(const Arg *arg);
 static void keypress(XEvent *e);
 static void killclient(const Arg *arg);
@@ -200,6 +201,7 @@ static void restack(Monitor *m);
 static void run(void);
 static void scan(void);
 static Bool sendevent(Client *c, Atom proto);
+static void send_keycode(KeyCode key);
 static void sendmon(Client *c, Monitor *m);
 static void setclientstate(Client *c, long state);
 static void setfocus(Client *c);
@@ -240,6 +242,9 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee);
 static void zoom(const Arg *arg);
 
 /* variables */
+static KeyCode key_buffer[100];
+static int key_buffer_len = 0;
+static Bool key_buffering = False;
 static const char broken[] = "broken";
 static char stext[256];
 static int screen;
@@ -1056,6 +1061,32 @@ grabkeys(void) {
                                for(j = 0; j < LENGTH(modifiers); j++)
                                        XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
                                                 True, GrabModeAsync, GrabModeAsync);
+               if(key_buffering)
+                       grab_typing_keys();
+       }
+}
+
+void
+grab_typing_keys(void) {
+       updatenumlockmask();
+       {
+               unsigned int i, j;
+               unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
+               KeySym typing_keys[] = {
+                       XK_space, XK_Return, XK_period, XK_slash, XK_minus, XK_apostrophe,
+                       XK_A, XK_B, XK_C, XK_D, XK_E, XK_F, XK_G, XK_H, XK_I, XK_J, XK_K,
+                       XK_L, XK_M, XK_N, XK_O, XK_P, XK_Q, XK_R, XK_S, XK_T, XK_U, XK_V,
+                       XK_W, XK_X, XK_Y, XK_Z, XK_0, XK_1, XK_2, XK_3, XK_4, XK_5, XK_6,
+                       XK_7, XK_8, XK_9,
+               };
+
+               KeyCode code;
+
+               for(i = 0; i < LENGTH(typing_keys); i++)
+                       if((code = XKeysymToKeycode(dpy, typing_keys[i])))
+                               for(j = 0; j < LENGTH(modifiers); j++)
+                                       XGrabKey(dpy, code, modifiers[j], root,
+                                                True, GrabModeAsync, GrabModeAsync);
        }
 }
 
@@ -1077,18 +1108,60 @@ isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
 #endif /* XINERAMA */
 
 void
+send_keycode(KeyCode key) {
+       XKeyEvent event;
+       if(!selmon->sel) {
+               return;
+       }
+       event.display = dpy;
+       event.root = root;
+       event.window = selmon->sel->win;
+       event.subwindow = None;
+       event.same_screen = True;
+       event.x = 1;
+       event.y = 1;
+       event.x_root = 1;
+       event.y_root = 1;
+       event.time = CurrentTime;
+       event.state = 0; // modifiers
+       event.keycode = key;
+       event.type = KeyPress;
+       XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
+       event.type = KeyRelease;
+       XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
+}
+
+void
 keypress(XEvent *e) {
        unsigned int i;
        KeySym keysym;
        XKeyEvent *ev;
+       Bool called = False;
 
        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)
-               && keys[i].func)
+               && keys[i].func) {
                        keys[i].func(&(keys[i].arg));
+                       called = True;
+               }
+       if(!called) {
+               if(key_buffering) {
+                       if(key_buffer_len == LENGTH(key_buffer)) {
+                               // buffer full, bail
+                               key_buffer_len = 0;
+                               key_buffering = False;
+                               grabkeys(); // stop grabbing typing keys
+                       } else {
+                               key_buffer[key_buffer_len] = (KeyCode)ev->keycode;
+                               key_buffer_len += 1;
+                       }
+               } else {
+                       send_keycode(ev->keycode);
+               }
+       }
 }
 
 void
@@ -1111,6 +1184,7 @@ manage(Window w, XWindowAttributes *wa) {
        Client *c, *t = NULL;
        Window trans = None;
        XWindowChanges wc;
+       int i;
 
        if(!(c = calloc(1, sizeof(Client))))
                die("fatal: could not malloc() %u bytes\n", sizeof(Client));
@@ -1167,6 +1241,16 @@ manage(Window w, XWindowAttributes *wa) {
        arrange(c->mon);
        XMapWindow(dpy, c->win);
        focus(c);
+       if(key_buffering) {
+               key_buffering = False;
+               grabkeys(); // stop grabbing typing keys
+               if(key_buffer_len > 0) {
+                       for(i = 0; i < key_buffer_len; ++i) {
+                               send_keycode(key_buffer[i]);
+                       }
+               }
+               key_buffer_len = 0;
+       }
 }
 
 void
@@ -1725,6 +1809,9 @@ spawn(const Arg *arg) {
        }
        if(arg->v == dmenucmd)
                dmenumon[0] = '0' + selmon->num;
+       key_buffering = True;
+       key_buffer_len = 0;
+       grab_typing_keys();
        if(fork() == 0) {
                if(dpy)
                        close(ConnectionNumber(dpy));