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