3 #include <X11/extensions/XTest.h>
9 #define STATUS_LEFT 0x01
10 #define STATUS_RIGHT 0x02
11 #define STATUS_UP 0x04
12 #define STATUS_DOWN 0x08
13 #define STATUS_MOVING 0xF
14 #define STATUS_TAPJUMP 0x100
15 #define STATUS_RUNNING 0x80000000
17 #define MIN(a,b) ({int __a = (a), __b = (b); (__a < __b) ? __a : __b; })
18 #define MAX(a,b) ({int __a = (a), __b = (b); (__a > __b) ? __a : __b; })
20 unsigned long long now()
23 gettimeofday(&tv, NULL);
24 return tv.tv_sec*1000000 + tv.tv_usec;
33 char key = 0, lastkey = 0;
34 unsigned long long lasttime = 0;
38 dpy = XOpenDisplay(NULL);
41 printf("Display open failed; bailing out\n");
45 if (!XTestQueryExtension(dpy, &dmy, &dmy, &dmy, &dmy))
47 printf("XTest NOT supported\n");
51 printf("Grabbing keyboard...\n");
52 XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("grave")), Mod1Mask, RootWindow(dpy, DefaultScreen(dpy)), True, GrabModeAsync, GrabModeAsync);
56 while (XCheckMaskEvent(dpy, 0xFFFFFFFF, &ev))
63 XKeyEvent *ke = (XKeyEvent*)&ev;
64 char *keystr = XKeysymToString(XKeycodeToKeysym(dpy, ke->keycode, 0));
65 //printf("Key %s: %s\n", ev.type == KeyPress ? "PRESS " : "RELEASE", keystr);
67 if (!strcmp(keystr, "grave")) {
68 if (ev.type == KeyPress)
70 XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("grave")), AnyModifier, RootWindow(dpy, DefaultScreen(dpy)), True, GrabModeAsync, GrabModeAsync);
72 status |= STATUS_RUNNING;
74 XUngrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("grave")), AnyModifier, RootWindow(dpy, DefaultScreen(dpy)));
75 XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("grave")), Mod1Mask, RootWindow(dpy, DefaultScreen(dpy)), True, GrabModeAsync, GrabModeAsync);
77 status &= ~STATUS_RUNNING;
79 } else if (!strcmp(keystr, "u"))
80 XTestFakeButtonEvent(dpy, 1, ev.type == KeyPress, 0);
81 else if (!strcmp(keystr, "o"))
82 XTestFakeButtonEvent(dpy, 3, ev.type == KeyPress, 0);
83 else if (!strcmp(keystr, "apostrophe") || !strcmp(keystr, "semicolon")) {
84 if (ev.type == KeyPress)
85 status |= STATUS_TAPJUMP;
87 status &= ~STATUS_TAPJUMP;
89 } else if (!strcmp(keystr, "j")) {
90 if (ev.type == KeyPress)
92 status |= STATUS_LEFT;
93 if ((lastkey == 'j') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
94 XTestFakeRelativeMotionEvent(dpy, -100.0 * pow(repeats++, 0.8), 0, 0);
96 status &= ~STATUS_LEFT;
97 } else if (!strcmp(keystr, "l")) {
98 if (ev.type == KeyPress)
100 status |= STATUS_RIGHT;
101 if ((lastkey == 'l') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
102 XTestFakeRelativeMotionEvent(dpy, 100.0 * pow(repeats++, 0.8), 0, 0);
104 status &= ~STATUS_RIGHT;
105 } else if (!strcmp(keystr, "i")) {
106 if (ev.type == KeyPress)
109 if ((lastkey == 'i') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
110 XTestFakeRelativeMotionEvent(dpy, 0, -100.0 * pow(repeats++, 0.8), 0);
112 status &= ~STATUS_UP;
113 } else if (!strcmp(keystr, "k")) {
114 if (ev.type == KeyPress)
116 status |= STATUS_DOWN;
117 if (lastkey == 'k' && (now() - lasttime) < 250000 && (status & STATUS_TAPJUMP))
118 XTestFakeRelativeMotionEvent(dpy, 0, 100.0 * pow(repeats++, 0.8), 0);
120 status &= ~STATUS_DOWN;
122 if (strlen(keystr) == 1 && ev.type == KeyPress)
126 } else if (ev.type == KeyPress) {
133 printf("NFI what %d is\n", ev.type);
136 if (!(status & STATUS_RUNNING))
138 if (!(status & STATUS_MOVING)) // if we haven't anything to do, don't sit and suck up cycles
140 XPeekEvent(dpy, &ev);
143 usleep(20000 - MIN(MAX(pow(13 * (now() - starttime), 0.6), 0), 18000));
144 if (now() - lasttime > 250000)
146 if (status & STATUS_LEFT)
147 XTestFakeRelativeMotionEvent(dpy, -2, 0, 0);
148 if (status & STATUS_RIGHT)
149 XTestFakeRelativeMotionEvent(dpy, 2, 0, 0);
150 if (status & STATUS_UP)
151 XTestFakeRelativeMotionEvent(dpy, 0, -2, 0);
152 if (status & STATUS_DOWN)
153 XTestFakeRelativeMotionEvent(dpy, 0, 2, 0);