{ MODKEY|ShiftMask, XK_x, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[LAYOUT_BOOKSHELF]} },
{ MODKEY, XK_y, setlayout, {.v = &layouts[LAYOUT_BOOKSTACK]} },
- { MODKEY, XK_u, setlayout, {.v = &layouts[LAYOUT_FLOAT]} },
+ { MODKEY, XK_r, setlayout, {.v = &layouts[LAYOUT_FLOAT]} },
+ { MODKEY, XK_i, kbptr_move, {.ui = KBPTR_NORTH} },
+ { MODKEY | ShiftMask, XK_i, kbptr_move, {.ui = KBPTR_NORTH | KBPTR_HALFSTEP} },
+ { MODKEY, XK_l, kbptr_move, {.ui = KBPTR_EAST} },
+ { MODKEY | ShiftMask, XK_l, kbptr_move, {.ui = KBPTR_EAST | KBPTR_HALFSTEP} },
+ { MODKEY, XK_k, kbptr_move, {.ui = KBPTR_SOUTH} },
+ { MODKEY | ShiftMask, XK_k, kbptr_move, {.ui = KBPTR_SOUTH | KBPTR_HALFSTEP} },
+ { MODKEY, XK_j, kbptr_move, {.ui = KBPTR_WEST} },
+ { MODKEY | ShiftMask, XK_j, kbptr_move, {.ui = KBPTR_WEST | KBPTR_HALFSTEP} },
+ { MODKEY, XK_u, kbptr_move, {.ui = KBPTR_CENTER} },
+ { MODKEY, XK_semicolon, kbptr_click, {.ui = KBPTR_LEFT} },
+ { MODKEY | ShiftMask, XK_semicolon, kbptr_click, {.ui = KBPTR_RIGHT} },
+ { MODKEY | ControlMask, XK_semicolon, kbptr_click, {.ui = KBPTR_MIDDLE} },
#ifndef M10K
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
* To understand everything else, start reading main().
*/
#define M10K 1
+#define _DEFAULT_SOURCE
#include <errno.h>
#include <locale.h>
int monitor;
};
+#define KBPTR_CENTER 0
+#define KBPTR_NORTH (1 << 1)
+#define KBPTR_EAST (1 << 2)
+#define KBPTR_SOUTH (1 << 3)
+#define KBPTR_WEST (1 << 4)
+#define KBPTR_DMASK (KBPTR_NORTH | KBPTR_EAST | KBPTR_SOUTH | KBPTR_WEST)
+#define KBPTR_HALFSTEP (1 << 0)
+
+#define KBPTR_LEFT Button1
+#define KBPTR_MIDDLE Button2
+#define KBPTR_RIGHT Button3
+
+struct kbptr {
+ int x;
+ int y;
+ int vstride;
+ int hstride;
+};
+
+static void kbptr_move(const union arg *arg);
+static void kbptr_click(const union arg *arg);
+
+static struct kbptr kbptr = { 0, 0, 0, 0 };
+
/* function declarations */
static void applyrules(struct client *c);
static Bool applysizehints(struct client *c, int *x, int *y,
return(exists);
}
+static void kbptr_move(const union arg *arg)
+{
+ struct client *client;
+ unsigned int dir;
+ unsigned int stepsize;
+
+ if(!selmon || !selmon->sel) {
+ return;
+ }
+
+ client = selmon->sel;
+ dir = arg->ui & KBPTR_DMASK;
+ stepsize = arg->ui & KBPTR_HALFSTEP;
+
+ switch(dir) {
+ case KBPTR_CENTER:
+ kbptr.x = client->geom.w / 2;
+ kbptr.y = client->geom.h / 2;
+ kbptr.hstride = kbptr.x / 2;
+ kbptr.vstride = kbptr.y / 2;
+ break;
+
+ case KBPTR_NORTH:
+ kbptr.vstride >>= stepsize;
+ kbptr.y -= kbptr.vstride;
+ kbptr.vstride /= 2;
+ break;
+
+ case KBPTR_EAST:
+ kbptr.hstride >>= stepsize;
+ kbptr.x += kbptr.hstride;
+ kbptr.hstride /= 2;
+ break;
+
+ case KBPTR_SOUTH:
+ kbptr.vstride >>= stepsize;
+ kbptr.y += kbptr.vstride;
+ kbptr.vstride /= 2;
+ break;
+
+ case KBPTR_WEST:
+ kbptr.hstride >>= stepsize;
+ kbptr.x -= kbptr.hstride;
+ kbptr.hstride /= 2;
+ break;
+
+ default:
+ return;
+ }
+
+ XWarpPointer(dpy, None, client->win,
+ 0, 0, 0, 0,
+ kbptr.x, kbptr.y);
+
+ return;
+}
+
+static int do_button(struct client *client,
+ const unsigned int button,
+ const unsigned int pressrelease)
+{
+ XButtonEvent event;
+ unsigned int mask;
+ unsigned int state;
+ int err;
+
+ switch(pressrelease) {
+ case ButtonPress:
+ mask = ButtonPressMask;
+ state = 0;
+ break;
+
+ case ButtonRelease:
+ /*
+ * If the button is released, this means it must have
+ * been pressed. Hence, the button's mask must be set.
+ */
+ mask = ButtonReleaseMask;
+ state = button << 8;
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+
+ err = XQueryPointer(dpy, client->win,
+ &event.root, &event.window,
+ &event.x_root, &event.y_root,
+ &event.x, &event.y,
+ &event.state);
+
+ if(err < 0) {
+ fprintf(stderr, "Failed to query pointer location\n");
+ return(-EIO);
+ }
+
+ event.type = pressrelease;
+ event.display = dpy;
+ event.window = client->win;
+ event.subwindow = None;
+ event.time = CurrentTime;
+
+ event.state = state;
+ event.button = button;
+ event.same_screen = True;
+
+ err = XSendEvent(dpy, client->win, True, mask, (XEvent*)&event);
+
+ if(err < 0) {
+ fprintf(stderr, "Couldn't send event\n");
+ return(-EIO);
+ }
+
+ err = XFlush(dpy);
+
+ if(err < 0) {
+ fprintf(stderr, "Couldn't flush event queue\n");
+ return(-EIO);
+ }
+
+ return(0);
+}
+
+static void kbptr_click(const union arg *arg)
+{
+ struct client *client;
+
+ if(!selmon || !selmon->sel) {
+ return;
+ }
+
+ client = selmon->sel;
+
+ do_button(client, arg->ui, ButtonPress);
+ usleep(100000);
+ do_button(client, arg->ui, ButtonRelease);
+
+ return;
+}
+
void setfocus(struct client *c)
{
+ union arg ptr_dest;
+
if(!c->neverfocus) {
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
}
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->geom.w / 2, c->geom.h / 2);
+ ptr_dest.ui = KBPTR_CENTER;
+ kbptr_move(&ptr_dest);
+
sendevent(c->win, wmatom[WMTakeFocus], NoEventMask,
wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);