1 /*
2  * Copyright (C) 2003 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include <config.h>
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_TERMIOS_H
22 #include <sys/termios.h>
23 #endif
24 #include <sys/time.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <string.h>
29 #ifdef HAVE_TERMIOS_H
30 #include <termios.h>
31 #endif
32 #include <unistd.h>
33 #include <glib.h>
34 #include "caps.h"
35 
36 #ifdef HAVE_SYS_SELECT_H
37 #include <sys/select.h>
38 #endif
39 
40 static enum {
41 	tracking_x10 = 9,
42 	tracking_mouse = 1000,
43 	tracking_hilite = 1001,
44 	tracking_cell_motion = 1002,
45 	tracking_all_motion = 1003,
46         tracking_xterm_ext = 1006,
47         tracking_urxvt = 1015
48 } tracking_mode = 0;
49 
50 static void
decset(int mode,gboolean value)51 decset(int mode, gboolean value)
52 {
53 	fprintf(stdout, _VTE_CAP_CSI "?%d%c", mode, value ? 'h' : 'l');
54 }
55 
56 static void
reset(void)57 reset(void)
58 {
59 	decset(tracking_x10, FALSE);
60 	decset(tracking_mouse, FALSE);
61 	decset(tracking_hilite, FALSE);
62 	decset(tracking_cell_motion, FALSE);
63 	decset(tracking_all_motion, FALSE);
64 	decset(tracking_xterm_ext, FALSE);
65 	decset(tracking_urxvt, FALSE);
66 	fflush(stdout);
67 }
68 
69 static void
clear(void)70 clear(void)
71 {
72 	fprintf(stdout, "%s",
73 		_VTE_CAP_ESC "7"
74 		_VTE_CAP_CSI "8;1H"
75 		_VTE_CAP_CSI "1J"
76 		_VTE_CAP_CSI "2K"
77 		_VTE_CAP_CSI "1;1H");
78 	reset();
79 	switch (tracking_mode) {
80 	case tracking_x10:
81 		fprintf(stdout, "X10 tracking enabled.\r\n");
82 		decset(tracking_x10, TRUE);
83 		break;
84 	case tracking_mouse:
85 		fprintf(stdout, "Mouse tracking enabled.\r\n");
86 		decset(tracking_mouse, TRUE);
87 		break;
88 	case tracking_hilite:
89 		fprintf(stdout, "Hilite tracking enabled.\r\n");
90 		decset(tracking_hilite, TRUE);
91 		break;
92 	case tracking_cell_motion:
93 		fprintf(stdout, "Cell motion tracking enabled.\r\n");
94 		decset(tracking_cell_motion, TRUE);
95 		break;
96 	case tracking_all_motion:
97 		fprintf(stdout, "All motion tracking enabled.\r\n");
98 		decset(tracking_all_motion, TRUE);
99 		break;
100 	case tracking_xterm_ext:
101 		fprintf(stdout, "Xterm 1006 mouse tracking extension enabled.\r\n");
102 		decset(tracking_xterm_ext, TRUE);
103 		break;
104 	case tracking_urxvt:
105 		fprintf(stdout, "rxvt-unicode 1015 mouse tracking extension enabled.\r\n");
106 		decset(tracking_urxvt, TRUE);
107 		break;
108 	default:
109 		fprintf(stdout, "Tracking disabled.\r\n");
110 		break;
111 	}
112 	fprintf(stdout, "A - X10.\r\n");
113 	fprintf(stdout, "B - Mouse tracking.\r\n");
114 	fprintf(stdout, "C - Hilite tracking [FIXME: NOT IMPLEMENTED].\r\n");
115 	fprintf(stdout, "D - Cell motion tracking.\r\n");
116 	fprintf(stdout, "E - All motion tracking.\r\n");
117 	fprintf(stdout, "F - Xterm 1006 extension.\r\n");
118 	fprintf(stdout, "G - rxvt-unicode extension.\r\n");
119 	fprintf(stdout, "%s", _VTE_CAP_ESC "8");
120 	fflush(stdout);
121 }
122 
123 static gboolean
parse(void)124 parse(void)
125 {
126 	GByteArray *bytes;
127 	gchar buffer[64];
128 	int i, length;
129 	guchar b;
130 	gboolean ret = FALSE;
131 
132 	bytes = g_byte_array_new();
133 	if ((length = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
134 		g_byte_array_append(bytes, buffer, length);
135 	}
136 
137 	i = 0;
138 	while (i < bytes->len) {
139 		switch (bytes->data[i]) {
140 		case 'A':
141 		case 'a':
142 			tracking_mode = (tracking_mode == tracking_x10) ?
143 					0 : tracking_x10;
144 			i++;
145 			break;
146 		case 'B':
147 		case 'b':
148 			tracking_mode = (tracking_mode == tracking_mouse) ?
149 					0 : tracking_mouse;
150 			i++;
151 			break;
152 		case 'C':
153 		case 'c':
154 			tracking_mode = (tracking_mode == tracking_hilite) ?
155 					0 : tracking_hilite;
156 			i++;
157 			break;
158 		case 'D':
159 		case 'd':
160 			tracking_mode = (tracking_mode == tracking_cell_motion) ?
161 					0 : tracking_cell_motion;
162 			i++;
163 			break;
164 		case 'E':
165 		case 'e':
166 			tracking_mode = (tracking_mode == tracking_all_motion) ?
167 					0 : tracking_all_motion;
168 			i++;
169 			break;
170 		case 'F':
171 		case 'f':
172 			tracking_mode = (tracking_mode == tracking_xterm_ext) ?
173 					0 : tracking_xterm_ext;
174 			i++;
175 			break;
176 		case 'G':
177 		case 'g':
178 			tracking_mode = (tracking_mode == tracking_urxvt) ?
179 					0 : tracking_urxvt;
180 			i++;
181 			break;
182 		case 'Q':
183 		case 'q':
184 			ret = TRUE;
185 			i++;
186 			break;
187 		case '\033':
188 			if (bytes->len - i >= 6) {
189 				int button = 0;
190 				const char *shift = "", *control = "",
191 					   *meta = "";
192 				gboolean motion = FALSE;
193 				int x, y;
194 				if ((bytes->data[i + 0] == '\033') &&
195 				    (bytes->data[i + 1] == '[')) {
196 					if (bytes->data[i + 2] == 'M') {
197 						b = bytes->data[i + 3] - 32;
198 						switch (b & 3) {
199 						case 0:
200 							button = 1;
201 							if (b & 64) {
202 								button += 3;
203 							}
204 							break;
205 						case 1:
206 							button = 2;
207 							if (b & 64) {
208 								button += 3;
209 							}
210 							break;
211 						case 2:
212 							button = 3;
213 							if (b & 64) {
214 								button += 3;
215 							}
216 							break;
217 						case 3:
218 							button = 0;
219 							break;
220 						}
221 						shift = b & 4 ?
222 							"[shift]" :
223 							"";
224 						meta = b & 8 ?
225 						       "[meta]" :
226 						       "";
227 						control = b & 16 ?
228 							  "[control]" :
229 							  "";
230 						motion = (b & 32) != 0;
231 						x = bytes->data[i + 4] - 32;
232 						y = bytes->data[i + 5] - 32;
233 						fprintf(stdout, "%d %s%s%s(%s%s%s) at %d,%d\r\n",
234 							button,
235 							motion ? "motion " : "",
236 							(!motion && button) ? "press" : "",
237 							(!motion && !button) ? "release" : "",
238 							meta, control, shift,
239 							x, y);
240 					}
241 				}
242 				i += 6;
243 				break;
244 			}
245 		default:
246 			while (i < length) {
247 				if (bytes->data[i] < 32) {
248 					fprintf(stdout, "'^%c' ",
249 						bytes->data[i] | 64);
250 				} else {
251 					fprintf(stdout, "'%c' ",
252 						bytes->data[i]);
253 				}
254 				i++;
255 			}
256 			fprintf(stdout, "\r\n");
257 			break;
258 		}
259 	}
260 	fflush(stdout);
261 	g_byte_array_free(bytes, TRUE);
262 
263 	return ret;
264 }
265 
266 static struct termios tcattr, original;
267 
268 static void
sigint_handler(int signum)269 sigint_handler(int signum)
270 {
271 	if (tcsetattr(STDIN_FILENO, TCSANOW, &original) != 0) {
272 		perror("tcsetattr");
273 	}
274 	reset();
275 	_exit(1);
276 }
277 
278 int
main(int argc,char ** argv)279 main(int argc, char **argv)
280 {
281 	int flags;
282 	gboolean stop;
283 	fd_set in_fds;
284 
285 	if (tcgetattr(STDIN_FILENO, &tcattr) != 0) {
286 		perror("tcgetattr");
287 		return 1;
288 	}
289 
290 	original = tcattr;
291 	signal(SIGINT, sigint_handler);
292 	/* Here we approximate what cfmakeraw() would do, for the benefit
293 	 * of systems which don't actually provide the function. */
294 	tcattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
295 			    INLCR | IGNCR | ICRNL | IXON);
296 	tcattr.c_oflag &= ~(OPOST);
297 	tcattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
298 	tcattr.c_cflag &= ~(CSIZE | PARENB);
299 	tcattr.c_cflag |= CS8;
300 #ifdef HAVE_CFMAKERAW
301 	cfmakeraw(&tcattr);
302 #endif
303 	if (tcsetattr(STDIN_FILENO, TCSANOW, &tcattr) != 0) {
304 		perror("tcsetattr");
305 		return 1;
306 	}
307 
308 	flags = fcntl(STDIN_FILENO, F_GETFL);
309 	fcntl(STDIN_FILENO, F_SETFL, flags & ~(O_NONBLOCK));
310 	fprintf(stdout, "%s",
311 		_VTE_CAP_CSI "9;1H"
312 		_VTE_CAP_CSI "2K"
313 		_VTE_CAP_CSI "2J");
314 	do {
315 		clear();
316 		FD_ZERO(&in_fds);
317 		FD_SET(STDIN_FILENO, &in_fds);
318 		stop = TRUE;
319 		switch (select(STDIN_FILENO + 1, &in_fds, NULL, NULL, NULL)) {
320 		case 1:
321 			stop = parse();
322 			break;
323 		default:
324 			stop = TRUE;
325 			break;
326 		}
327 	} while (!stop);
328 	reset();
329 	fcntl(STDIN_FILENO, F_SETFL, flags);
330 
331 	if (tcsetattr(STDIN_FILENO, TCSANOW, &original) != 0) {
332 		perror("tcsetattr");
333 		return 1;
334 	}
335 
336 	return 0;
337 }
338