1 /*==============================================================
2 //	A program to exercise and test the console input
3 //	routines and keyboard translation of yaze-ag
4 //	Copyright (c) by Jon Saxton (Australia) 2015
5 //============================================================*/
6 
7 #include "chan.h"
8 #include "ytypes.h"
9 #include "ktt.h"
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <memory.h>
15 #include <unistd.h>
16 #include <termios.h>
17 #include <sys/time.h>
18 
19 #define INTERKEY_TIMEOUT 50000
20 #define ISATTY 1
21 #define ISRAW  2
22 
23 /*---------------------------------------------------------
24 //  Some things copied from ybios.c and monitor.c to
25 //  set the console input mode.
26 //-------------------------------------------------------*/
27 
28 struct sio
29 {
30     FILE *fp;
31     char *filename;
32     char *streamname;
33     char tty;
34     const char strtype;
35 } s;
36 
37 struct termios
38     rawtio,
39     cookedtio;
40 int
41     ttyflags,
42     interrupt = 0;
43 
44 int
45     ttyflags = ISATTY;
46 
ttyraw()47 void ttyraw()
48 {
49     if ((ttyflags & (ISATTY|ISRAW)) == ISATTY)
50     {
51 	tcsetattr(fileno(stdin), TCSAFLUSH, &rawtio);
52 	ttyflags |= ISRAW;
53     }
54 }
55 
ttycook()56 void ttycook()
57 {
58     if (ttyflags & ISRAW)
59     {
60 	tcsetattr(fileno(stdin), TCSAFLUSH, &cookedtio);
61 	putc('\n', stdout);
62 	ttyflags &= ~ISRAW;
63     }
64 }
65 
serin(int chan)66 int serin(int chan)
67 {
68     char c;
69     int ch;
70 
71     if (s.fp == NULL)
72 	return 0x1A;
73     if (s.tty)
74     {	if (read(fileno(s.fp), &c, 1) == 0)
75 	    return 0x1A;
76 	else
77 	    return c;
78     }
79     if ((ch = getc(s.fp)) == EOF)
80 	return 0x1A;
81     else
82 	return ch & 0xFF;
83 }
84 
85 void *
xmalloc(size_t size)86 xmalloc(size_t size)
87 {
88     void *p = malloc(size);
89 
90     if (p == NULL)
91     {
92 	fputs("insufficient memory\n", stderr);
93 	exit(1);
94     }
95     return p;
96 }
97 
98 /* stash a string away on the heap */
99 char *
newstr(const char * str)100 newstr(const char *str)
101 {
102 	char *p = xmalloc(strlen(str) + 1);
103 	(void) strcpy(p, str);
104 	return p;
105 }
106 
107 /*-------------------------------------------------------
108 //			init_term()
109 //
110 //  init_term() puts the console (keyboard) into raw
111 //  mode.
112 //-----------------------------------------------------*/
113 
init_term()114 void init_term()
115 {
116     char *name = ttyname(fileno(stdin));
117 
118     s.fp = stdin;
119     s.filename = name ? newstr(name) : "(stdin)";
120     s.tty = isatty(fileno(stdin));
121     if (s.tty)
122     {
123 	ttyflags = ISATTY;
124 	if (tcgetattr(fileno(stdin), &cookedtio) != 0)
125 	{
126 	    perror("tcgetattr");
127 	    exit(1);
128 	}
129 	rawtio = cookedtio;
130 	rawtio.c_iflag = 0;
131 	rawtio.c_oflag = 0;
132 	rawtio.c_lflag = interrupt ? ISIG : 0;
133 	memset(rawtio.c_cc, 0, NCCS);
134 	rawtio.c_cc[VINTR] = interrupt;
135 	rawtio.c_cc[VMIN] = 1;
136     }
137     atexit(ttycook);
138     ttyraw();
139     puts("Press keys.  <esc> <esc> <esc> to end\r");
140 }
141 
142 /*--------------------------------------------------------
143 //			contest()
144 //
145 //  Returns TRUE if a character is available from the
146 //  keyboard within 50 ms.  Used after an ESC character
147 //  is seen to decide whether the ESC is an isolated
148 //  character or part of a multi-byte sequence.
149 //------------------------------------------------------*/
150 
contest()151 int contest()
152 {
153     static struct timeval
154         t = { 0, INTERKEY_TIMEOUT };
155     fd_set
156         rdy;
157     int
158         fd = STDIN_FILENO;
159 
160     FD_ZERO(&rdy);
161     FD_SET(fd, &rdy);
162     (void) select(fd+1, &rdy, NULL, NULL, &t);
163     return FD_ISSET(fd, &rdy);
164 }
165 
166 /*--------------------------------------------------------
167 //			usage
168 //------------------------------------------------------*/
169 
170 char banner1[] =
171     "\nThis program is for testing keyboard input and translation.\n\n"
172     "The first parameter determines the mode of operation:-\n\n"
173     "   -\tdisplays characters as they are entered via the keyboard.  This\n"
174     "\tis useful for seeing exactly what sequence of characters any key\n"
175     "\tgenerates.\n",
176     banner2[] =
177     "   +\tshows what comes back from the translation module.  Use this mode\n"
178     "\tto test translation tables.\n\n"
179     "  fn\t(where fn is a file name) is like + except that fn.ktt is loaded\n"
180     "\tinstead of yaze.ktt\n\n"
181     "In translated mode, pressing ESC twice toggles a diagnostic feature in the\n"
182     "translation module which prints the keycode that it sees.\n";
183 
usage()184 void usage()
185 {
186     puts(banner1);
187     puts(banner2);
188 }
189 
190 /*--------------------------------------------------------
191 //		Various I/O functions
192 //------------------------------------------------------*/
193 
_putch(int c)194 int _putch(int c)
195 {
196     int e = putchar(c);
197     fflush(stdout);
198     return e;
199 }
200 
putstr(char * v)201 void putstr(char *v)
202 {
203     while (*v)
204 	_putch(*v++);
205 }
206 
207 int hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
208                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
209 
puthex(int k)210 void puthex(int k)
211 {
212     _putch('<');
213     _putch(hex[(k & 0xF0) >> 4]);
214     _putch(hex[k & 0xF]);
215     _putch('>');
216 }
217 
218 extern BYTE conin();
219 static int verbose = 0;
220 extern void diagnose(int v);
221 
222 enum mode_
223 {
224     UNSPECIFIED,
225     UNADORNED,
226     TRANSLATED
227 };
228 
229 
230 /*----------------------------------------------------------
231 //		   It all happens here
232 //--------------------------------------------------------*/
233 
main(int argc,char * argv[])234 int main(int argc, char *argv[])
235 {
236     BYTE
237         key;
238     int
239         mode = UNSPECIFIED,
240         escapes=0;
241 
242     /* Need more standard argument parsing than this ... */
243     if (argc > 1)
244     {
245         if (strcmp(argv[1], "-") == 0)
246             mode = UNADORNED;
247         else if (strcmp(argv[1], "+") == 0)
248             mode = TRANSLATED;
249         else
250         {
251             /* Try to load the named translate table */
252             char
253                 fn[140];
254             strcpy(fn, argv[1]);
255             strcat(fn, ".ktt");
256             ktt_load(fn);
257             mode = TRANSLATED;
258         }
259     }
260     if (mode == UNSPECIFIED)
261     {
262         usage();
263         return 1;
264     }
265 
266     init_term();
267     while (escapes < 3)
268     {
269 	key = mode == TRANSLATED ? conin() : serin(0);
270 	if (key == 0x1B)
271 	{
272 	    putstr("<esc>");
273 	    if (++escapes >= 3)
274 		break;
275             if (escapes == 2 && mode == TRANSLATED)
276                 diagnose((verbose = 1 - verbose));
277 	}
278 	else
279 	{
280 	    escapes = 0;
281 	    switch (key)
282 	    {
283 	    case '\r':
284 	    case '\n':
285 		puthex(key);
286 		_putch('\n');
287 		_putch('\r');
288 		break;
289 	    default:
290 		if (key < 0x20 || key > 0x7E)
291 		    puthex(key);
292 		else
293 		    _putch(key);
294 	    }
295 	}
296     }
297     _putch('\n');
298     _putch('\r');
299     return 0;
300 }
301 
302