1 /* $Id: keyboard.c,v 1.37 2018/07/26 00:22:47 tom Exp $ */
2 
3 #include <vttest.h>
4 #include <ttymodes.h>
5 #include <esc.h>
6 
7 /* Test of:
8      - DECLL   (Load LEDs)
9      - Keyboard return messages
10      - SM RM   (Set/Reset Mode) - Cursor Keys
11                                 - Auto repeat
12      - DECKPAM (Keypad Application Mode)
13      - DECKPNM (Keypad Numeric Mode)
14 
15 The standard VT100 keyboard layout:
16 
17                                                         UP   DN   LE  RI
18 
19 ESC   1!   2@   3#   4$   5%   6^   7&   8*   9(   0)   -_   =+   `~  BS
20 
21 TAB*    qQ   wW   eE   rR   tT   yY   uU   iI   oO   pP   [{   ]}      DEL
22 
23 **   **   aA   sS   dD   fF   gG   hH   jJ   kK   lL   ;:   ,"   RETN  \|
24 
25 **   ****   zZ   xX   cC   vV   bB   nN   mM   ,<   .>   /?   ****   LF
26 
27              ****************SPACE BAR****************
28 
29                                                            PF1 PF2 PF3 PF4
30 
31                                                            *7* *8* *9* *-*
32 
33                                                            *4* *5* *6* *,*
34 
35                                                            *1* *2* *3*
36 
37                                                            ***0*** *.* ENT
38 
39 The standard LK401 (VT420) keyboard layout:
40 
41 F1 F2 F3 F4 F5   F6 F7 F8 F9 F10   F11 F12 F13 F14   Help Do   F17 F18 F19 F20
42 
43   `~  1!   2@   3#   4$   5%   6^   7&   8*   9(   0)   -_   =+   DEL
44 
45 TAB*    qQ   wW   eE   rR   tT   yY   uU   iI   oO   pP   [{   ]}   Return
46 
47 **   **   aA   sS   dD   fF   gG   hH   jJ   kK   lL   ;:   ,"   \|
48 
49 *****   <>  zZ   xX   cC   vV   bB   nN   mM   ,<   .>   /?    ******
50 
51 ***** *****  ****************SPACE BAR****************  ****** ******
52 
53                        Find  Insert Remove                 PF1 PF2 PF3 PF4
54 
55                       Select  Prev   Next                  *7* *8* *9* *-*
56 
57                                Up                          *4* *5* *6* *,*
58 
59                        Left   Down   Right                 *1* *2* *3*
60 
61                                                            ***0*** *.* ENT
62 */
63 /* *INDENT-OFF* */
64 static struct key {
65     char c;
66     int  row;
67     int  col;
68     const char *symbol;
69 } VT100_keytab [] = {
70     { ESC, 1,  0, "ESC" },
71     { '1', 1,  6, "1" },    { '!', 1,  7, "!" },
72     { '2', 1, 11, "2" },    { '@', 1, 12, "@" },
73     { '3', 1, 16, "3" },    { '#', 1, 17, "#" },
74     { '4', 1, 21, "4" },    { '$', 1, 22, "$" },
75     { '5', 1, 26, "5" },    { '%', 1, 27, "%" },
76     { '6', 1, 31, "6" },    { '^', 1, 32, "^" },
77     { '7', 1, 36, "7" },    { '&', 1, 37, "&" },
78     { '8', 1, 41, "8" },    { '*', 1, 42, "*" },
79     { '9', 1, 46, "9" },    { '(', 1, 47, "(" },
80     { '0', 1, 51, "0" },    { ')', 1, 52, ")" },
81     { '-', 1, 56, "-" },    { '_', 1, 57, "_" },
82     { '=', 1, 61, "=" },    { '+', 1, 62, "+" },
83     { '`', 1, 66, "`" },    { '~', 1, 67, "~" },
84     {   8, 1, 70, "BS" },
85     {   9, 2,  0, " TAB " },
86     { 'q', 2,  8, "q" },    { 'Q', 2,  9, "Q" },
87     { 'w', 2, 13, "w" },    { 'W', 2, 14, "W" },
88     { 'e', 2, 18, "e" },    { 'E', 2, 19, "E" },
89     { 'r', 2, 23, "r" },    { 'R', 2, 24, "R" },
90     { 't', 2, 28, "t" },    { 'T', 2, 29, "T" },
91     { 'y', 2, 33, "y" },    { 'Y', 2, 34, "Y" },
92     { 'u', 2, 38, "u" },    { 'U', 2, 39, "U" },
93     { 'i', 2, 43, "i" },    { 'I', 2, 44, "I" },
94     { 'o', 2, 48, "o" },    { 'O', 2, 49, "O" },
95     { 'p', 2, 53, "p" },    { 'P', 2, 54, "P" },
96     { '[', 2, 58, "[" },    { '{', 2, 59, "{" },
97     { ']', 2, 63, "]" },    { '}', 2, 64, "}" },
98     { 127, 2, 71, "DEL" },
99     { 'a', 3, 10, "a" },    { 'A', 3, 11, "A" },
100     { 's', 3, 15, "s" },    { 'S', 3, 16, "S" },
101     { 'd', 3, 20, "d" },    { 'D', 3, 21, "D" },
102     { 'f', 3, 25, "f" },    { 'F', 3, 26, "F" },
103     { 'g', 3, 30, "g" },    { 'G', 3, 31, "G" },
104     { 'h', 3, 35, "h" },    { 'H', 3, 36, "H" },
105     { 'j', 3, 40, "j" },    { 'J', 3, 41, "J" },
106     { 'k', 3, 45, "k" },    { 'K', 3, 46, "K" },
107     { 'l', 3, 50, "l" },    { 'L', 3, 51, "L" },
108     { ';', 3, 55, ";" },    { ':', 3, 56, ":" },
109     {'\'', 3, 60, "'" },    { '"', 3, 61,"\"" },
110     {  13, 3, 65, "RETN"},
111     {'\\', 3, 71,"\\" },    { '|', 3, 72, "|" },
112     { 'z', 4, 12, "z" },    { 'Z', 4, 13, "Z" },
113     { 'x', 4, 17, "x" },    { 'X', 4, 18, "X" },
114     { 'c', 4, 22, "c" },    { 'C', 4, 23, "C" },
115     { 'v', 4, 27, "v" },    { 'V', 4, 28, "V" },
116     { 'b', 4, 32, "b" },    { 'B', 4, 33, "B" },
117     { 'n', 4, 37, "n" },    { 'N', 4, 38, "N" },
118     { 'm', 4, 42, "m" },    { 'M', 4, 43, "M" },
119     { ',', 4, 47, "," },    { '<', 4, 48, "<" },
120     { '.', 4, 52, "." },    { '>', 4, 53, ">" },
121     { '/', 4, 57, "/" },    { '?', 4, 58, "?" },
122     {  10, 4, 69, "LF" },
123     { ' ', 5, 13, "                SPACE BAR                "},
124     {'\0', 0,  0, ""  }
125   },
126   LK401_keytab [] = {
127     { '`', 1,  3, "`" },    { '~', 1,  4, "~" },
128     { '1', 1,  7, "1" },    { '!', 1,  8, "!" },
129     { '2', 1, 12, "2" },    { '@', 1, 13, "@" },
130     { '3', 1, 17, "3" },    { '#', 1, 18, "#" },
131     { '4', 1, 22, "4" },    { '$', 1, 23, "$" },
132     { '5', 1, 27, "5" },    { '%', 1, 28, "%" },
133     { '6', 1, 32, "6" },    { '^', 1, 33, "^" },
134     { '7', 1, 37, "7" },    { '&', 1, 38, "&" },
135     { '8', 1, 42, "8" },    { '*', 1, 43, "*" },
136     { '9', 1, 47, "9" },    { '(', 1, 48, "(" },
137     { '0', 1, 52, "0" },    { ')', 1, 53, ")" },
138     { '-', 1, 57, "-" },    { '_', 1, 58, "_" },
139     { '=', 1, 62, "=" },    { '+', 1, 63, "+" },
140     { 127, 1, 67, "DEL" },
141     {   9, 2,  0, "TAB " },
142     { 'q', 2,  9, "q" },    { 'Q', 2, 10, "Q" },
143     { 'w', 2, 14, "w" },    { 'W', 2, 15, "W" },
144     { 'e', 2, 19, "e" },    { 'E', 2, 20, "E" },
145     { 'r', 2, 24, "r" },    { 'R', 2, 25, "R" },
146     { 't', 2, 29, "t" },    { 'T', 2, 30, "T" },
147     { 'y', 2, 34, "y" },    { 'Y', 2, 35, "Y" },
148     { 'u', 2, 39, "u" },    { 'U', 2, 40, "U" },
149     { 'i', 2, 44, "i" },    { 'I', 2, 45, "I" },
150     { 'o', 2, 49, "o" },    { 'O', 2, 50, "O" },
151     { 'p', 2, 54, "p" },    { 'P', 2, 55, "P" },
152     { '[', 2, 59, "[" },    { '{', 2, 60, "{" },
153     { ']', 2, 64, "]" },    { '}', 2, 65, "}" },
154     { 13,  2, 69, "Return" },
155     { 'a', 3, 11, "a" },    { 'A', 3, 12, "A" },
156     { 's', 3, 16, "s" },    { 'S', 3, 17, "S" },
157     { 'd', 3, 21, "d" },    { 'D', 3, 22, "D" },
158     { 'f', 3, 26, "f" },    { 'F', 3, 27, "F" },
159     { 'g', 3, 31, "g" },    { 'G', 3, 32, "G" },
160     { 'h', 3, 36, "h" },    { 'H', 3, 37, "H" },
161     { 'j', 3, 41, "j" },    { 'J', 3, 42, "J" },
162     { 'k', 3, 46, "k" },    { 'K', 3, 47, "K" },
163     { 'l', 3, 51, "l" },    { 'L', 3, 52, "L" },
164     { ';', 3, 56, ";" },    { ':', 3, 57, ":" },
165     {'\'', 3, 61, "'" },    { '"', 3, 62,"\"" },
166     {'\\', 3, 66,"\\" },    { '|', 3, 67, "|" },
167     { '<', 4,  9, "<" },    { '>', 4, 10, ">" },
168     { 'z', 4, 13, "z" },    { 'Z', 4, 14, "Z" },
169     { 'x', 4, 18, "x" },    { 'X', 4, 19, "X" },
170     { 'c', 4, 23, "c" },    { 'C', 4, 24, "C" },
171     { 'v', 4, 28, "v" },    { 'V', 4, 29, "V" },
172     { 'b', 4, 33, "b" },    { 'B', 4, 34, "B" },
173     { 'n', 4, 38, "n" },    { 'N', 4, 39, "N" },
174     { 'm', 4, 43, "m" },    { 'M', 4, 44, "M" },
175     { ',', 4, 48, "," },    { '<', 4, 49, "<" },
176     { '.', 4, 53, "." },    { '>', 4, 54, ">" },
177     { '/', 4, 58, "/" },    { '?', 4, 59, "?" },
178     { ' ', 5, 14, "                SPACE BAR                "},
179     {'\0', 0,  0, ""  }
180   },
181   *keytab;
182 /* *INDENT-ON* */
183 
184 typedef struct {
185   unsigned char prefix;
186   const char *msg;
187 } CTLKEY;
188 /* *INDENT-OFF* */
189 static struct curkey {
190     CTLKEY curkeymsg[3];
191     int  curkeyrow;
192     int  curkeycol;
193     const char *curkeysymbol;
194     const char *curkeyname;
195 } VT100_curkeytab [] = {
196 
197     /* A Reset,   A Set,     VT52  */
198 
199     {{{CSI,"A"}, {SS3,"A"}, {ESC,"A"}}, 0, 56, "UP",  "Up arrow"   },
200     {{{CSI,"B"}, {SS3,"B"}, {ESC,"B"}}, 0, 61, "DN",  "Down arrow" },
201     {{{CSI,"D"}, {SS3,"D"}, {ESC,"D"}}, 0, 66, "LT",  "Left arrow" },
202     {{{CSI,"C"}, {SS3,"C"}, {ESC,"C"}}, 0, 71, "RT",  "Right arrow"},
203     {{{0,  ""},  {0,  ""},  {0,  "" }}, 0,  0, "",    "" }
204   },
205   LK401_curkeytab [] = {
206 
207     /* A Reset,   A Set,     VT52  */
208 
209     {{{CSI,"A"}, {SS3,"A"}, {ESC,"A"}}, 8, 32, "Up",    "Up arrow"   },
210     {{{CSI,"B"}, {SS3,"B"}, {ESC,"B"}}, 9, 31, "Down",  "Down arrow" },
211     {{{CSI,"D"}, {SS3,"D"}, {ESC,"D"}}, 9, 24, "Left",  "Left arrow" },
212     {{{CSI,"C"}, {SS3,"C"}, {ESC,"C"}}, 9, 38, "Right", "Right arrow"},
213     {{{0,  ""},  {0,  ""},  {0,  "" }}, 0,  0, "",      "" }
214   },
215   *curkeytab;
216 static struct fnckey {
217     CTLKEY fnkeymsg[2];
218     int  fnkeyrow;
219     int  fnkeycol;
220     const char *fnkeysymbol;
221     const char *fnkeyname;
222 } fnkeytab [] = {
223 
224     /* Normal,     VT100/VT52  */
225     {{{CSI,"11~"}, {0,""}},  0,  1, "F1",   "F1 (xterm)"   },
226     {{{CSI,"12~"}, {0,""}},  0,  4, "F2",   "F2 (xterm)"   },
227     {{{CSI,"13~"}, {0,""}},  0,  7, "F3",   "F3 (xterm)"   },
228     {{{CSI,"14~"}, {0,""}},  0, 10, "F4",   "F4 (xterm)"   },
229     {{{CSI,"15~"}, {0,""}},  0, 13, "F5",   "F5 (xterm)"   },
230 
231     {{{CSI,"17~"}, {0,""}},  0, 18, "F6",   "F6"   },
232     {{{CSI,"18~"}, {0,""}},  0, 21, "F7",   "F7"   },
233     {{{CSI,"19~"}, {0,""}},  0, 24, "F8",   "F8"   },
234     {{{CSI,"20~"}, {0,""}},  0, 27, "F9",   "F9"   },
235     {{{CSI,"21~"}, {0,""}},  0, 30, "F10",  "F10"   },
236     {{{CSI,"23~"}, {0,""}},  0, 36, "F11",  "F11"   },
237     {{{CSI,"24~"}, {0,""}},  0, 40, "F12",  "F12"   },
238     {{{CSI,"25~"}, {0,""}},  0, 44, "F13",  "F13"   },
239     {{{CSI,"26~"}, {0,""}},  0, 48, "F14",  "F14"   },
240     {{{CSI,"28~"}, {0,""}},  0, 54, "Help", "Help (F15)"   },
241     {{{CSI,"29~"}, {0,""}},  0, 59, "Do",   "Do (F16)"   },
242     {{{CSI,"31~"}, {0,""}},  0, 64, "F17",  "F17"   },
243     {{{CSI,"32~"}, {0,""}},  0, 68, "F18",  "F18"   },
244     {{{CSI,"33~"}, {0,""}},  0, 72, "F19",  "F19"   },
245     {{{CSI,"34~"}, {0,""}},  0, 76, "F20",  "F20"   },
246     {{{0,  ""},    {0,"" }}, 0,  0, "",     ""   }
247   },
248   edt_keypadtab[] = {
249     {{{CSI,"1~"}, {0,""}}, 6, 24, "Find" ,  "Find"  },
250     {{{CSI,"2~"}, {0,""}}, 6, 30, "Insert", "Insert Here"   },
251     {{{CSI,"3~"}, {0,""}}, 6, 37, "Remove", "Remove"   },
252     {{{CSI,"4~"}, {0,""}}, 7, 23, "Select", "Select"   },
253     {{{CSI,"5~"}, {0,""}}, 7, 31, "Prev",   "Prev"   },
254     {{{CSI,"6~"}, {0,""}}, 7, 38, "Next",   "Next"   },
255     {{{0,  ""},   {0,""}}, 0,  0, "",       ""   }
256   };
257 static struct fnkey {
258     CTLKEY fnkeymsg[4];
259     int  fnkeyrow;
260     int  fnkeycol;
261     const char *fnkeysymbol;
262     const char *fnkeyname;
263 } num_keypadtab [] = {
264 
265   /* ANSI-num, ANSI-app,  VT52-nu,   VT52-ap,     r,  c,  symb   name        */
266 
267   {{{SS3,"P"}, {SS3,"P"}, {ESC,"P"}, {ESC,"P" }}, 6, 59, "PF1", "PF1"        },
268   {{{SS3,"Q"}, {SS3,"Q"}, {ESC,"Q"}, {ESC,"Q" }}, 6, 63, "PF2", "PF2"        },
269   {{{SS3,"R"}, {SS3,"R"}, {ESC,"R"}, {ESC,"R" }}, 6, 67, "PF3", "PF3"        },
270   {{{SS3,"S"}, {SS3,"S"}, {ESC,"S"}, {ESC,"S" }}, 6, 71, "PF4", "PF4"        },
271   {{{0,  "7"}, {SS3,"w"}, {0,  "7"}, {ESC,"?w"}}, 7, 59, " 7 ", "Numeric 7"  },
272   {{{0,  "8"}, {SS3,"x"}, {0,  "8"}, {ESC,"?x"}}, 7, 63, " 8 ", "Numeric 8"  },
273   {{{0,  "9"}, {SS3,"y"}, {0,  "9"}, {ESC,"?y"}}, 7, 67, " 9 ", "Numeric 9"  },
274   {{{0,  "-"}, {SS3,"m"}, {0,  "-"}, {ESC,"?m"}}, 7, 71, " - ", "Minus"      },
275   {{{0,  "4"}, {SS3,"t"}, {0,  "4"}, {ESC,"?t"}}, 8, 59, " 4 ", "Numeric 4"  },
276   {{{0,  "5"}, {SS3,"u"}, {0,  "5"}, {ESC,"?u"}}, 8, 63, " 5 ", "Numeric 5"  },
277   {{{0,  "6"}, {SS3,"v"}, {0,  "6"}, {ESC,"?v"}}, 8, 67, " 6 ", "Numeric 6"  },
278   {{{0,  ","}, {SS3,"l"}, {0,  ","}, {ESC,"?l"}}, 8, 71, " , ", "Comma"      },
279   {{{0,  "1"}, {SS3,"q"}, {0,  "1"}, {ESC,"?q"}}, 9, 59, " 1 ", "Numeric 1"  },
280   {{{0,  "2"}, {SS3,"r"}, {0,  "2"}, {ESC,"?r"}}, 9, 63, " 2 ", "Numeric 2"  },
281   {{{0,  "3"}, {SS3,"s"}, {0,  "3"}, {ESC,"?s"}}, 9, 67, " 3 ", "Numeric 3"  },
282   {{{0,  "0"}, {SS3,"p"}, {0,  "0"}, {ESC,"?p"}},10, 59, "   0   ","Numeric 0"},
283   {{{0,  "."}, {SS3,"n"}, {0,  "."}, {ESC,"?n"}},10, 67, " . ", "Point"      },
284   {{{0,"\015"},{SS3,"M"}, {0,"\015"},{ESC,"?M"}},10, 71, "ENT", "ENTER"      },
285   {{{0,  ""},  {0,  ""},  {0,  ""},  {0,  ""}},   0,  0, "",    ""           }
286 };
287 /* *INDENT-ON* */
288 
289 struct natkey {
290   char natc;
291   int natrow;
292   int natcol;
293   const char *natsymbol;
294 };
295 
296 static int same_CTLKEY(const char *response, CTLKEY *code);
297 
298 static int
find_cursor_key(char * curkeystr,int ckeymode)299 find_cursor_key(char *curkeystr, int ckeymode)
300 {
301   int i;
302 
303   for (i = 0; curkeytab[i].curkeysymbol[0] != '\0'; i++) {
304     if (same_CTLKEY(curkeystr, &curkeytab[i].curkeymsg[ckeymode])) {
305       return i;
306     }
307   }
308   return -1;
309 }
310 
311 static int
find_editing_key(char * keypadstr,int fkeymode)312 find_editing_key(char *keypadstr, int fkeymode)
313 {
314   int i;
315 
316   for (i = 0; edt_keypadtab[i].fnkeysymbol[0] != '\0'; i++) {
317     if (same_CTLKEY(keypadstr, &edt_keypadtab[i].fnkeymsg[fkeymode])) {
318       return i;
319     }
320   }
321   return -1;
322 }
323 
324 static int
find_function_key(char * keypadstr,int fkeymode)325 find_function_key(char *keypadstr, int fkeymode)
326 {
327   int i;
328 
329   for (i = 0; fnkeytab[i].fnkeysymbol[0] != '\0'; i++) {
330     if (same_CTLKEY(keypadstr, &fnkeytab[i].fnkeymsg[fkeymode])) {
331       return i;
332     }
333   }
334   return -1;
335 }
336 
337 static int
find_num_keypad_key(char * keypadstr,int fkeymode)338 find_num_keypad_key(char *keypadstr, int fkeymode)
339 {
340   int i;
341 
342   for (i = 0; num_keypadtab[i].fnkeysymbol[0] != '\0'; i++) {
343     if (same_CTLKEY(keypadstr, &num_keypadtab[i].fnkeymsg[fkeymode])) {
344       return i;
345     }
346   }
347   return -1;
348 }
349 
350 static void
set_keyboard_layout(struct natkey * table)351 set_keyboard_layout(struct natkey *table)
352 {
353   int i, j;
354 
355   for (j = 0; table[j].natc != '\0'; j++) {
356     for (i = 0; keytab[i].c != '\0'; i++) {
357       if (keytab[i].row == table[j].natrow &&
358           keytab[i].col == table[j].natcol) {
359         keytab[i].c = table[j].natc;
360         keytab[i].symbol = table[j].natsymbol;
361         break;
362       }
363     }
364   }
365 }
366 
367 static int
default_layout(MENU_ARGS)368 default_layout(MENU_ARGS)
369 {
370   /* FIXME: nothing resets the default keytab to original state */
371   return MENU_NOHOLD;
372 }
373 
374 static int
same_CTLKEY(const char * response,CTLKEY * code)375 same_CTLKEY(const char *response, CTLKEY *code)
376 {
377   switch (code->prefix) {
378   case CSI:
379     if ((response = skip_csi_2(response)) == 0)
380       return FALSE;
381     break;
382   case SS3:
383     if ((response = skip_ss3_2(response)) == 0)
384       return FALSE;
385     break;
386   case ESC:
387     if (*response++ != ESC)
388       return FALSE;
389     /* FALLTHRU */
390   default:
391     break;
392   }
393   return !strcmp(response, code->msg);
394 }
395 
396 static int
set_D47_layout(MENU_ARGS)397 set_D47_layout(MENU_ARGS)
398 {
399   /* *INDENT-OFF* */
400   static struct natkey table[] =
401   {
402     { '"', 1, 12, "\""},
403     { '&', 1, 32, "&" },
404     { '/', 1, 37, "/" },
405     { '(', 1, 42, "(" },
406     { ')', 1, 47, ")" },
407     { '=', 1, 52, "=" },
408     { '+', 1, 56, "+" },
409     { '?', 1, 57, "?" },
410     { '`', 1, 61, "`" },
411     { '@', 1, 62, "@" },
412     { '<', 1, 66, "<" },
413     { '>', 1, 67, ">" },
414     { '}', 2, 58, "}" },
415     { ']', 2, 59, "]" },
416     { '^', 2, 63, "^" },
417     { '~', 2, 64, "~" },
418     { '|', 3, 55, "|" },
419     {'\\', 3, 56,"\\" },
420     { '{', 3, 60, "{" },
421     { '[', 3, 61, "[" },
422     {'\'', 3, 71, "'" },
423     { '*', 3, 72, "*" },
424     { ',', 4, 47, "," },
425     { ';', 4, 48, ";" },
426     { '.', 4, 52, "." },
427     { ':', 4, 53, ":" },
428     { '-', 4, 57, "-" },
429     { '_', 4, 58, "_" },
430     {'\0', 0,  0, ""  }
431   };
432   /* *INDENT-ON* */
433 
434   set_keyboard_layout(table);
435   return MENU_NOHOLD;
436 }
437 
438 static int
set_E47_layout(MENU_ARGS)439 set_E47_layout(MENU_ARGS)
440 {
441   /* *INDENT-OFF* */
442   static struct natkey table[] =
443   {
444     { '"', 1, 12, "\""},
445     { '&', 1, 32, "&" },
446     { '/', 1, 37, "/" },
447     { '(', 1, 42, "(" },
448     { ')', 1, 47, ")" },
449     { '=', 1, 52, "=" },
450     { '+', 1, 56, "+" },
451     { '?', 1, 57, "?" },
452     { '`', 1, 61, "`" },
453     { '@', 1, 62, "@" },
454     { '<', 1, 66, "<" },
455     { '>', 1, 67, ">" },
456     { '}', 2, 58, "}" },
457     { ']', 2, 59, "]" },
458     { '~', 2, 63, "~" },
459     { '^', 2, 64, "^" },
460     { '|', 3, 55, "|" },
461     {'\\', 3, 56,"\\" },
462     { '{', 3, 60, "{" },
463     { '[', 3, 61, "[" },
464     {'\'', 3, 71, "'" },
465     { '*', 3, 72, "*" },
466     { ',', 4, 47, "," },
467     { ';', 4, 48, ";" },
468     { '.', 4, 52, "." },
469     { ':', 4, 53, ":" },
470     { '-', 4, 57, "-" },
471     { '_', 4, 58, "_" },
472     {'\0', 0,  0, ""  }
473   };
474   /* *INDENT-ON* */
475 
476   set_keyboard_layout(table);
477   return MENU_NOHOLD;
478 }
479 
480 static void
show_character(int i,char * scs_params,int hilite)481 show_character(int i, char *scs_params, int hilite)
482 {
483   int special = ((scs_params != 0) && (strlen(keytab[i].symbol) == 1));
484 
485   vt_move(1 + 2 * keytab[i].row, 1 + keytab[i].col);
486   if (hilite)
487     vt_hilite(TRUE);
488   if (special)
489     esc(scs_params);
490   printf("%s", keytab[i].symbol);
491   if (special)
492     scs(0, 'B');
493   if (hilite)
494     vt_hilite(FALSE);
495 }
496 
497 static void
show_cursor_keys(int flag)498 show_cursor_keys(int flag)
499 {
500   int i;
501 
502   curkeytab = (terminal_id() < 200) ? VT100_curkeytab : LK401_curkeytab;
503 
504   for (i = 0; curkeytab[i].curkeysymbol[0] != '\0'; i++) {
505     vt_move(1 + 2 * curkeytab[i].curkeyrow, 1 + curkeytab[i].curkeycol);
506     if (flag)
507       vt_hilite(TRUE);
508     printf("%s", curkeytab[i].curkeysymbol);
509     if (flag)
510       vt_hilite(FALSE);
511   }
512 }
513 
514 static void
show_editing_keypad(int flag)515 show_editing_keypad(int flag)
516 {
517   if (terminal_id() >= 200) {
518     int i;
519 
520     for (i = 0; edt_keypadtab[i].fnkeysymbol[0] != '\0'; i++) {
521       vt_move(1 + 2 * edt_keypadtab[i].fnkeyrow, 1 + edt_keypadtab[i].fnkeycol);
522       if (flag)
523         vt_hilite(TRUE);
524       printf("%s", edt_keypadtab[i].fnkeysymbol);
525       if (flag)
526         vt_hilite(FALSE);
527     }
528   }
529 }
530 
531 static void
show_function_keys(int flag)532 show_function_keys(int flag)
533 {
534   if (terminal_id() >= 200) {
535     int i;
536 
537     for (i = 0; fnkeytab[i].fnkeysymbol[0] != '\0'; i++) {
538       vt_move(1 + 2 * fnkeytab[i].fnkeyrow, 1 + fnkeytab[i].fnkeycol);
539       if (flag)
540         vt_hilite(TRUE);
541       printf("%s", fnkeytab[i].fnkeysymbol);
542       if (flag)
543         vt_hilite(FALSE);
544     }
545   }
546 }
547 
548 static void
show_keyboard(int flag GCC_UNUSED,char * scs_params)549 show_keyboard(int flag GCC_UNUSED, char *scs_params)
550 {
551   int i;
552 
553   if (terminal_id() >= 200)   /* LK201 _looks_ the same as LK401 (to me) */
554     keytab = LK401_keytab;
555   else
556     keytab = VT100_keytab;
557 
558   for (i = 0; keytab[i].c != '\0'; i++) {
559     show_character(i, scs_params, TRUE);
560   }
561 }
562 
563 static void
show_numeric_keypad(int flag)564 show_numeric_keypad(int flag)
565 {
566   int i;
567 
568   for (i = 0; num_keypadtab[i].fnkeysymbol[0] != '\0'; i++) {
569     vt_move(1 + 2 * num_keypadtab[i].fnkeyrow, 1 + num_keypadtab[i].fnkeycol);
570     if (flag)
571       vt_hilite(TRUE);
572     printf("%s", num_keypadtab[i].fnkeysymbol);
573     if (flag)
574       vt_hilite(FALSE);
575   }
576 }
577 
578 /******************************************************************************/
579 
580 static int
tst_AnswerBack(MENU_ARGS)581 tst_AnswerBack(MENU_ARGS)
582 {
583   char *abmstr;
584 
585   set_tty_crmod(TRUE);
586   vt_clear(2);
587   vt_move(5, 1);
588   println("Finally, a check of the ANSWERBACK MESSAGE, which can be sent");
589   println("by pressing CTRL-BREAK. The answerback message can be loaded");
590   println("in SET-UP B by pressing SHIFT-A and typing e.g.");
591   println("");
592   println("         \" H e l l o , w o r l d Return \"");
593   println("");
594   println("(the double-quote characters included).  Do that, and then try");
595   println("to send an answerback message with CTRL-BREAK.  If it works,");
596   println("the answerback message should be displayed in reverse mode.");
597   println("Finish with a single RETURN.");
598 
599   set_tty_crmod(FALSE);
600 
601   do {
602     int row, col;
603 
604     vt_move(row = 17, col = 1);
605     inflush();
606     abmstr = get_reply();
607     vt_move(row, col);
608     vt_el(0);
609     chrprint2(abmstr, row, col);
610   } while (strcmp(abmstr, "\r"));
611 
612   restore_ttymodes();
613   return MENU_NOHOLD;
614 }
615 
616 static int
tst_AutoRepeat(MENU_ARGS)617 tst_AutoRepeat(MENU_ARGS)
618 {
619   char arptstring[BUFSIZ];
620 
621   vt_clear(2);
622   vt_move(10, 1);
623   println("Test of the AUTO REPEAT feature");
624 
625   println("");
626   println("Hold down an alphanumeric key for a while, then push RETURN.");
627   printf("%s", "Auto Repeat OFF: ");
628   decarm(FALSE);  /* DECARM */
629   inputline(arptstring);
630   if (LOG_ENABLED)
631     fprintf(log_fp, "Input: %s\n", arptstring);
632   if (strlen(arptstring) == 0)
633     println("No characters read!??");
634   else if (strlen(arptstring) == 1)
635     println("OK.");
636   else
637     println("Too many characters read.");
638   println("");
639 
640   println("Hold down an alphanumeric key for a while, then push RETURN.");
641   printf("%s", "Auto Repeat ON: ");
642   decarm(TRUE);
643   inputline(arptstring);
644   if (LOG_ENABLED)
645     fprintf(log_fp, "Input: %s\n", arptstring);
646   if (strlen(arptstring) == 0)
647     println("No characters read!??");
648   else if (strlen(arptstring) == 1)
649     println("Not enough characters read.");
650   else
651     println("OK.");
652   println("");
653 
654   return MENU_HOLD;
655 }
656 
657 static int
tst_ControlKeys(MENU_ARGS)658 tst_ControlKeys(MENU_ARGS)
659 {
660   int i, okflag;
661   int kbdc;
662   char temp[80];
663   char *kbds = strcpy(temp, " ");
664   /* *INDENT-OFF* */
665   static struct {
666       int  ccount;
667       const char *csymbol;
668   } ckeytab [] = {
669       { 0, "NUL (CTRL-@ or CTRL-Space)" },
670       { 0, "SOH (CTRL-A)" },
671       { 0, "STX (CTRL-B)" },
672       { 0, "ETX (CTRL-C)" },
673       { 0, "EOT (CTRL-D)" },
674       { 0, "ENQ (CTRL-E)" },
675       { 0, "ACK (CTRL-F)" },
676       { 0, "BEL (CTRL-G)" },
677       { 0, "BS  (CTRL-H) (BACK SPACE)" },
678       { 0, "HT  (CTRL-I) (TAB)" },
679       { 0, "LF  (CTRL-J) (LINE FEED)" },
680       { 0, "VT  (CTRL-K)" },
681       { 0, "FF  (CTRL-L)" },
682       { 0, "CR  (CTRL-M) (RETURN)" },
683       { 0, "SO  (CTRL-N)" },
684       { 0, "SI  (CTRL-O)" },
685       { 0, "DLE (CTRL-P)" },
686       { 0, "DC1 (CTRL-Q) (X-On)" },
687       { 0, "DC2 (CTRL-R)" },
688       { 0, "DC3 (CTRL-S) (X-Off)" },
689       { 0, "DC4 (CTRL-T)" },
690       { 0, "NAK (CTRL-U)" },
691       { 0, "SYN (CTRL-V)" },
692       { 0, "ETB (CTRL-W)" },
693       { 0, "CAN (CTRL-X)" },
694       { 0, "EM  (CTRL-Y)" },
695       { 0, "SUB (CTRL-Z)" },
696       { 0, "ESC (CTRL-[) (ESCAPE)" },
697       { 0, "FS  (CTRL-\\ or CTRL-? or CTRL-_)" },
698       { 0, "GS  (CTRL-])" },
699       { 0, "RS  (CTRL-^ or CTRL-~ or CTRL-`)" },
700       { 0, "US  (CTRL-_ or CTRL-?)" }
701   };
702   /* *INDENT-ON* */
703 
704   vt_clear(2);
705   for (i = 0; i < 32; i++) {
706     vt_move(1 + (i % 16), 1 + 40 * (i / 16));
707     vt_hilite(TRUE);
708     printf("%s", ckeytab[i].csymbol);
709     vt_hilite(FALSE);
710   }
711   vt_move(19, 1);
712   set_tty_crmod(TRUE);
713   println(
714            "Push each CTRL-key TWICE. Note that you should be able to send *all*");
715   println(
716            "CTRL-codes twice, including CTRL-S (X-Off) and CTRL-Q (X-Off)!");
717   println(
718            "Finish with DEL (also called DELETE or RUB OUT), or wait 1 minute.");
719   set_tty_raw(TRUE);
720   do {
721     int row, col;
722 
723     vt_move(row = max_lines - 1, col = 1);
724     kbdc = inchar();
725     vt_move(row, col);
726     vt_el(0);
727     if (kbdc < 32) {
728       printf("  %s", ckeytab[kbdc].csymbol);
729       if (LOG_ENABLED)
730         fprintf(log_fp, "Key: %s\n", ckeytab[kbdc].csymbol);
731     } else {
732       sprintf(kbds, "%c", kbdc);
733       chrprint2(kbds, row, col);
734       printf("%s", " -- not a CTRL key");
735     }
736     if (kbdc < 32)
737       ckeytab[kbdc].ccount++;
738     if (ckeytab[kbdc].ccount == 2) {
739       vt_move(1 + (kbdc % 16), 1 + 40 * (kbdc / 16));
740       printf("%s", ckeytab[kbdc].csymbol);
741     }
742   } while (kbdc != '\177');
743 
744   restore_ttymodes();
745   vt_move(max_lines, 1);
746   okflag = 1;
747   for (i = 0; i < 32; i++)
748     if (ckeytab[i].ccount < 2)
749       okflag = 0;
750   if (okflag)
751     printf("%s", "OK. ");
752   else
753     printf("%s", "You have not been able to send all CTRL keys! ");
754   return MENU_HOLD;
755 }
756 
757 static int
tst_CursorKeys(MENU_ARGS)758 tst_CursorKeys(MENU_ARGS)
759 {
760   int i;
761   int ckeymode;
762   int row, col;
763   char *curkeystr;
764   VTLEVEL save;
765 
766   static const char *curkeymodes[3] =
767   {
768     "ANSI / Cursor key mode RESET",
769     "ANSI / Cursor key mode SET",
770     "VT52 Mode"
771   };
772 
773   vt_clear(2);
774   save_level(&save);
775   show_keyboard(0, (char *) 0);
776   show_function_keys(0);
777   show_editing_keypad(0);
778   show_numeric_keypad(0);
779   vt_move(max_lines - 2, 1);
780 
781   set_tty_crmod(FALSE);
782   set_tty_echo(FALSE);
783 
784   for (ckeymode = 0; ckeymode <= 2; ckeymode++) {
785     decckm(ckeymode);   /* DECCKM */
786 
787     show_cursor_keys(1);
788     vt_move(21, 1);
789     printf("<%s>%20s", curkeymodes[ckeymode], "");
790     vt_move(max_lines - 2, 1);
791     vt_el(0);
792     vt_move(max_lines - 2, 1);
793     printf("%s", "Press each cursor key. Finish with TAB.");
794     for (;;) {
795       vt_move(max_lines - 1, 1);
796       if (ckeymode == 2)
797         set_level(0);   /* VT52 mode */
798       curkeystr = instr();
799       set_level(1);   /* ANSI mode */
800 
801       vt_move(row = max_lines - 1, col = 1);
802       vt_el(0);
803       vt_move(row, col);
804       chrprint2(curkeystr, row, col);
805 
806       if (!strcmp(curkeystr, "\t"))
807         break;
808       if ((i = find_cursor_key(curkeystr, ckeymode)) >= 0) {
809         vt_hilite(TRUE);
810         show_result(" (%s key) ", curkeytab[i].curkeyname);
811         vt_hilite(FALSE);
812         vt_move(1 + 2 * curkeytab[i].curkeyrow, 1 + curkeytab[i].curkeycol);
813         printf("%s", curkeytab[i].curkeysymbol);
814       } else {
815         vt_hilite(TRUE);
816         show_result("%s", " (Unknown cursor key) ");
817         vt_hilite(FALSE);
818       }
819     }
820   }
821 
822   decckm(FALSE);
823   restore_level(&save);
824   vt_move(max_lines - 1, 1);
825   vt_el(0);
826   restore_ttymodes();
827   return MENU_MERGE;
828 }
829 
830 static int
tst_EditingKeypad(MENU_ARGS)831 tst_EditingKeypad(MENU_ARGS)
832 {
833   int i;
834   int fkeymode;
835   int row, col;
836   char *fnkeystr;
837   VTLEVEL save;
838 
839   static const char *fnkeymodes[] =
840   {
841     "Normal mode",
842     "VT100/VT52 mode (none should be recognized)"
843   };
844 
845   save_level(&save);
846   show_keyboard(0, (char *) 0);
847   show_cursor_keys(0);
848   show_function_keys(0);
849   show_numeric_keypad(0);
850   vt_move(max_lines - 2, 1);
851 
852   if (terminal_id() < 200) {
853     printf("Sorry, a real VT%d terminal doesn't have an editing keypad\n",
854            terminal_id());
855     return MENU_HOLD;
856   }
857 
858   set_tty_crmod(FALSE);
859   set_tty_echo(FALSE);
860 
861   for (fkeymode = 0; fkeymode <= 1; fkeymode++) {
862     show_editing_keypad(1);
863     vt_move(21, 1);
864     printf("<%s>%20s", fnkeymodes[fkeymode], "");
865     vt_move(max_lines - 2, 1);
866     vt_el(0);
867     vt_move(max_lines - 2, 1);
868     printf("%s", "Press each function key. Finish with TAB.");
869 
870     for (;;) {
871       vt_move(max_lines - 1, 1);
872       if (fkeymode == 0)
873         default_level();
874       if (fkeymode != 0)
875         set_level(1);   /* VT100 mode */
876 
877       fnkeystr = instr();
878 
879       vt_move(row = max_lines - 1, col = 1);
880       vt_el(0);
881       vt_move(row, col);
882       chrprint2(fnkeystr, row, col);
883 
884       if (!strcmp(fnkeystr, "\t"))
885         break;
886       if ((i = find_editing_key(fnkeystr, fkeymode)) >= 0) {
887         vt_hilite(TRUE);
888         show_result(" (%s key) ", edt_keypadtab[i].fnkeyname);
889         vt_hilite(FALSE);
890         vt_move(1 + 2 * edt_keypadtab[i].fnkeyrow, 1 + edt_keypadtab[i].fnkeycol);
891         printf("%s", edt_keypadtab[i].fnkeysymbol);
892       } else {
893         vt_hilite(TRUE);
894         show_result("%s", " (Unknown function key) ");
895         vt_hilite(FALSE);
896       }
897     }
898   }
899 
900   vt_move(max_lines - 1, 1);
901   vt_el(0);
902   restore_level(&save);
903   restore_ttymodes();
904   return MENU_MERGE;
905 }
906 
907 static int
tst_FunctionKeys(MENU_ARGS)908 tst_FunctionKeys(MENU_ARGS)
909 {
910   int i;
911   int fkeymode;
912   int row, col;
913   char *fnkeystr;
914   VTLEVEL save;
915 
916   static const char *fnkeymodes[] =
917   {
918     "Normal mode (F6-F20, except xterm also F1-F5)",
919     "VT100/VT52 mode (F11-F13 only)"
920   };
921 
922   save_level(&save);
923   show_keyboard(0, (char *) 0);
924   show_cursor_keys(0);
925   show_editing_keypad(0);
926   show_numeric_keypad(0);
927   vt_move(max_lines - 2, 1);
928 
929   if (terminal_id() < 200) {
930     printf("Sorry, a real VT%d terminal doesn't have function keys\n",
931            terminal_id());
932     return MENU_HOLD;
933   }
934 
935   set_tty_crmod(FALSE);
936   set_tty_echo(FALSE);
937 
938   for (fkeymode = 0; fkeymode <= 1; fkeymode++) {
939     show_function_keys(1);
940     vt_move(21, 1);
941     printf("<%s>%20s", fnkeymodes[fkeymode], "");
942     vt_move(max_lines - 2, 1);
943     vt_el(0);
944     vt_move(max_lines - 2, 1);
945     printf("%s", "Press each function key. Finish with TAB.");
946 
947     for (;;) {
948       vt_move(max_lines - 1, 1);
949       if (fkeymode == 0)
950         default_level();
951       if (fkeymode != 0)
952         set_level(1);   /* VT100 mode */
953 
954       fnkeystr = instr();
955 
956       vt_move(row = max_lines - 1, col = 1);
957       vt_el(0);
958       vt_move(row, col);
959       chrprint2(fnkeystr, row, col);
960 
961       if (!strcmp(fnkeystr, "\t"))
962         break;
963       if ((i = find_function_key(fnkeystr, fkeymode)) >= 0) {
964         vt_hilite(TRUE);
965         show_result(" (%s key) ", fnkeytab[i].fnkeyname);
966         vt_hilite(FALSE);
967         vt_move(1 + 2 * fnkeytab[i].fnkeyrow, 1 + fnkeytab[i].fnkeycol);
968         printf("%s", fnkeytab[i].fnkeysymbol);
969       } else {
970         vt_hilite(TRUE);
971         show_result("%s", " (Unknown function key) ");
972         vt_hilite(FALSE);
973       }
974     }
975   }
976 
977   vt_move(max_lines - 1, 1);
978   vt_el(0);
979   restore_level(&save);
980   restore_ttymodes();
981   return MENU_MERGE;
982 }
983 
984 static int
tst_NumericKeypad(MENU_ARGS)985 tst_NumericKeypad(MENU_ARGS)
986 {
987   int i;
988   int fkeymode;
989   int row, col;
990   char *fnkeystr;
991   VTLEVEL save;
992 
993   static const char *fnkeymodes[4] =
994   {
995     "ANSI Numeric mode",
996     "ANSI Application mode",
997     "VT52 Numeric mode",
998     "VT52 Application mode"
999   };
1000 
1001   vt_clear(2);
1002   save_level(&save);
1003   show_keyboard(0, (char *) 0);
1004   show_cursor_keys(0);
1005   show_function_keys(0);
1006   show_editing_keypad(0);
1007   vt_move(max_lines - 2, 1);
1008 
1009   set_tty_crmod(FALSE);
1010   set_tty_echo(FALSE);
1011 
1012   for (fkeymode = 0; fkeymode <= 3; fkeymode++) {
1013     show_numeric_keypad(1);
1014     vt_move(21, 1);
1015     printf("<%s>%20s", fnkeymodes[fkeymode], "");
1016     vt_move(max_lines - 2, 1);
1017     vt_el(0);
1018     vt_move(max_lines - 2, 1);
1019     printf("%s", "Press each function key. Finish with TAB.");
1020 
1021     for (;;) {
1022       vt_move(max_lines - 1, 1);
1023       if (fkeymode >= 2)
1024         set_level(0);   /* VT52 mode */
1025       if (fkeymode % 2)
1026         deckpam();  /* Application mode */
1027       else
1028         deckpnm();  /* Numeric mode     */
1029       fnkeystr = instr();
1030       set_level(1);   /* ANSI mode */
1031 
1032       vt_move(row = max_lines - 1, col = 1);
1033       vt_el(0);
1034       vt_move(row, col);
1035       chrprint2(fnkeystr, row, col);
1036 
1037       if (!strcmp(fnkeystr, "\t"))
1038         break;
1039       if ((i = find_num_keypad_key(fnkeystr, fkeymode)) >= 0) {
1040         vt_hilite(TRUE);
1041         show_result(" (%s key) ", num_keypadtab[i].fnkeyname);
1042         vt_hilite(FALSE);
1043         vt_move(1 + 2 * num_keypadtab[i].fnkeyrow, 1 + num_keypadtab[i].fnkeycol);
1044         printf("%s", num_keypadtab[i].fnkeysymbol);
1045       } else {
1046         vt_hilite(TRUE);
1047         show_result("%s", " (Unknown function key) ");
1048         vt_hilite(FALSE);
1049       }
1050     }
1051   }
1052 
1053   deckpnm();
1054   vt_move(max_lines - 1, 1);
1055   vt_el(0);
1056   restore_level(&save);
1057   restore_ttymodes();
1058   return MENU_MERGE;
1059 }
1060 
1061 static int
tst_KeyboardLayout(MENU_ARGS)1062 tst_KeyboardLayout(MENU_ARGS)
1063 {
1064   /* *INDENT-OFF* */
1065   static MENU keyboardmenu[] = {
1066       { "Standard American ASCII layout",                    default_layout },
1067       { "Swedish national layout D47",                       set_D47_layout },
1068       { "Swedish national layout E47",                       set_E47_layout },
1069         /* add new keyboard layouts here */
1070       { "",                                                  0 }
1071     };
1072   /* *INDENT-ON* */
1073 
1074   if (terminal_id() < 200) {
1075     vt_clear(2);
1076     keytab = VT100_keytab;
1077     title(0);
1078     println("Choose keyboard layout:");
1079     (void) menu(keyboardmenu);
1080   }
1081 
1082   tst_keyboard_layout((char *) 0);
1083 
1084   return MENU_MERGE;
1085 }
1086 
1087 static int
tst_LED_Lights(MENU_ARGS)1088 tst_LED_Lights(MENU_ARGS)
1089 {
1090   int i;
1091   const char *ledmsg[6], *ledseq[6];
1092   /* *INDENT-OFF* */
1093   ledmsg[0] = "L1 L2 L3 L4"; ledseq[0] = "1;2;3;4";
1094   ledmsg[1] = "   L2 L3 L4"; ledseq[1] = "1;0;4;3;2";
1095   ledmsg[2] = "   L2 L3";    ledseq[2] = "1;4;;2;3";
1096   ledmsg[3] = "L1 L2";       ledseq[3] = ";;2;1";
1097   ledmsg[4] = "L1";          ledseq[4] = "1";
1098   ledmsg[5] = "";            ledseq[5] = "";
1099   /* *INDENT-ON* */
1100 
1101 #ifdef UNIX
1102   fflush(stdout);
1103 #endif
1104   vt_clear(2);
1105   vt_move(10, 1);
1106   println("These LEDs (\"lamps\") on the keyboard should be on:");
1107   for (i = 0; i <= 5; i++) {
1108     vt_move(10, 52);
1109     vt_el(0);
1110     printf("%s", ledmsg[i]);
1111     decll("0");
1112     decll(ledseq[i]);
1113     vt_move(12, 1);
1114     holdit();
1115   }
1116   decll("0");
1117   return MENU_NOHOLD;
1118 }
1119 
1120 /******************************************************************************/
1121 int
tst_keyboard_layout(char * scs_params)1122 tst_keyboard_layout(char *scs_params)
1123 {
1124   int i;
1125   int kbdc;
1126   char temp[80];
1127   char *kbds = strcpy(temp, " ");
1128 
1129   vt_clear(2);
1130   show_keyboard(1, scs_params);
1131   show_cursor_keys(0);
1132   show_function_keys(0);
1133   show_editing_keypad(0);
1134   show_numeric_keypad(0);
1135   vt_move(max_lines - 2, 1);
1136 
1137   set_tty_crmod(FALSE);
1138   set_tty_echo(FALSE);
1139 
1140   inflush();
1141   printf("Press each key, both shifted and unshifted. Finish with RETURN:");
1142 
1143   do {          /* while (kbdc != 13) */
1144     int row, col;
1145     vt_move(row = max_lines - 1, col = 1);
1146     kbdc = inchar();
1147     vt_move(row, col);
1148     vt_el(0);
1149     if (scs_params != 0 && kbdc > ' ' && kbdc < '\177') {
1150       vt_hilite(TRUE);
1151       esc(scs_params);
1152       printf(" %c ", kbdc);
1153       scs(0, 'B');
1154       printf("= %d ", kbdc);
1155       scs(0, 'B');
1156       vt_hilite(FALSE);
1157     } else {
1158       sprintf(kbds, "%c", kbdc);
1159       chrprint2(kbds, row, col);
1160     }
1161     for (i = 0; keytab[i].c != '\0'; i++) {
1162       if (keytab[i].c == kbdc) {
1163         show_character(i, scs_params, FALSE);
1164         /* LK401 keyboard will have more than one hit for '<' and '>' */
1165       }
1166     }
1167   } while (kbdc != 13);
1168 
1169   vt_move(max_lines - 1, 1);
1170   vt_el(0);
1171   restore_ttymodes();
1172   return MENU_MERGE;
1173 }
1174 
1175 /******************************************************************************/
1176 int
tst_keyboard(MENU_ARGS)1177 tst_keyboard(MENU_ARGS)
1178 {
1179   /* *INDENT-OFF* */
1180   static MENU my_menu[] = {
1181       { "Exit",                                              0 },
1182       { "LED Lights",                                        tst_LED_Lights },
1183       { "Auto Repeat",                                       tst_AutoRepeat },
1184       { "KeyBoard Layout",                                   tst_KeyboardLayout },
1185       { "Cursor Keys",                                       tst_CursorKeys },
1186       { "Numeric Keypad",                                    tst_NumericKeypad },
1187       { "Editing Keypad",                                    tst_EditingKeypad },
1188       { "Function Keys",                                     tst_FunctionKeys },
1189       { "AnswerBack",                                        tst_AnswerBack },
1190       { "Control Keys",                                      tst_ControlKeys },
1191       { "", 0 }
1192     };
1193   /* *INDENT-ON* */
1194 
1195   do {
1196     vt_clear(2);
1197     __(title(0), printf("Keyboard Tests"));
1198     __(title(2), println("Choose test type:"));
1199   } while (menu(my_menu));
1200   return MENU_NOHOLD;
1201 }
1202