1 /*
2 * int KeyInit (map, flushproc)
3 * struct KeyMap *map;
4 * void (*flushproc) (void);
5 *
6 * - set key map table.
7 * Flushproc is called before actual reading from terminal.
8 * Returns 1 if ok else 0.
9 *
10 * int KeyGet ()
11 *
12 * - reads key from terminal.
13 * Returns key (always >= 0).
14 *
15 * int KeyGetChar ()
16 *
17 * - reads char from terminal.
18 * Returns char (always >= 0).
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #if HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif
26 #include "scr.h"
27
28 static struct KeyMap *km;
29 static void (*flush) (void);
30
31 #include <setjmp.h>
32 #include <signal.h>
33
34 #define NKEY 100
35
36 static jmp_buf wakeup;
37 static keyback;
38 static unsigned oldalarm;
39
40 static cyrinput;
41 extern char VCyrInputTable [];
42
43 /*
44 * Compare keys. Used in call to qsort.
45 * Return -1, 0, 1 iff a is less, equal or greater than b.
46 * First, check if there is ->str.
47 * Then compare lengths, then strings.
48 * If equal, check ->tcap field.
49 */
compkeys(const void * arg1,const void * arg2)50 static int compkeys (const void *arg1, const void *arg2)
51 {
52 const struct KeyMap *a = arg1;
53 const struct KeyMap *b = arg2;
54 register cmp;
55
56 if (! a->str) {
57 if (! b->str)
58 return (0);
59 return (1);
60 }
61 if (! b->str)
62 return (-1);
63 cmp = strcmp (a->str, b->str);
64 if (cmp)
65 return (cmp);
66 if (! a->tcap) {
67 if (! b->tcap)
68 return (0);
69 return (1);
70 }
71 if (! b->tcap)
72 return (-1);
73 return (0);
74 }
75
KeyInit(struct KeyMap * map,void (* flushproc)(void))76 void KeyInit (struct KeyMap *map, void (*flushproc) (void))
77 {
78 struct CapTab tab [NKEY];
79 register struct KeyMap *kp;
80 register struct CapTab *t;
81
82 km = map;
83 flush = flushproc;
84 for (t=tab, kp=km; kp->val && t<tab+NKEY-1; ++kp, ++t) {
85 if (! kp->tcap)
86 continue;
87 memcpy (t->tname, kp->tcap, sizeof (t->tname));
88 t->ttype = CAPSTR;
89 t->tdef = 0;
90 t->tc = 0;
91 t->ti = 0;
92 t->ts = &kp->str;
93 }
94 kp->val = 0;
95 t->tname[0] = 0;
96 CapGet (tab);
97 qsort ((char *) km, (unsigned) (kp - km), sizeof (km[0]), compkeys);
98 #ifdef notdef
99 {
100 register struct KeyMap *p;
101 for (p=km; p<kp; ++p)
102 if (kp->str)
103 printf ("'\\%03o%s' -> %x\n", p->str[0], p->str+1, p->val);
104 }
105 #endif
106 }
107
KeyGetChar()108 int KeyGetChar ()
109 {
110 char c;
111
112 while (read (0, &c, 1) != 1)
113 if (! isatty (0))
114 exit (0);
115 return (c & 0377);
116 }
117
badkey()118 static RETSIGTYPE badkey ()
119 {
120 alarm (oldalarm);
121 longjmp (wakeup, -1);
122 }
123
nmgetch(struct KeyMap * kp)124 static int nmgetch (struct KeyMap *kp)
125 {
126 register match, c;
127 register struct KeyMap *lp;
128
129 for (match=1; ; ++match) {
130 if (! kp->str [match])
131 return (kp->val);
132 c = KeyGetChar ();
133 if (kp->str [match] == c)
134 continue;
135 lp = kp;
136 do {
137 ++kp;
138 if (! kp->str)
139 goto unknown;
140 } while (kp->str [match] != c);
141 if (lp->str [match-1] != kp->str [match-1])
142 goto unknown;
143 if (match>1 && strncmp (lp->str, kp->str, match-1))
144 goto unknown;
145 }
146 unknown:
147 alarm (oldalarm);
148 longjmp (wakeup, 1);
149 /* NOTREACHED */
150 }
151
KeyGet()152 int KeyGet ()
153 {
154 static struct KeyMap *kp;
155 static int c, j;
156
157 if (keyback) {
158 c = keyback;
159 keyback = 0;
160 return (c);
161 }
162 if (flush)
163 (*flush) ();
164 nextkey:
165 c = KeyGetChar ();
166 for (kp=km; kp->str; ++kp)
167 if ((char) c == kp->str[0])
168 break;
169 if (! kp->str) {
170 #ifdef DOC
171 if (c == cntrl ('_')) {
172 _prscreen ();
173 goto nextkey;
174 }
175 #endif
176 /*
177 * Handle cyrillic input.
178 * ^N turns on cyrillic input mode,
179 * after that all input characters
180 * in range ' '...'~' must be recoded
181 * by special cyrillic input table.
182 * It is specified by Ct termcap descriptor.
183 * ^O turns off cyrillic input mode.
184 */
185 if (c == cntrl ('N')) {
186 cyrinput = 1;
187 goto nextkey;
188 } else if (c == cntrl ('O')) {
189 cyrinput = 0;
190 goto nextkey;
191 } else if (cyrinput && c>=' ' && c<='~')
192 c = VCyrInputTable [c - ' '] & 0xff;
193
194 return (c);
195 }
196 if (! kp->str [1])
197 return (kp->val);
198 /* look for escape sequence */
199 if ((j = setjmp (wakeup))) {
200 /* time out or unknown escape sequence */
201 TtyFlushInput ();
202 if (j < 0)
203 return (c);
204 goto nextkey;
205 }
206 signal (SIGALRM, badkey);
207 oldalarm = alarm (2);
208 c = nmgetch (kp);
209 alarm (oldalarm);
210 return (c);
211 }
212
KeyUnget(int key)213 void KeyUnget (int key)
214 {
215 keyback = key;
216 }
217