summaryrefslogtreecommitdiff
path: root/anyscroll.c
blob: 419600f20ca9e7047ac29a88f6e079065724d335 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <unistd.h>
#include <X11/extensions/XInput2.h>
#include <pthread.h>
#include <math.h>


static Display *dpy;
static int scr, sw, sh;
static int sx = -1, sy = -1;
static Window root;

static const int direction = -1;
static const int pixels_to_scroll = 16;

static void scroll(int v) {
	v = v * direction;

	int btn;
	if (v > 0) btn = 4;
	else if (v < 0) btn = 5;
	else return;	
	
	int times = ceil(abs(v) / pixels_to_scroll) + 1;
	for (int i = 0; i < times; i++) {
		XTestFakeButtonEvent(dpy, btn, True, CurrentTime);
		XFlush(dpy);
		XTestFakeButtonEvent(dpy, btn, False, CurrentTime);
		XFlush(dpy);
	}
}

static void select_events(Display *dpy, Window win) {
	XIEventMask evmasks[1];
	unsigned char mask1[(XI_LASTEVENT + 7)/8];

	memset(mask1, 0, sizeof(mask1));

	XISetMask(mask1, XI_RawButtonPress);
	XISetMask(mask1, XI_RawButtonRelease);

	evmasks[0].deviceid = XIAllMasterDevices;
	evmasks[0].mask_len = sizeof(mask1);
	evmasks[0].mask = mask1;

	XISelectEvents(dpy, win, evmasks, 1);
	XFlush(dpy);
}

static void getmousepos(int *px, int *py) {
	Window r, child;
	int rx, ry;
	unsigned int mask;
	XQueryPointer(dpy, root, &r,  &child, px, py, &rx, &ry, &mask);
}

static void* loop() {
	int px, py, lx, ly, dx, dy;
	while (1) {
		lx =  px, ly = py;
		getmousepos(&px, &py);
		dx = px - lx;
		dy = py - ly;

		if (sx != -1 && sy != -1) scroll(dy);

		if (dx != 0 | dy != 0) {
			printf("%d, %d with deltas (%d, %d)\n", sx, sy,  dx, dy);
		}
		sleep(0.1);
	}
}

static void mouse_down(XIRawEvent *xev) {
	getmousepos(&sx, &sy);
}

static void mouse_up(XIRawEvent *xev) {
	sx = -1;
	sy = -1;
}

int main(int argc, const char **argv) {
	XInitThreads();
	for (int i = 1; i < argc; i++) {
		if (argv[i][1] == 'h') {
			fprintf(stdout, "there is no help to be given\n");
		}
	}
	
	if (!(dpy = XOpenDisplay(0x0))) return 1;

	scr = DefaultScreen(dpy);
	root = XDefaultRootWindow(dpy);
	sw = DisplayWidth(dpy, scr);
	sh = DisplayHeight(dpy, scr);
	
	fprintf(stdout, "waiting for events...\n");

	XEvent ev;
	XIEvent *xi_event;
	XIRawEvent *xev;
	XGenericEventCookie *cookie = &ev.xcookie;
	
	select_events(dpy, root);

	pthread_t id[2];
	pthread_create(&id[0], NULL, loop, &argv);
	
	for (;;) {
		if (XCheckTypedEvent(dpy, GenericEvent ,&ev)) {
			if (cookie->type != GenericEvent || !XGetEventData(dpy, cookie)) {
				continue;
			}


			xi_event = (XIEvent *) cookie->data;
			xev = (XIRawEvent *) xi_event;
			switch (cookie->evtype) {
				case XI_RawButtonPress:
					if (xev->detail == 2) mouse_down(xev);
				break;
				case XI_RawButtonRelease:
					if (xev->detail == 2) mouse_up(xev);
				break;
			}
	
			XFreeEventData(dpy, cookie);
		}
	} // there is no way out of this loop lol
	XCloseDisplay(dpy);
	return 0;
}