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