1 /* Curses terminal
2
3 Copyright (c) 1997-2012 Free Software Foundation, Inc.
4
5 This file is part of GNU Zile.
6
7 GNU Zile is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GNU Zile is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Zile; see the file COPYING. If not, write to the
19 Free Software Foundation, Fifth Floor, 51 Franklin Street, Boston,
20 MA 02111-1301, USA. */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25 #if defined HAVE_NCURSESW_CURSES_H
26 # include <ncursesw/curses.h>
27 #elif defined HAVE_NCURSESW_H
28 # include <ncursesw.h>
29 #elif defined HAVE_NCURSES_CURSES_H
30 # include <ncurses/curses.h>
31 #elif defined HAVE_NCURSES_H
32 # include <ncurses.h>
33 #elif defined HAVE_CURSES_H
34 # include <curses.h>
35 #else
36 # error "SysV or X/Open-compatible Curses header file required"
37 #endif
38 #include <term.h>
39 #include "gl_array_list.h"
40
41 #include "main.h"
42 #include "extern.h"
43
44 static gl_list_t key_buf;
45
46 static char backspace_code = 0177;
47
48 size_t
term_buf_len(void)49 term_buf_len (void)
50 {
51 return gl_list_size (key_buf);
52 }
53
54 void
term_move(size_t y,size_t x)55 term_move (size_t y, size_t x)
56 {
57 move ((int) y, (int) x);
58 }
59
60 void
term_clrtoeol(void)61 term_clrtoeol (void)
62 {
63 clrtoeol ();
64 }
65
66 void
term_refresh(void)67 term_refresh (void)
68 {
69 refresh ();
70 }
71
72 void
term_clear(void)73 term_clear (void)
74 {
75 clear ();
76 }
77
78 void
term_addch(char c)79 term_addch (char c)
80 {
81 addch (c);
82 }
83
84 void
term_addstr(const char * s)85 term_addstr (const char *s)
86 {
87 addstr (s);
88 }
89
90 void
term_attrset(size_t attr)91 term_attrset (size_t attr)
92 {
93 int attrs = 0;
94 if (attr & FONT_REVERSE)
95 attrs |= A_REVERSE;
96 if (attr & FONT_UNDERLINE)
97 attrs |= A_UNDERLINE;
98 attrset (attrs);
99 }
100
101 void
term_beep(void)102 term_beep (void)
103 {
104 beep ();
105 }
106
107 size_t
term_width(void)108 term_width (void)
109 {
110 return (size_t) COLS;
111 }
112
113 size_t
term_height(void)114 term_height (void)
115 {
116 return (size_t) LINES;
117 }
118
119 void
term_init(void)120 term_init (void)
121 {
122 initscr ();
123 noecho ();
124 nonl ();
125 raw ();
126 meta (stdscr, true);
127 intrflush (stdscr, false);
128 keypad (stdscr, true);
129 key_buf = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, NULL, true);
130 char *kbs = tigetstr("kbs");
131 if (kbs && strlen (kbs) == 1)
132 backspace_code = *kbs;
133 }
134
135 void
term_close(void)136 term_close (void)
137 {
138 /* Finish with ncurses. */
139 endwin ();
140 }
141
142 static _GL_ATTRIBUTE_PURE size_t
codetokey(int c)143 codetokey (int c)
144 {
145 switch (c)
146 {
147 case '\0': /* C-@ */
148 return KBD_CTRL | '@';
149 case '\1':
150 case '\2':
151 case '\3':
152 case '\4':
153 case '\5':
154 case '\6':
155 case '\7':
156 case '\10':
157 case '\12':
158 case '\13':
159 case '\14':
160 case '\16':
161 case '\17':
162 case '\20':
163 case '\21':
164 case '\22':
165 case '\23':
166 case '\24':
167 case '\25':
168 case '\26':
169 case '\27':
170 case '\30':
171 case '\31':
172 case '\32': /* C-a ... C-z */
173 return KBD_CTRL | ('a' + c - 1);
174 case '\11':
175 return KBD_TAB;
176 case '\15':
177 return KBD_RET;
178 case '\37':
179 return KBD_CTRL | '_';
180 #ifdef KEY_SUSPEND
181 case KEY_SUSPEND: /* C-z */
182 return KBD_CTRL | 'z';
183 #endif
184 case '\33': /* META */
185 return KBD_META;
186 case KEY_PPAGE: /* PGUP */
187 return KBD_PGUP;
188 case KEY_NPAGE: /* PGDN */
189 return KBD_PGDN;
190 case KEY_HOME:
191 return KBD_HOME;
192 case KEY_END:
193 return KBD_END;
194 case KEY_DC: /* DEL */
195 return KBD_DEL;
196 case KEY_BACKSPACE: /* Backspace or Ctrl-H */
197 return codetokey (backspace_code);
198 case 0177: /* BS */
199 return KBD_BS;
200 case KEY_IC: /* INSERT */
201 return KBD_INS;
202 case KEY_LEFT:
203 return KBD_LEFT;
204 case KEY_RIGHT:
205 return KBD_RIGHT;
206 case KEY_UP:
207 return KBD_UP;
208 case KEY_DOWN:
209 return KBD_DOWN;
210 case KEY_F (1):
211 return KBD_F1;
212 case KEY_F (2):
213 return KBD_F2;
214 case KEY_F (3):
215 return KBD_F3;
216 case KEY_F (4):
217 return KBD_F4;
218 case KEY_F (5):
219 return KBD_F5;
220 case KEY_F (6):
221 return KBD_F6;
222 case KEY_F (7):
223 return KBD_F7;
224 case KEY_F (8):
225 return KBD_F8;
226 case KEY_F (9):
227 return KBD_F9;
228 case KEY_F (10):
229 return KBD_F10;
230 case KEY_F (11):
231 return KBD_F11;
232 case KEY_F (12):
233 return KBD_F12;
234 default:
235 if (c > 0xff || c < 0)
236 return KBD_NOKEY; /* ERR (no key) or undefined behaviour. */
237 return c;
238 }
239 }
240
241 static size_t
keytocodes(size_t key,int ** codevec)242 keytocodes (size_t key, int ** codevec)
243 {
244 if (key == KBD_NOKEY)
245 return 0;
246
247 int *p = *codevec = XCALLOC (2, int);
248
249 if (key & KBD_META) /* META */
250 *p++ = '\33';
251 key &= ~KBD_META;
252
253 switch (key)
254 {
255 case KBD_CTRL | '@': /* C-@ */
256 *p++ = '\0';
257 break;
258 case KBD_CTRL | 'a':
259 case KBD_CTRL | 'b':
260 case KBD_CTRL | 'c':
261 case KBD_CTRL | 'd':
262 case KBD_CTRL | 'e':
263 case KBD_CTRL | 'f':
264 case KBD_CTRL | 'g':
265 case KBD_CTRL | 'h':
266 case KBD_CTRL | 'j':
267 case KBD_CTRL | 'k':
268 case KBD_CTRL | 'l':
269 case KBD_CTRL | 'n':
270 case KBD_CTRL | 'o':
271 case KBD_CTRL | 'p':
272 case KBD_CTRL | 'q':
273 case KBD_CTRL | 'r':
274 case KBD_CTRL | 's':
275 case KBD_CTRL | 't':
276 case KBD_CTRL | 'u':
277 case KBD_CTRL | 'v':
278 case KBD_CTRL | 'w':
279 case KBD_CTRL | 'x':
280 case KBD_CTRL | 'y':
281 case KBD_CTRL | 'z': /* C-a ... C-z */
282 *p++ = (key & ~KBD_CTRL) + 1 - 'a';
283 break;
284 case KBD_TAB:
285 *p++ = '\11';
286 break;
287 case KBD_RET:
288 *p++ = '\15';
289 break;
290 case KBD_CTRL | '_':
291 *p++ = '\37';
292 break;
293 case KBD_PGUP: /* PGUP */
294 *p++ = KEY_PPAGE;
295 break;
296 case KBD_PGDN: /* PGDN */
297 *p++ = KEY_NPAGE;
298 break;
299 case KBD_HOME:
300 *p++ = KEY_HOME;
301 break;
302 case KBD_END:
303 *p++ = KEY_END;
304 break;
305 case KBD_DEL: /* DEL */
306 *p++ = KEY_DC;
307 break;
308 case KBD_BS: /* BS */
309 *p++ = 0177;
310 break;
311 case KBD_INS: /* INSERT */
312 *p++ = KEY_IC;
313 break;
314 case KBD_LEFT:
315 *p++ = KEY_LEFT;
316 break;
317 case KBD_RIGHT:
318 *p++ = KEY_RIGHT;
319 break;
320 case KBD_UP:
321 *p++ = KEY_UP;
322 break;
323 case KBD_DOWN:
324 *p++ = KEY_DOWN;
325 break;
326 case KBD_F1:
327 *p++ = KEY_F (1);
328 break;
329 case KBD_F2:
330 *p++ = KEY_F (2);
331 break;
332 case KBD_F3:
333 *p++ = KEY_F (3);
334 break;
335 case KBD_F4:
336 *p++ = KEY_F (4);
337 break;
338 case KBD_F5:
339 *p++ = KEY_F (5);
340 break;
341 case KBD_F6:
342 *p++ = KEY_F (6);
343 break;
344 case KBD_F7:
345 *p++ = KEY_F (7);
346 break;
347 case KBD_F8:
348 *p++ = KEY_F (8);
349 break;
350 case KBD_F9:
351 *p++ = KEY_F (9);
352 break;
353 case KBD_F10:
354 *p++ = KEY_F (10);
355 break;
356 case KBD_F11:
357 *p++ = KEY_F (11);
358 break;
359 case KBD_F12:
360 *p++ = KEY_F (12);
361 break;
362 default:
363 if ((key & 0xff) == key)
364 *p++ = key;
365 break;
366 }
367
368 return p - *codevec;
369 }
370
371 static int
get_char(int delay)372 get_char (int delay)
373 {
374 int c;
375
376 size_t size = term_buf_len ();
377 if (size > 0)
378 {
379 c = (ptrdiff_t) gl_list_get_at (key_buf, size - 1);
380 gl_list_remove_at (key_buf, size - 1);
381 }
382 else
383 {
384 timeout (delay);
385
386 #ifdef KEY_RESIZE
387 do {
388 #endif
389 c = getch ();
390
391 #ifdef KEY_RESIZE
392 if (c == KEY_RESIZE)
393 resize_windows ();
394 } while (c == KEY_RESIZE);
395 #endif
396 }
397
398 return c;
399 }
400
401 size_t
term_getkey(int delay)402 term_getkey (int delay)
403 {
404 size_t key = codetokey (get_char (delay));
405 while (key == KBD_META)
406 key = codetokey (get_char (GETKEY_DEFAULT)) | KBD_META;
407 return key;
408 }
409
410 int
term_getkey_unfiltered(int delay)411 term_getkey_unfiltered (int delay)
412 {
413 keypad (stdscr, false);
414 int key = get_char (delay);
415 keypad (stdscr, true);
416 return key;
417 }
418
419 void
term_ungetkey(size_t key)420 term_ungetkey (size_t key)
421 {
422 int * codes = NULL;
423 for (size_t i = keytocodes (key, &codes); i > 0; i--)
424 gl_list_add_last (key_buf, (void *)(ptrdiff_t) codes[i - 1]);
425 }
426