aboutsummaryrefslogtreecommitdiff
path: root/xchord.c
blob: c4f6f474d2f9acb08531fbd2914acb27d54c6099 (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
/*
 *  xchord -- run dwim on button 1 + 3
 *
 *  This is a simple program that runs dwim whenever the right
 *  mouse button is pressed while the left mouse button is held.
 *
 *  It does *not* block the button events.  That means that both
 *  clicks will be registered by other programs.  This may be a
 *  problem in programs that open a context menu on button 3.
 *
 *  On NetBSD, xchord should be compiled with the following flags:
 *
 *     CFLAGS = -I/usr/X11R7/include
 *     LDFLAGS = -L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -lXi
 *
 *  xchord is written by John Ankarström <john (at) ankarstrom.se>.
 */

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xlib.h>

Display *dpy;
Window rwin;

int
main(int argc, char *argv[])
{
	int p;
	unsigned char mask[(XI_LASTEVENT+7)/8];
	XEvent ev;
	XGenericEventCookie *cookie;
	XIEventMask evmasks[1];
	XIRawEvent *rev;

	dpy = XOpenDisplay(NULL);
	if(!dpy){
		fprintf(stderr, "could not open display");
		return 1;
	}
	rwin = DefaultRootWindow(dpy);

	/* select events */
	memset(mask, 0, sizeof(mask));

	XISetMask(mask, XI_RawButtonPress);
	XISetMask(mask, XI_RawButtonRelease);

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

	XISelectEvents(dpy, rwin, evmasks, 1);
	XFlush(dpy);

	cookie = &ev.xcookie;
	p = 0;

	/* watch for events */
	for(;;){
		XNextEvent(dpy, &ev);
		XPutBackEvent(dpy, &ev);
		if(!XCheckTypedEvent(dpy, GenericEvent, &ev))
			continue;
		if(cookie->type != GenericEvent || !XGetEventData(dpy, cookie))
			continue;

		rev = (XIRawEvent*)cookie->data;

		switch(cookie->evtype){
		case XI_RawButtonPress:
			/* 1 pressed (first step) */
			if(rev->detail == 1) p = 1;
			/* 1 + 3 pressed (second step) */
			if(p > 0 && rev->detail == 3) p = 2;
			break;
		case XI_RawButtonRelease:
			/* 1 pressed + 3 pressed + 3 released (third step) */
			if(p == 2 && rev->detail == 3){
				p = 3;
				system("dwim -o");
			}
			/* 1 released (reset) */
			if((p == 1 || p == 3) && rev->detail == 1) p = 0;
			break;
		}

		XFreeEventData(dpy, cookie);
	}
}