1/*
2 * Forward key and mouse button events from one window to another.
3 *
4 * This is useful to use a Desktop window as a Root window.
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <X11/Xlocale.h>
10#include <X11/Xlib.h>
11
12char *ProgramName;
13Display *dpy;
14int screen;
15
16static void
17usage(void)
18{
19	static const char *msg[] = {
20		"    -display displayname                X server to contact",
21		"    -id windowid                        use existing window",
22		"    -root                               use root window",
23		"    -name string                        window name",
24		"",
25		NULL
26	};
27	const char **cpp;
28
29	fprintf(stderr, "usage:  %s [-options ...]\n", ProgramName);
30	fprintf(stderr, "where options include:\n");
31
32	for(cpp = msg; *cpp; cpp++) {
33		fprintf(stderr, "%s\n", *cpp);
34	}
35
36	exit(1);
37}
38
39int
40main(int argc, char **argv)
41{
42	char *displayname = NULL;
43	int i;
44	Window w;
45	XWindowAttributes wattr;
46	long event_mask;
47	int done;
48	Window ws[2];   /* from-window, to-window */
49	int wi = 0;
50	char *name;
51
52	ProgramName = argv[0];
53
54	if(setlocale(LC_ALL, "") == NULL) {
55		fprintf(stderr, "%s: warning: could not set default locale\n",
56		        ProgramName);
57	}
58
59	w = 0;
60	for(i = 1; i < argc; i++) {
61		char *arg = argv[i];
62
63		if(arg[0] == '-') {
64			switch(arg[1]) {
65				case 'd':                 /* -display host:dpy */
66					if(++i >= argc) {
67						usage();
68					}
69					displayname = argv[i];
70					continue;
71				case 'i':                 /* -id */
72					if(++i >= argc || wi > 1) {
73						usage();
74					}
75					sscanf(argv[i], "0x%lx", &w);
76					if(!w) {
77						sscanf(argv[i], "%lu", &w);
78					}
79					if(!w) {
80						usage();
81					}
82					ws[wi++] = w;
83					continue;
84				case 'n':                 /* -name */
85					if(++i >= argc || wi > 1) {
86						usage();
87					}
88					name = argv[i]; /* not implemented yet */
89					(void)name; // Silence unused warning
90					continue;
91				case 'r':
92					switch(arg[2]) {
93						case 'o':             /* -root */
94							if(wi > 1) {
95								usage();
96							}
97							ws[wi++] = -1;
98							continue;
99						default:
100							usage();
101					}
102					continue;
103				default:
104					usage();
105			}                           /* end switch on - */
106		}
107		else {
108			usage();
109		}
110	}                                   /* end for over argc */
111
112	dpy = XOpenDisplay(displayname);
113	if(!dpy) {
114		fprintf(stderr, "%s:  unable to open display '%s'\n",
115		        ProgramName, XDisplayName(displayname));
116		exit(1);
117	}
118	screen = DefaultScreen(dpy);
119
120	if(ws[0] == -1) {
121		ws[0] = RootWindow(dpy, screen);
122	}
123	if(ws[1] == -1) {
124		ws[1] = RootWindow(dpy, screen);
125	}
126
127	if(ws[0] == ws[1]) {
128		fprintf(stderr, "error: from-window and to-window must differ.\n");
129		exit(1);
130	}
131
132	event_mask = KeyPressMask | KeyReleaseMask |
133	             ButtonPressMask | ButtonReleaseMask;
134
135	if(ws[0]) {
136		XGetWindowAttributes(dpy, ws[0], &wattr);
137		/* We can't select on button presses if someone else already does... */
138		if(wattr.all_event_masks & ButtonPressMask) {
139			event_mask &= ~ButtonPressMask;
140			fprintf(stderr, "warning: can't forward button presses.\n");
141		}
142		event_mask &= ~SubstructureRedirectMask;
143		printf("XSelectInput 0x%x %lx\n", (unsigned int)ws[0], event_mask);
144		XSelectInput(dpy, ws[0], event_mask);
145	}
146
147	for(done = 0; !done;) {
148		XEvent event;
149
150		XNextEvent(dpy, &event);
151
152		switch(event.type) {
153			case KeyPress:
154			case KeyRelease:
155				printf("KeyPress/KeyRelease\n");
156				event.xkey.window = ws[1];
157				XSendEvent(dpy, ws[1], False, KeyPressMask, &event);
158				break;
159			case ButtonPress:
160			case ButtonRelease:
161				printf("ButtonPress/ButtonRelease\n");
162				event.xbutton.window = ws[1];
163				XSendEvent(dpy, ws[1], False, KeyPressMask, &event);
164				break;
165			default:
166				printf("some other event\n");
167		}
168	}
169
170	XCloseDisplay(dpy);
171	return 0;
172}
173