Add middle-click with 'p'
[xvmouse.git] / xvmouse.c
1 #include <X11/Xlib.h>
2 #include <math.h>
3 #include <X11/extensions/XTest.h>
4 #include <stdio.h>
5 #include <signal.h>
6 #include <sys/time.h>
7 #include <time.h>
8
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
16
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; })
19
20 unsigned long long now()
21 {
22         struct timeval tv;
23         gettimeofday(&tv, NULL);
24         return tv.tv_sec*1000000 + tv.tv_usec;
25 }
26
27 int main()
28 {
29         int e;
30         XEvent ev;
31         Display *dpy;
32         int status = 0, dmy;
33         char key = 0, lastkey = 0;
34         unsigned long long lasttime = 0;
35         int repeats = 1;
36         int starttime = 0;
37         
38         dpy = XOpenDisplay(NULL);
39         if (!dpy)
40         {
41                 printf("Display open failed; bailing out\n");
42                 exit(1);
43         }
44         
45         if (!XTestQueryExtension(dpy, &dmy, &dmy, &dmy, &dmy))
46         {
47                 printf("XTest NOT supported\n");
48                 exit(1);
49         }
50         
51         printf("Grabbing keyboard...\n");
52         XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("grave")), Mod1Mask, RootWindow(dpy, DefaultScreen(dpy)), True, GrabModeAsync, GrabModeAsync);
53         
54         while (1)
55         {
56                 while (XCheckMaskEvent(dpy, 0xFFFFFFFF, &ev))
57                 {
58                         switch (ev.type)
59                         {
60                         case KeyPress:
61                         case KeyRelease:
62                         {
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);
66                                 
67                                 if (!strcmp(keystr, "grave")) {
68                                         if (ev.type == KeyPress)
69                                         {
70                                                 XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("grave")), AnyModifier, RootWindow(dpy, DefaultScreen(dpy)), True, GrabModeAsync, GrabModeAsync);
71                                                 XAutoRepeatOff(dpy);
72                                                 status |= STATUS_RUNNING;
73                                         } else {
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);
76                                                 XAutoRepeatOn(dpy);
77                                                 status &= ~STATUS_RUNNING;
78                                         }
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;
88                                         else
89                                                 status &= ~STATUS_TAPJUMP;
90                                         repeats = 1;
91                                 } else if (!strcmp(keystr, "j")) {
92                                         if (ev.type == KeyPress)
93                                         {
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);
97                                         } else
98                                                 status &= ~STATUS_LEFT;
99                                 } else if (!strcmp(keystr, "l")) {
100                                         if (ev.type == KeyPress)
101                                         {
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);
105                                         } else
106                                                 status &= ~STATUS_RIGHT;
107                                 } else if (!strcmp(keystr, "i")) {
108                                         if (ev.type == KeyPress)
109                                         {
110                                                 status |= STATUS_UP;
111                                                 if ((lastkey == 'i') && ((now() - lasttime) < 250000) && (status & STATUS_TAPJUMP))
112                                                         XTestFakeRelativeMotionEvent(dpy, 0, -100.0 * pow(repeats++, 0.8), 0);
113                                         } else
114                                                 status &= ~STATUS_UP;
115                                 } else if (!strcmp(keystr, "k")) {
116                                         if (ev.type == KeyPress)
117                                         {
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);
121                                         } else
122                                                 status &= ~STATUS_DOWN;
123                                 }
124                                 if (strlen(keystr) == 1 && ev.type == KeyPress)
125                                 {
126                                         lastkey = keystr[0];
127                                         lasttime = now();
128                                 } else if (ev.type == KeyPress) {
129                                         lastkey = 0;
130                                         repeats = 0;
131                                 }
132                                 break;
133                         }
134                         default:
135                                 printf("NFI what %d is\n", ev.type);
136                         }
137                 }
138                 if (!(status & STATUS_RUNNING))
139                         status = 0;
140                 if (!(status & STATUS_MOVING))  // if we haven't anything to do, don't sit and suck up cycles
141                 {
142                         XPeekEvent(dpy, &ev);
143                         starttime = now();
144                 }
145                 usleep(20000 - MIN(MAX(pow(13 * (now() - starttime), 0.6), 0), 18000));
146                 if (now() - lasttime > 250000)
147                         repeats = 1;
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);
156         }
157         
158         exit(0);
159 }
This page took 0.073611 seconds and 4 git commands to generate.