1 /********************************************************************/
2 /*                                                                  */
3 /*  kbd_inf.c     Driver for terminfo keyboard access.              */
4 /*  Copyright (C) 1989 - 2013  Thomas Mertes                        */
5 /*                                                                  */
6 /*  This file is part of the Seed7 Runtime Library.                 */
7 /*                                                                  */
8 /*  The Seed7 Runtime Library is free software; you can             */
9 /*  redistribute it and/or modify it under the terms of the GNU     */
10 /*  Lesser General Public License as published by the Free Software */
11 /*  Foundation; either version 2.1 of the License, or (at your      */
12 /*  option) any later version.                                      */
13 /*                                                                  */
14 /*  The Seed7 Runtime Library is distributed in the hope that it    */
15 /*  will be useful, but WITHOUT ANY WARRANTY; without even the      */
16 /*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /*  PURPOSE.  See the GNU Lesser General Public License for more    */
18 /*  details.                                                        */
19 /*                                                                  */
20 /*  You should have received a copy of the GNU Lesser General       */
21 /*  Public License along with this program; if not, write to the    */
22 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
23 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
24 /*                                                                  */
25 /*  Module: Seed7 Runtime Library                                   */
26 /*  File: seed7/src/kbd_inf.c                                       */
27 /*  Changes: 1994, 2006, 2010, 2013  Thomas Mertes                  */
28 /*  Content: Driver for terminfo keyboard access.                   */
29 /*                                                                  */
30 /********************************************************************/
31 
32 #include "version.h"
33 
34 #ifdef USE_KBD_INF
35 #include "stdlib.h"
36 #include "stdio.h"
37 #include "string.h"
38 #include "time.h"
39 
40 #if UNISTD_H_PRESENT
41 #include "unistd.h"
42 #endif
43 
44 #include "common.h"
45 #include "striutl.h"
46 
47 #ifdef TERM_INCLUDE
48 #include TERM_INCLUDE
49 #ifdef HAS_TERMIOS_H
50 #include "termios.h"
51 #endif
52 #else
53 #ifdef INCL_CURSES_BEFORE_TERM
54 /* The following include is necessary for RM Machines. */
55 #include "curses.h"
56 #endif
57 
58 #include "termios.h"
59 
60 #ifdef USE_TERMINFO
61 #ifdef INCL_NCURSES_TERM
62 #include "ncurses/term.h"
63 #else
64 #include "term.h"
65 #endif
66 #endif
67 #endif
68 
69 #include "errno.h"
70 
71 #include "os_decls.h"
72 #include "rtl_err.h"
73 #include "trm_drv.h"
74 
75 #ifdef USE_TERMCAP
76 #include "cap_def.h"
77 #endif
78 
79 #include "con_drv.h"
80 
81 #undef EXTERN
82 #define EXTERN
83 #include "kbd_drv.h"
84 
85 
86 #undef TRACE_FKEYS
87 
88 
89 /* #define atexit(x) */
90 
91 
92 static boolType utf8_mode = FALSE;
93 static boolType key_buffer_filled = FALSE;
94 static int last_key;
95 extern boolType changes;
96 static struct termios term_descr;
97 static struct termios term_bak;
98 
99 static boolType keybd_initialized = FALSE;
100 
101 
102 #define SIZE_KEY_TABLE 131
103 
104 static const_cstriType key_table[SIZE_KEY_TABLE];
105 static char erase_ch[2];
106 
107 static charType key_code[SIZE_KEY_TABLE] = {
108 /*   0 */ K_BS,         K_BS,         K_BACKTAB,    K_PAD_CENTER, 0,
109 /*   5 */ 0,            0,            K_DEL,        K_DELLN,      K_DOWN,
110 /*  10 */ K_INS,        K_END,        K_NL,         0,            0,
111 /*  15 */ K_HOME,       0,            K_F1,         K_F2,         K_F3,
112 /*  20 */ K_F4,         K_F5,         K_F6,         K_F7,         K_F8,
113 /*  25 */ K_F9,         K_F10,        K_F11,        K_F12,        K_SFT_F1,
114 /*  30 */ K_SFT_F2,     K_SFT_F3,     K_SFT_F4,     K_SFT_F5,     K_SFT_F6,
115 /*  35 */ K_SFT_F7,     K_SFT_F8,     K_SFT_F9,     K_SFT_F10,    K_SFT_F11,
116 /*  40 */ K_SFT_F12,    K_CTL_F1,     K_CTL_F2,     K_CTL_F3,     K_CTL_F4,
117 /*  45 */ K_CTL_F5,     K_CTL_F6,     K_CTL_F7,     K_CTL_F8,     K_CTL_F9,
118 /*  50 */ K_CTL_F10,    K_CTL_F11,    K_CTL_F12,    0,            0,
119 /*  55 */ 0,            0,            0,            0,            0,
120 /*  60 */ 0,            0,            0,            0,            0,
121 /*  65 */ K_ALT_F1,     K_ALT_F2,     K_ALT_F3,     K_ALT_F4,     K_ALT_F5,
122 /*  70 */ K_ALT_F6,     K_ALT_F7,     K_ALT_F8,     K_ALT_F9,     K_ALT_F10,
123 /*  75 */ K_ALT_F11,    K_ALT_F12,    0,            0,            0,
124 /*  80 */ K_HOME,       K_INS,        K_INSLN,      K_LEFT,       K_END,
125 /*  85 */ K_PGDN,       K_PGUP,       K_RIGHT,      K_END,        K_SCRLDN,
126 /*  90 */ K_SCRLUP,     0,            K_UP,         K_ALT_A,      K_ALT_B,
127 /*  95 */ K_ALT_C,      K_ALT_D,      K_ALT_E,      K_ALT_F,      K_ALT_G,
128 /* 100 */ K_ALT_H,      K_ALT_I,      K_ALT_J,      K_ALT_K,      K_ALT_L,
129 /* 105 */ K_ALT_M,      K_ALT_N,      K_ALT_O,      K_ALT_P,      K_ALT_Q,
130 /* 110 */ K_ALT_R,      K_ALT_S,      K_ALT_T,      K_ALT_U,      K_ALT_V,
131 /* 115 */ K_ALT_W,      K_ALT_X,      K_ALT_Y,      K_ALT_Z,      K_ALT_0,
132 /* 120 */ K_ALT_1,      K_ALT_2,      K_ALT_3,      K_ALT_4,      K_ALT_5,
133 /* 125 */ K_ALT_6,      K_ALT_7,      K_ALT_8,      K_ALT_9,      K_ESC,
134 /* 130 */ K_DEL};
135 
136 
137 
138 #ifdef OUT_OF_ORDER
show_term_descr(struct termios * curr_term_descr)139 static void show_term_descr (struct termios *curr_term_descr)
140 
141   {
142     int pos;
143 
144   /* show_term_descr */
145     printf("c_iflag=%x\n", curr_term_descr->c_iflag);      /* input modes */
146     printf("c_oflag=%x\n", curr_term_descr->c_oflag);      /* output modes */
147     printf("c_cflag=%x\n", curr_term_descr->c_cflag);      /* control modes */
148     printf("c_lflag=%x\n", curr_term_descr->c_lflag);      /* local modes */
149     for (pos = 0; pos < NCCS; pos++) {
150       printf("%d ", curr_term_descr->c_cc[pos]);
151     } /* for */
152     printf("\n");
153     printf("ECHO=%d\n", (curr_term_descr->c_lflag & ECHO) != 0);
154     printf("ECHOE=%d\n", (curr_term_descr->c_lflag & ECHOE) != 0);
155     printf("ECHOK=%d\n", (curr_term_descr->c_lflag & ECHOK) != 0);
156     printf("ECHONL=%d\n", (curr_term_descr->c_lflag & ECHONL) != 0);
157     printf("ICANON=%d\n", (curr_term_descr->c_lflag & ICANON) != 0);
158     printf("VINTR=%d\n", curr_term_descr->c_cc[VINTR]);
159     printf("VQUIT=%d\n", curr_term_descr->c_cc[VQUIT]);
160     printf("VSTOP=%d\n", curr_term_descr->c_cc[VSTOP]);
161 #ifdef VSTART
162     printf("VSTART=%d\n", curr_term_descr->c_cc[VSTART]);
163 #endif
164 #ifdef VSUSP
165     printf("VSUSP=%d\n", curr_term_descr->c_cc[VSUSP]);
166 #endif
167     printf("VMIN=%d\n", curr_term_descr->c_cc[VMIN]);
168     printf("VTIME=%d\n", curr_term_descr->c_cc[VTIME]);
169   } /* show_term_descr */
170 #endif
171 
172 
173 
174 /**
175  *  Determine if two termios structs are equal.
176  *  Comparing with memcmp does not work correctly.
177  *  Struct termios has data at and after &c_cc[NCCS].
178  *  Therefore memcmp sees differences, even if the
179  *  official fields of struct termios are equal.
180  *  @return TRUE if the termios structs are equal,
181  *          FALSE otherwise.
182  */
term_descr_equal(struct termios * term_descr1,struct termios * term_descr2)183 static boolType term_descr_equal (struct termios *term_descr1, struct termios *term_descr2)
184 
185   {
186     int pos;
187     boolType equal;
188 
189   /* term_descr_equal */
190     equal = term_descr1->c_iflag == term_descr2->c_iflag &&
191             term_descr1->c_oflag == term_descr2->c_oflag &&
192             term_descr1->c_cflag == term_descr2->c_cflag &&
193             term_descr1->c_lflag == term_descr2->c_lflag;
194     for (pos = 0; pos < NCCS; pos++) {
195       if (term_descr1->c_cc[pos] != term_descr2->c_cc[pos]) {
196         equal = FALSE;
197       } /* if */
198     } /* for */
199     return equal;
200   } /* term_descr_equal */
201 
202 
203 
204 /**
205  *  Change the terminal attributes to 'new_term_descr'.
206  *  The function tcsetattr() returns success if any of the
207  *  requested changes could be successfully carried out.
208  *  If doing multiple changes it is necessary to check
209  *  with tcgetattr(), that all changes have been performed
210  *  successfully.
211  *  @return TRUE if the change of the attributes was successful,
212  *          FALSE otherwise.
213  */
tcset_term_descr(int file_no,struct termios * new_term_descr)214 static boolType tcset_term_descr (int file_no, struct termios *new_term_descr)
215 
216   {
217     struct termios term_descr_check;
218     int trial = 0;
219     boolType succeeded = FALSE;
220 
221   /* tcset_term_descr */
222     do {
223       trial++;
224       if (tcsetattr(file_no, TCSANOW, new_term_descr) == 0 &&
225           tcgetattr(file_no, &term_descr_check) == 0 &&
226           term_descr_equal(new_term_descr, &term_descr_check)) {
227         succeeded = TRUE;
228       } /* if */
229     } while (!succeeded && trial < 10);
230     /* show_term_descr(new_term_descr);
231        show_term_descr(&term_descr_check); */
232     /* printf("trial=%d\n", trial); */
233     return succeeded;
234   } /* tcset_term_descr */
235 
236 
237 
238 /**
239  *  Change the terminal attributes 'vmin' and 'vtime'.
240  *  The function tcsetattr() returns success if any of the
241  *  requested changes could be successfully carried out.
242  *  If doing multiple changes it is necessary to check
243  *  with tcgetattr(), that all changes have been performed
244  *  successfully.
245  *  @return TRUE if the change of the attributes was successful,
246  *          FALSE otherwise.
247  */
tcset_vmin_vtime(int file_no,int vmin,int vtime)248 static boolType tcset_vmin_vtime (int file_no, int vmin, int vtime)
249 
250   {
251     struct termios term_descr_check;
252     int trial = 0;
253     boolType succeeded = FALSE;
254 
255   /* tcset_vmin_vtime */
256     term_descr.c_cc[VMIN]  = (cc_t) vmin;
257     term_descr.c_cc[VTIME] = (cc_t) vtime;
258     do {
259       trial++;
260       if (tcsetattr(file_no, TCSANOW, &term_descr) == 0 &&
261           tcgetattr(file_no, &term_descr_check) == 0 &&
262           term_descr_check.c_cc[VMIN]  == vmin &&
263           term_descr_check.c_cc[VTIME] == vtime) {
264         succeeded = TRUE;
265       } /* if */
266     } while (!succeeded && trial < 10);
267     return succeeded;
268   } /* tcset_vmin_vtime */
269 
270 
271 
read_char_if_present(ucharType * ch)272 static boolType read_char_if_present (ucharType *ch)
273 
274   {
275     int file_no;
276     boolType result;
277 
278   /* read_char_if_present */
279     file_no = fileno(stdin);
280     tcset_vmin_vtime(file_no, 0, 10); /* Time in units of 0.1 seconds */
281     result = read(file_no, ch, 1) == 1;
282     tcset_vmin_vtime(file_no, 1, 0);
283     return result;
284   } /* read_char_if_present */
285 
286 
287 
consume_chars_present(void)288 static void consume_chars_present (void)
289 
290   {
291     int file_no;
292     ucharType ch;
293 
294   /* consume_chars_present */
295     file_no = fileno(stdin);
296     tcset_vmin_vtime(file_no, 0, 0);
297     while (read(file_no, &ch, 1) == 1) {
298       /* printf("consume: %d\n", ch); */
299     } /* while */
300     tcset_vmin_vtime(file_no, 1, 0);
301   } /* consume_chars_present */
302 
303 
304 
read_utf8_key(ustriType ustri,size_t ustri_len)305 static charType read_utf8_key (ustriType ustri, size_t ustri_len)
306 
307   {
308     memSizeType len;
309     strElemType stri[6];
310     memSizeType dest_len;
311 
312   /* read_utf8_key */
313     if (ustri[0] <= 0x7F) {
314       if (ustri_len == 1) {
315         return ustri[0];
316       } else { /* ustri_len == 2 */
317         last_key = ustri[1];
318         key_buffer_filled = TRUE;
319         return ustri[0];
320       } /* if */
321     } else if ((ustri[0] & 0xE0) == 0xC0) {
322       len = 2;
323     } else if ((ustri[0] & 0xF0) == 0xE0) {
324       len = 3;
325     } else if ((ustri[0] & 0xF8) == 0xF0) {
326       len = 4;
327     } else if ((ustri[0] & 0xFC) == 0xF8) {
328       len = 5;
329     } else if ((ustri[0] & 0xFC) == 0xFC) {
330       len = 6;
331     } else {
332       if (ustri_len == 1) {
333         return ustri[0];
334       } else { /* ustri_len == 2 */
335         last_key = ustri[1];
336         key_buffer_filled = TRUE;
337         return ustri[0];
338       } /* if */
339     } /* if */
340     if (ustri_len == 2 && (ustri[1] & 0xC0) != 0x80) {
341       last_key = ustri[1];
342       key_buffer_filled = TRUE;
343       return ustri[0];
344     } else {
345       while (ustri_len < len) {
346         if (read_char_if_present(&ustri[ustri_len])) {
347           ustri[ustri_len + 1] = '\0';
348         } else {
349           ustri[ustri_len] = '\0';
350         } /* if */
351         if (ustri[ustri_len] == '\0') {
352           if (ustri_len == 1) {
353             return ustri[0];
354           } else {
355             return K_UNDEF;
356           } /* if */
357         } else if ((ustri[ustri_len] & 0xC0) != 0x80) {
358           last_key = ustri[ustri_len];
359           key_buffer_filled = TRUE;
360           if (ustri_len == 1) {
361             return ustri[0];
362           } else {
363             return K_UNDEF;
364           } /* if */
365         } /* if */
366         ustri_len++;
367       } /* while */
368       if (utf8_to_stri(stri, &dest_len, ustri, len) == 0 &&
369           dest_len == 1) {
370         return stri[0];
371       } else {
372         return K_UNDEF;
373       } /* if */
374     } /* if */
375   } /* read_utf8_key */
376 
377 
378 
read_f_key(charType actual_char)379 static charType read_f_key (charType actual_char)
380 
381   {
382     char in_buffer[101];
383     static char last_partial_match[101];
384     static time_t last_partial_time = 0;
385     size_t pos;
386     int exact_match;
387     int partial_match;
388     int number;
389     size_t len;
390     int key_number;
391     charType result;
392 
393   /* read_f_key */
394     if (last_partial_time != 0) {
395       if (time(NULL) - last_partial_time < 5) {
396         /* If the previous call of read_f_key was at most 5 seconds */
397         /* ago and the function key was recognised with a partial   */
398         /* match and a timeout the following check is done. It is   */
399         /* checked if the new character together with the           */
400         /* characters from the partial match of the previous call   */
401         /* of read_f_key are a possible begin of a function key. In */
402         /* this case it was wrong that the previous call of         */
403         /* read_f_key submits the function key found with a partial */
404         /* match and a timeout. Hopefully the function key did not  */
405         /* damage something. Normally the function key deliverd in  */
406         /* such a case is the escape key. For that reason escape    */
407         /* should not start any dangerous function. Terminating a   */
408         /* function with escape should be safe. The following       */
409         /* actions are done to avoid further damage. As long as     */
410         /* characters are already typed in they are read and        */
411         /* discarded. If no more characters are present in the      */
412         /* input queue the function returns K_NULLCMD. The          */
413         /* K_NULLCMD should do nothing in every application.        */
414         /* fprintf(stderr, "<possible garbage keys>"); */
415         pos = strlen(last_partial_match);
416         last_partial_match[pos] = (char) actual_char;
417         last_partial_match[pos + 1] = '\0';
418         pos++;
419         key_number = 0;
420         exact_match = 0;
421         partial_match = 0;
422         for (number = 0; number < SIZE_KEY_TABLE; number++) {
423           if (key_table[number] != NULL) {
424             len = strlen(key_table[number]);
425             if (pos <= len) {
426               if (strncmp(key_table[number], last_partial_match,
427                   pos) == 0) {
428                 if (pos == len) {
429                   exact_match++;
430                   key_number = number;
431                 } else {
432                   partial_match++;
433                 } /* if */
434               } /* if */
435             } /* if */
436           } /* if */
437         } /* for */
438         if (exact_match != 0 || partial_match != 0) {
439 #ifdef TRACE_FKEYS
440           printf("exact %d partial %d - consume_chars_present\n",
441               exact_match, partial_match);
442 #endif
443           consume_chars_present();
444           last_partial_time = 0;
445           return K_NULLCMD;
446         } /* if */
447       } /* if */
448       last_partial_time = 0;
449     } /* if */
450     in_buffer[0] = (char) actual_char;
451     in_buffer[1] = '\0';
452     pos = 1;
453     do {
454       key_number = 0;
455       exact_match = 0;
456       partial_match = 0;
457       for (number = 0; number < SIZE_KEY_TABLE; number++) {
458         if (key_table[number] != NULL) {
459           len = strlen(key_table[number]);
460           if (pos <= len) {
461             if (strncmp(key_table[number], in_buffer,
462                 pos) == 0) {
463               if (pos == len) {
464                 exact_match++;
465                 key_number = number;
466               } else {
467                 partial_match++;
468               } /* if */
469             } /* if */
470           } /* if */
471         } /* if */
472       } /* for */
473 #ifdef TRACE_FKEYS
474       { char *cha = in_buffer;
475         printf("key match \"");
476         while (*cha != 0) {
477           if (*cha == '\"' || *cha == '\\') {
478             printf("\%c", *cha);
479           } else if (*cha >= ' ' && *cha <= '~') {
480             printf("%c", *cha);
481           } else {
482             printf("\\%d\\", (int) *cha);
483           } /* if */
484           cha++;
485         } /* while */
486         printf("\" exact %d partial %d\n", exact_match, partial_match);
487       }
488 #endif
489       if (exact_match == 0) {
490         if (partial_match != 0) {
491           if (read(fileno(stdin), &in_buffer[pos], 1) != 1) {
492             in_buffer[pos] = (char) EOF;
493           } /* if */
494           in_buffer[pos + 1] = '\0';
495         } /* if */
496       } else {
497         if (partial_match != 0) {
498           if (read_char_if_present((ucharType *) &in_buffer[pos])) {
499             in_buffer[pos + 1] = '\0';
500           } else {
501             strcpy(last_partial_match, in_buffer);
502             last_partial_time = time(NULL);
503             partial_match = 0;
504           } /* if */
505         } /* if */
506       } /* if */
507       pos++;
508     } while (partial_match != 0 && pos < 100);
509     if (exact_match == 1) {
510       result = key_code[key_number];
511     } else {
512       if (pos == 2 || pos == 3) {
513         if (utf8_mode) {
514           result = read_utf8_key((ustriType) in_buffer, pos - 1);
515         } else {
516           if (pos == 2) {
517             result = actual_char;
518           } else { /* if (pos == 3) { */
519             last_key = in_buffer[1];
520             key_buffer_filled = TRUE;
521             result = actual_char;
522           } /* if */
523         } /* if */
524       } else {
525         result = K_UNDEF;
526       } /* if */
527     } /* if */
528     return result;
529   } /* read_f_key */
530 
531 
532 
utf8_init(void)533 static void utf8_init (void)
534 
535   {
536     char *s;
537 
538   /* utf8_init */
539     if (((s = getenv("LC_ALL"))   && *s) ||
540         ((s = getenv("LC_CTYPE")) && *s) ||
541         ((s = getenv("LANG"))     && *s)) {
542       if (strstr(s, "UTF-8") || strstr(s, "utf8")) {
543         utf8_mode = TRUE;
544       } /* if */
545     } else {
546       utf8_mode = TRUE;
547     } /* if */
548   } /* utf8_init */
549 
550 
551 
key_table_init(void)552 static void key_table_init (void)
553 
554   {
555     int number;
556     int num2;
557 
558   /* key_table_init */
559     /* fprintf(stderr, "keypad_xmit=\"%s\"\n", keypad_xmit); */
560     putcontrol(keypad_xmit); /* keypad_transmit_mode */
561     key_table[ 0] = erase_ch;   /* K_BS */
562     /* printf("erase_ch %d\n", erase_ch[0]); */
563     if (key_backspace != NULL && strcmp(key_backspace, erase_ch) != 0) {
564       /* If the backspace character defined in the terminfo/termcap */
565       /* database is different from the erase character defined by  */
566       /* the terminal device it is defined additionally as K_BS.    */
567       key_table[ 1] = key_backspace; /* K_BS */
568     } else {
569       key_table[ 1] = NULL;
570     } /* if */
571     /* printf("key_backspace %d\n", key_backspace[0]); */
572     key_table[ 2] = key_btab;   /* K_BACKTAB */
573     key_table[ 3] = key_b2;     /* K_PAD_CENTER */
574     key_table[ 4] = key_catab;
575     key_table[ 5] = key_clear;
576     key_table[ 6] = key_ctab;
577     key_table[ 7] = key_dc;     /* K_DEL */
578     key_table[ 8] = key_dl;     /* K_DELLN */
579     key_table[ 9] = key_down;   /* K_DOWN */
580     key_table[10] = key_eic;    /* K_INS */
581     key_table[11] = key_end;    /* K_END */
582     key_table[12] = key_enter;  /* K_NL */
583     key_table[13] = key_eol;
584     key_table[14] = key_eos;
585     key_table[15] = key_home;   /* K_HOME */
586     key_table[16] = key_f0;
587     key_table[17] = key_f1;     /* K_F1 */
588     key_table[18] = key_f2;     /* K_F2 */
589     key_table[19] = key_f3;     /* K_F3 */
590     key_table[20] = key_f4;     /* K_F4 */
591     key_table[21] = key_f5;     /* K_F5 */
592     key_table[22] = key_f6;     /* K_F6 */
593     key_table[23] = key_f7;     /* K_F7 */
594     key_table[24] = key_f8;     /* K_F8 */
595     key_table[25] = key_f9;     /* K_F9 */
596     key_table[26] = key_f10;    /* K_F10 */
597     key_table[27] = key_f11;    /* K_F11 */
598     key_table[28] = key_f12;    /* K_F12 */
599     key_table[29] = key_f13;    /* K_SFT_F1 */
600     key_table[30] = key_f14;    /* K_SFT_F2 */
601     key_table[31] = key_f15;    /* K_SFT_F3 */
602     key_table[32] = key_f16;    /* K_SFT_F4 */
603     key_table[33] = key_f17;    /* K_SFT_F5 */
604     key_table[34] = key_f18;    /* K_SFT_F6 */
605     key_table[35] = key_f19;    /* K_SFT_F7 */
606     key_table[36] = key_f20;    /* K_SFT_F8 */
607     key_table[37] = key_f21;    /* K_SFT_F9 */
608     key_table[38] = key_f22;    /* K_SFT_F10 */
609     key_table[39] = key_f23;    /* K_SFT_F11 */
610     key_table[40] = key_f24;    /* K_SFT_F12 */
611     key_table[41] = key_f25;    /* K_CTL_F1 */
612     key_table[42] = key_f26;    /* K_CTL_F2 */
613     key_table[43] = key_f27;    /* K_CTL_F3 */
614     key_table[44] = key_f28;    /* K_CTL_F4 */
615     key_table[45] = key_f29;    /* K_CTL_F5 */
616     key_table[46] = key_f30;    /* K_CTL_F6 */
617     key_table[47] = key_f31;    /* K_CTL_F7 */
618     key_table[48] = key_f32;    /* K_CTL_F8 */
619     key_table[49] = key_f33;    /* K_CTL_F9 */
620     key_table[50] = key_f34;    /* K_CTL_F10 */
621     key_table[51] = key_f35;    /* K_CTL_F11 */
622     key_table[52] = key_f36;    /* K_CTL_F12 */
623     key_table[53] = key_f37;
624     key_table[54] = key_f38;
625     key_table[55] = key_f39;
626     key_table[56] = key_f40;
627     key_table[57] = key_f41;
628     key_table[58] = key_f42;
629     key_table[59] = key_f43;
630     key_table[60] = key_f44;
631     key_table[61] = key_f45;
632     key_table[62] = key_f46;
633     key_table[63] = key_f47;
634     key_table[64] = key_f48;
635     key_table[65] = key_f49;    /* K_ALT_F1 */
636     key_table[66] = key_f50;    /* K_ALT_F2 */
637     key_table[67] = key_f51;    /* K_ALT_F3 */
638     key_table[68] = key_f52;    /* K_ALT_F4 */
639     key_table[69] = key_f53;    /* K_ALT_F5 */
640     key_table[70] = key_f54;    /* K_ALT_F6 */
641     key_table[71] = key_f55;    /* K_ALT_F7 */
642     key_table[72] = key_f56;    /* K_ALT_F8 */
643     key_table[73] = key_f57;    /* K_ALT_F9 */
644     key_table[74] = key_f58;    /* K_ALT_F10 */
645     key_table[75] = key_f59;    /* K_ALT_F11 */
646     key_table[76] = key_f60;    /* K_ALT_F12 */
647     key_table[77] = key_f61;
648     key_table[78] = key_f62;
649     key_table[79] = key_f63;
650     key_table[80] = key_find;   /* K_HOME */
651     key_table[81] = key_ic;     /* K_INS */
652     key_table[82] = key_il;     /* K_INSLN */
653     key_table[83] = key_left;   /* K_LEFT */
654     key_table[84] = key_ll;     /* K_END */
655     key_table[85] = key_npage;  /* K_PGDN */
656     key_table[86] = key_ppage;  /* K_PGUP */
657     key_table[87] = key_right;  /* K_RIGHT */
658     key_table[88] = key_select; /* K_END */
659     key_table[89] = key_sf;     /* K_SCRLDN */
660     key_table[90] = key_sr;     /* K_SCRLUP */
661     key_table[91] = key_stab;
662     key_table[92] = key_up;     /* K_UP */
663     key_table[93] = "\033a";    /* K_ALT_A */
664     key_table[94] = "\033b";    /* K_ALT_B */
665     key_table[95] = "\033c";    /* K_ALT_C */
666     key_table[96] = "\033d";    /* K_ALT_D */
667     key_table[97] = "\033e";    /* K_ALT_E */
668     key_table[98] = "\033f";    /* K_ALT_F */
669     key_table[99] = "\033g";    /* K_ALT_G */
670     key_table[100] = "\033h";    /* K_ALT_H */
671     key_table[101] = "\033i";   /* K_ALT_I */
672     key_table[102] = "\033j";   /* K_ALT_J */
673     key_table[103] = "\033k";   /* K_ALT_K */
674     key_table[104] = "\033l";   /* K_ALT_L */
675     key_table[105] = "\033m";   /* K_ALT_M */
676     key_table[106] = "\033n";   /* K_ALT_N */
677     key_table[107] = "\033o";   /* K_ALT_O */
678     key_table[108] = "\033p";   /* K_ALT_P */
679     key_table[109] = "\033q";   /* K_ALT_Q */
680     key_table[110] = "\033r";   /* K_ALT_R */
681     key_table[111] = "\033s";   /* K_ALT_S */
682     key_table[112] = "\033t";   /* K_ALT_T */
683     key_table[113] = "\033u";   /* K_ALT_U */
684     key_table[114] = "\033v";   /* K_ALT_V */
685     key_table[115] = "\033w";   /* K_ALT_W */
686     key_table[116] = "\033x";   /* K_ALT_X */
687     key_table[117] = "\033y";   /* K_ALT_Y */
688     key_table[118] = "\033z";   /* K_ALT_Z */
689     key_table[119] = "\0330";   /* K_ALT_0 */
690     key_table[120] = "\0331";   /* K_ALT_1 */
691     key_table[121] = "\0332";   /* K_ALT_2 */
692     key_table[122] = "\0333";   /* K_ALT_3 */
693     key_table[123] = "\0334";   /* K_ALT_4 */
694     key_table[124] = "\0335";   /* K_ALT_5 */
695     key_table[125] = "\0336";   /* K_ALT_6 */
696     key_table[126] = "\0337";   /* K_ALT_7 */
697     key_table[127] = "\0338";   /* K_ALT_8 */
698     key_table[128] = "\0339";   /* K_ALT_9 */
699     key_table[129] = "\033";    /* K_ESC */
700     key_table[130] = "\177";    /* K_DEL */
701     /* Some function key definitions start with a printable         */
702     /* character. This makes absolutely no sense and confuses the   */
703     /* function key recognition. Therefore such definitions are     */
704     /* thrown out here.                                             */
705     for (number = 0; number < SIZE_KEY_TABLE; number++) {
706 #ifdef TRACE_FKEYS
707       if (key_table[number] != NULL) {
708         const_cstriType ch_ptr;
709 
710         fprintf(stderr, "key%d=\"", number);
711         ch_ptr = key_table[number];
712         while (*ch_ptr != '\0') {
713           if (*ch_ptr <= 31) {
714             fprintf(stderr, "^%c", *ch_ptr + '@');
715           } else if (*ch_ptr == '^' || *ch_ptr == '\\') {
716             fprintf(stderr, "%c%c", *ch_ptr, *ch_ptr);
717           } else if (*ch_ptr <= 126) {
718             fprintf(stderr, "%c", *ch_ptr);
719           } else {
720             fprintf(stderr, "\\%3o", *ch_ptr);
721           } /* if */
722           ch_ptr++;
723         } /* while */
724         fprintf(stderr, "\"\n");
725       } else {
726         fprintf(stderr, "key%d=NULL\n", number);
727       } /* if */
728 #endif
729       if (key_table[number] != NULL &&
730           key_table[number][0] >= ' ' && key_table[number][0] <= '~') {
731         /* fprintf(stderr, "key%d=\"%s\" thrown out\n",
732             number, key_table[number]); */
733         key_table[number] = NULL;
734       } /* if */
735     } /* for */
736     /* Sometimes there are double entries in the function key       */
737     /* definitions. This makes absolutely no sense and confuses the */
738     /* function key recognition. Therefore such definitions are     */
739     /* thrown out here.                                             */
740     for (number = 0; number < SIZE_KEY_TABLE; number++) {
741       for (num2 = number + 1; num2 < SIZE_KEY_TABLE; num2++) {
742         if (key_table[number] != NULL && key_table[num2] != NULL &&
743             strcmp(key_table[number], key_table[num2]) == 0) {
744           /* fprintf(stderr, "key%d=kex%d=\"%s\"\n",
745               number, num2, key_table[number]); */
746           key_table[num2] = NULL;
747         } /* if */
748       } /* for */
749     } /* for */
750   } /* key_table_init */
751 
752 
753 
kbdShut(void)754 void kbdShut (void)
755 
756   { /* kbdShut */
757     if (keybd_initialized) {
758       tcset_term_descr(fileno(stdin), &term_bak);
759       if (caps_initialized) {
760         /* fprintf(stderr, "keypad_local=\"%s\"\n", keypad_local); */
761         putcontrol(keypad_local); /* out of keypad transmit mode */
762       } /* if */
763       keybd_initialized = FALSE;
764     } /* if */
765   } /* kbdShut */
766 
767 
768 
kbd_init(void)769 static void kbd_init (void)
770 
771   {
772     int file_no;
773 
774   /* kbd_init */
775     if (!findTermDll()) {
776       logError(printf("kbd_init: findTermDll() failed.\n"););
777     } else {
778       if (!caps_initialized) {
779         getcaps();
780       } /* if */
781       file_no = fileno(stdin);
782       if (tcgetattr(file_no, &term_descr) != 0) {
783         printf("kbd_init: tcgetattr(%d, ...) failed:\n"
784                "errno=%d\nerror: %s\n",
785                file_no, errno, strerror(errno));
786       } else {
787         /* show_term_descr(&term_descr); */
788         memcpy(&term_bak, &term_descr, sizeof(struct termios));
789         erase_ch[0] = (char) term_descr.c_cc[VERASE];
790         erase_ch[1] = '\0';
791         /* printf("erase_ch %d\n", erase_ch[0]); */
792         term_descr.c_lflag &= (unsigned int) ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
793         term_descr.c_cc[VINTR] = (cc_t) -1;
794         term_descr.c_cc[VQUIT] = (cc_t) -1;
795         term_descr.c_cc[VSTOP] = (cc_t) -1;
796 #ifdef VSTART
797         term_descr.c_cc[VSTART] = (cc_t) -1;
798 #endif
799 #ifdef VSUSP
800         term_descr.c_cc[VSUSP] = (cc_t) -1;
801 #endif
802         term_descr.c_cc[VMIN] = 1;
803         term_descr.c_cc[VTIME] = 0;
804         if (!tcset_term_descr(file_no, &term_descr)) {
805           printf("kbd_init: tcsetattr(%d, VMIN=1) failed:\n"
806                  "errno=%d\nerror: %s\n",
807                  file_no, errno, strerror(errno));
808           /* show_term_descr(&term_descr); */
809         } else {
810           keybd_initialized = TRUE;
811           atexit(kbdShut);
812           if (getcaps()) {
813             key_table_init();
814           } /* if */
815           utf8_init();
816           fflush(stdout);
817         } /* if */
818       } /* if */
819     } /* if */
820   } /* kbd_init */
821 
822 
823 
kbdKeyPressed(void)824 boolType kbdKeyPressed (void)
825 
826   {
827     int file_no;
828     char buffer;
829     boolType result;
830 
831   /* kbdKeyPressed */
832     if (!keybd_initialized) {
833       kbd_init();
834     } /* if */
835     if (!keybd_initialized) {
836       logError(printf("kbdKeyPressed: kbd_init() failed to open the keyboard.\n"););
837       raise_error(FILE_ERROR);
838       result = FALSE;
839     } else if (key_buffer_filled) {
840       result = TRUE;
841     } else {
842       if (changes) {
843         conFlush();
844       } /* if */
845       file_no = fileno(stdin);
846       if (!tcset_vmin_vtime(file_no, 0, 0)) {
847         printf("kbdKeyPressed: tcsetattr(%d, VMIN=0) failed:\n"
848                "errno=%d\nerror: %s\n",
849                file_no, errno, strerror(errno));
850         result = FALSE;
851       } else {
852         if (read(file_no, &buffer, 1) == 1) {
853           result = TRUE;
854           last_key = buffer;
855           key_buffer_filled = TRUE;
856         } else {
857           result = FALSE;
858         } /* if */
859         if (!tcset_vmin_vtime(file_no, 1, 0)) {
860           printf("kbdKeyPressed: tcsetattr(%d, VMIN=1) failed:\n"
861                  "errno=%d\nerror: %s\n",
862                  file_no, errno, strerror(errno));
863         } /* if */
864       } /* if */
865     } /* if */
866     return result;
867   } /* kbdKeyPressed */
868 
869 
870 
kbdGetc(void)871 charType kbdGetc (void)
872 
873   {
874     ucharType ch;
875     charType result;
876 
877   /* kbdGetc */
878     if (!keybd_initialized) {
879       kbd_init();
880     } /* if */
881     if (!keybd_initialized) {
882       logError(printf("kbdGetc: kbd_init() failed to open the keyboard.\n"););
883       raise_error(FILE_ERROR);
884       result = (charType) EOF;
885     } else if (key_buffer_filled) {
886       key_buffer_filled = FALSE;
887       result = (charType) last_key;
888     } else {
889       if (changes) {
890         conFlush();
891       } /* if */
892       if (read(fileno(stdin), &ch, 1) != 1) {
893         result = (charType) EOF;
894       } else {
895         result = (charType) ch;
896       } /* if */
897     } /* if */
898     result = read_f_key(result);
899 /*  fprintf(stderr, "<%d>", result); */
900     return result;
901   } /* kbdGetc */
902 
903 
904 
kbdRawGetc(void)905 charType kbdRawGetc (void)
906 
907   {
908     ucharType ch;
909     charType result;
910 
911   /* kbdRawRead */
912     if (!keybd_initialized) {
913       kbd_init();
914     } /* if */
915     if (!keybd_initialized) {
916       logError(printf("kbdRawGetc: kbd_init() failed to open the keyboard.\n"););
917       raise_error(FILE_ERROR);
918       result = (charType) EOF;
919     } else if (key_buffer_filled) {
920       key_buffer_filled = FALSE;
921       result = ((charType) last_key) & 0xFF;
922     } else {
923       if (changes) {
924         conFlush();
925       } /* if */
926       if (read(fileno(stdin), &ch, 1) != 1) {
927         result = (charType) EOF;
928       } else {
929         result = (charType) ch;
930       } /* if */
931     } /* if */
932 /*  fprintf(stderr, "<%d>", result); */
933     return result;
934   } /* kbdRawRead */
935 
936 #endif
937