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, "p"))
84 XTestFakeButtonEvent(dpy, 2, ev.type == KeyPress, 0);
85 else if (!strcmp(keystr, "apostrophe") || !strcmp(keystr, "semicolon")) {
86 if (ev.type == KeyPress)
87 status |= STATUS_TAPJUMP;
89 status &= ~STATUS_TAPJUMP;
91 } else if (!strcmp(keystr, "j")) {
92 if (ev.type == KeyPress)
94 status |= STATUS_LEFT;
95 if ((lastkey == 'j') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
96 XTestFakeRelativeMotionEvent(dpy, -100.0 * pow(repeats++, 0.8), 0, 0);
98 status &= ~STATUS_LEFT;
99 } else if (!strcmp(keystr, "l")) {
100 if (ev.type == KeyPress)
102 status |= STATUS_RIGHT;
103 if ((lastkey == 'l') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
104 XTestFakeRelativeMotionEvent(dpy, 100.0 * pow(repeats++, 0.8), 0, 0);
106 status &= ~STATUS_RIGHT;
107 } else if (!strcmp(keystr, "i")) {
108 if (ev.type == KeyPress)
111 if ((lastkey == 'i') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
112 XTestFakeRelativeMotionEvent(dpy, 0, -100.0 * pow(repeats++, 0.8), 0);
114 status &= ~STATUS_UP;
115 } else if (!strcmp(keystr, "k")) {
116 if (ev.type == KeyPress)
118 status |= STATUS_DOWN;
119 if (lastkey == 'k' && (now() - lasttime) < 250000 && (status & STATUS_TAPJUMP))
120 XTestFakeRelativeMotionEvent(dpy, 0, 100.0 * pow(repeats++, 0.8), 0);
122 status &= ~STATUS_DOWN;
124 if (strlen(keystr) == 1 && ev.type == KeyPress)
128 } else if (ev.type == KeyPress) {
135 printf("NFI what %d is\n", ev.type);
138 if (!(status & STATUS_RUNNING))
140 if (!(status & STATUS_MOVING)) // if we haven't anything to do, don't sit and suck up cycles
142 XPeekEvent(dpy, &ev);
145 usleep(20000 - MIN(MAX(pow(13 * (now() - starttime), 0.6), 0), 18000));
146 if (now() - lasttime > 250000)
148 if (status & STATUS_LEFT)
149 XTestFakeRelativeMotionEvent(dpy, -2, 0, 0);
150 if (status & STATUS_RIGHT)
151 XTestFakeRelativeMotionEvent(dpy, 2, 0, 0);
152 if (status & STATUS_UP)
153 XTestFakeRelativeMotionEvent(dpy, 0, -2, 0);
154 if (status & STATUS_DOWN)
155 XTestFakeRelativeMotionEvent(dpy, 0, 2, 0);