paulo@0: /* paulo@0: * Visual user-directed binary search for something to point your mouse at. paulo@0: */ paulo@0: paulo@0: #include "config.h" paulo@0: paulo@0: #include paulo@0: #include paulo@0: #include paulo@0: paulo@0: #include paulo@0: #include paulo@0: #include paulo@0: #include paulo@0: #include paulo@0: paulo@0: Display *dpy; paulo@0: Window root; paulo@0: XWindowAttributes attr; paulo@0: int drag = 0; paulo@0: int allmoves = 0; paulo@0: int allhits = 0; paulo@0: int allclicks = 0; paulo@0: int ninegrid_default = 0; paulo@0: int ninegrid_n_switch = 0; paulo@0: int ninegrid = 0; paulo@0: paulo@0: struct /* undo stack */ paulo@0: { paulo@0: int x[N_UNDO]; paulo@0: int y[N_UNDO]; paulo@0: int w[N_UNDO]; paulo@0: int h[N_UNDO]; paulo@0: int ninegrid[N_UNDO]; paulo@0: } u; paulo@0: paulo@0: void toggleninegrid() { paulo@0: if (ninegrid) paulo@0: ninegrid = 0; paulo@0: else paulo@0: ninegrid = 1; paulo@0: } paulo@0: paulo@0: void stats(int hits, int moves) { paulo@0: allhits += hits; paulo@0: allmoves += moves; paulo@0: allclicks++; paulo@0: printf("hits=%d, moves=%d \n", hits, moves); paulo@0: printf("total hits=%d, total moves=%d, total clicks=%d, avg. hit/click=%.2f, avg. moves/click=%.2f \n", allhits, allmoves, allclicks, (float)allhits/(float)allclicks, (float)allmoves/(float)allclicks); paulo@0: fflush(stdout); fflush(stderr); // force buffers to write out paulo@0: } paulo@0: paulo@0: void grab(char *keyname, int mods) { paulo@0: int key; paulo@0: paulo@0: key = XKeysymToKeycode(dpy, XStringToKeysym(keyname)); paulo@0: XGrabKey(dpy, key, mods, root, False, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: XGrabKey(dpy, key, mods | CAPSLOCKMASK, root, False, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: XGrabKey(dpy, key, mods | NUMLOCKMASK, root, False, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: XGrabKey(dpy, key, mods | CAPSLOCKMASK | NUMLOCKMASK, root, False, paulo@0: GrabModeAsync, GrabModeAsync); paulo@0: } paulo@0: paulo@0: void ungrab(char *keyname, int mod) { paulo@0: int key; paulo@0: paulo@0: key = XKeysymToKeycode(dpy, XStringToKeysym(keyname)); paulo@0: XUngrabKey(dpy, key, mod, root); paulo@0: XUngrabKey(dpy, key, mod | CAPSLOCKMASK, root); paulo@0: XUngrabKey(dpy, key, mod | NUMLOCKMASK, root); paulo@0: XUngrabKey(dpy, key, mod | CAPSLOCKMASK | NUMLOCKMASK, root); paulo@0: } paulo@0: paulo@0: void buttondown(int i) { paulo@0: XTestFakeButtonEvent(dpy, i, True, 50); paulo@0: } paulo@0: paulo@0: void buttonup(int i) { paulo@0: XTestFakeButtonEvent(dpy, i, False, 50); paulo@0: } paulo@0: paulo@0: void warppointer(int x, int y, int w, int h) { paulo@0: XWarpPointer(dpy, None, root, 0, 0, 0, 0, x + w/2, y + h/2); paulo@0: } paulo@0: paulo@0: /* operations for undo */ paulo@0: void undo_stack_push(int x, int y, int w, int h) { paulo@0: int i; paulo@0: paulo@0: if (x >= 0 && y >= 0 && w > 0 && h > 0) { paulo@0: fprintf(stderr,"undo_stack_push success: @(%d,%d) #(%d,%d)\n", x, y, w, h); paulo@0: for (i=N_UNDO-1; i>0; i--) { paulo@0: u.x[i] = u.x[i-1]; paulo@0: u.y[i] = u.y[i-1]; paulo@0: u.w[i] = u.w[i-1]; paulo@0: u.h[i] = u.h[i-1]; paulo@0: u.ninegrid[i] = u.ninegrid[i-1]; paulo@0: } paulo@0: u.x[0] = x; paulo@0: u.y[0] = y; paulo@0: u.w[0] = w; paulo@0: u.h[0] = h; paulo@0: u.ninegrid[0] = ninegrid; paulo@0: } paulo@0: } paulo@0: paulo@0: int undo_stack_pop(int *x, int *y, int *w, int *h, int *ninegrid) { paulo@0: int i; paulo@0: int ret = 0; paulo@0: paulo@0: int rx = u.x[0]; paulo@0: int ry = u.y[0]; paulo@0: int rw = u.w[0]; paulo@0: int rh = u.h[0]; paulo@0: int rninegrid = u.ninegrid[0]; paulo@0: paulo@0: if (rx >= 0 && ry >= 0 && rw > 0 && rh > 0) { paulo@0: fprintf(stderr,"undo_stack_pop success: @(%d,%d) #(%d,%d)\n", *x, *y, *w, *h); paulo@0: ret = 1; // return success paulo@0: for (i=0; i 0) *x -= *w; // shift left paulo@0: } paulo@0: if (chk_keysym(keysym, KEY_DOWN) || chk_keysym(keysym, KEY_DOWNLEFT) || chk_keysym(keysym, KEY_DOWNRIGHT)) { paulo@0: if ((*y + *h) < attr.height) *y += *h; // shift down paulo@0: } paulo@0: if (chk_keysym(keysym, KEY_UP) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_UPRIGHT)) { paulo@0: if (*y > 0) *y -= *h; // shift up paulo@0: } paulo@0: if (chk_keysym(keysym, KEY_RIGHT) || chk_keysym(keysym, KEY_UPRIGHT) || chk_keysym(keysym, KEY_DOWNRIGHT)) { paulo@0: if ((*x + *w) < attr.width) *x += *w; // shift right paulo@0: } paulo@0: } else { paulo@0: if (ninegrid) { paulo@0: if (chk_keysym(keysym, KEY_UPLEFT)) { paulo@0: *w /= 3; *h /= 3; // split upper left paulo@0: } else if (chk_keysym(keysym, KEY_UP)) { paulo@0: *w /= 3; *h /= 3; // split up paulo@0: *x += *w; paulo@0: } else if (chk_keysym(keysym, KEY_UPRIGHT)) { paulo@0: *w /= 3; *h /= 3; // split upper right paulo@0: *x += *w * 2; paulo@0: } else if (chk_keysym(keysym, KEY_LEFT)) { paulo@0: *w /= 3; *h /= 3; // split left paulo@0: *y += *h; paulo@0: } else if (chk_keysym(keysym, KEY_CENTER)) { paulo@0: *w /= 3; *h /= 3; // split center paulo@0: *x += *w; *y += *h; paulo@0: } else if (chk_keysym(keysym, KEY_RIGHT)) { paulo@0: *w /= 3; *h /= 3; // split right paulo@0: *x += *w * 2; *y += *h; paulo@0: } else if (chk_keysym(keysym, KEY_DOWNLEFT)) { paulo@0: *w /= 3; *h /= 3; // split bottom left paulo@0: *y += *h * 2; paulo@0: } else if (chk_keysym(keysym, KEY_DOWN)) { paulo@0: *w /= 3; *h /= 3; // split down paulo@0: *x += *w; *y += *h * 2; paulo@0: } else if (chk_keysym(keysym, KEY_DOWNRIGHT)) { paulo@0: *w /= 3; *h /= 3; // split bottom right paulo@0: *x += *w * 2; *y += *h * 2; paulo@0: } paulo@0: } else { paulo@0: if (chk_keysym(keysym, KEY_LEFT) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_DOWNLEFT)) { paulo@0: *w /= 2; // split left paulo@0: } paulo@0: if (chk_keysym(keysym, KEY_DOWN) || chk_keysym(keysym, KEY_DOWNLEFT) || chk_keysym(keysym, KEY_DOWNRIGHT)) { paulo@0: *h /= 2; // split down paulo@0: *y += *h; paulo@0: } paulo@0: if (chk_keysym(keysym, KEY_UP) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_UPRIGHT)) { paulo@0: *h /= 2; // split up paulo@0: } paulo@0: if (chk_keysym(keysym, KEY_RIGHT) || chk_keysym(keysym, KEY_UPRIGHT) || chk_keysym(keysym, KEY_DOWNRIGHT)) { paulo@0: *w /= 2; // split right paulo@0: *x += *w; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: if (ox != *x || oy != *y || ow != *w || oh != *h) { paulo@0: undo_stack_push(ox, oy, ow, oh); paulo@0: *moves += 1; paulo@0: } paulo@0: else if (chk_keysym(keysym, KEY_UNDO)) { paulo@0: int i, j; paulo@0: paulo@0: if (mod & SHIFTMASK) j = 0; paulo@0: else j = SHIFT_N_UNDO-1; paulo@0: paulo@0: for (i=j; i= ninegrid_n_switch) paulo@0: ninegrid = 0; paulo@0: hits++; paulo@0: XMoveResizeWindow(dpy, zone, x, y, w, h); paulo@0: drawquadrants(zone, w, h); paulo@0: } else paulo@0: done++; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: // end mouse key paulo@0: XUngrabKeyboard(dpy, CurrentTime); paulo@0: XDestroyWindow(dpy, zone); paulo@0: undo_stack_push(x, y, w, h); paulo@0: paulo@0: if (warp) paulo@0: warppointer(x, y, w, h); paulo@0: if (click == 1) { paulo@0: if (!drag) paulo@0: buttondown(1); paulo@0: if (mod & DRAGMASK && !drag) paulo@0: drag = 1; paulo@0: else if (mod & DRAGMASK) { paulo@0: buttonup(1); paulo@0: buttondown(1); paulo@0: } else { paulo@0: buttonup(1); paulo@0: drag = 0; paulo@0: } paulo@0: } else if (click) { paulo@0: buttondown(click); paulo@0: buttonup(click); paulo@0: } paulo@0: paulo@0: if (click) stats(hits, moves); paulo@0: paulo@0: // loop back if in drag mode paulo@0: if (drag) { paulo@0: usleep(50); paulo@0: startmousekey(0); paulo@0: } paulo@0: paulo@0: // re-enable trigger keygrabs paulo@0: grab(KEY_TRIGGER, TRIGGERMASK); paulo@0: grab(KEY_UNDO, TRIGGERMASK); paulo@0: } paulo@0: paulo@0: int main(int argc, char **argv) { paulo@0: char *pcDisplay; paulo@0: paulo@0: if ((dpy = XOpenDisplay(pcDisplay = getenv("DISPLAY"))) == NULL) { paulo@0: fprintf(stderr,"Error: Can't open display: %s", pcDisplay); paulo@0: exit(1); paulo@0: } paulo@0: fprintf(stderr,"Display: %s\n", pcDisplay); paulo@0: paulo@0: // parse options paulo@0: if (argc > 1) paulo@0: if (argv[1][0] && argv[1][0] == '-') paulo@0: if (argv[1][1] && argv[1][1] == 'n') { paulo@0: ninegrid_default = 1; paulo@0: fprintf(stderr,"nine-grid default mode \n"); paulo@0: if (argv[2]) { paulo@0: ninegrid_n_switch = atoi(argv[2]); paulo@0: fprintf(stderr,"nine-grid autoswitch num: %d \n", ninegrid_n_switch); paulo@0: } paulo@0: } paulo@0: paulo@0: root = XDefaultRootWindow(dpy); paulo@0: XGetWindowAttributes(dpy, root, &attr); paulo@0: paulo@0: // these are the trigger keygrabs paulo@0: grab(KEY_TRIGGER, TRIGGERMASK); paulo@0: grab(KEY_UNDO, TRIGGERMASK); paulo@0: paulo@0: while (1) { paulo@0: XEvent e; paulo@0: XNextEvent(dpy, &e); paulo@0: if (e.type == KeyPress) paulo@0: if (chk_keysym(XKeycodeToKeysym(dpy, e.xkey.keycode, 0), KEY_UNDO)) paulo@0: startmousekey(1); paulo@0: else paulo@0: startmousekey(0); paulo@0: } paulo@0: }