xref: /openbsd/usr.bin/mg/kbd.c (revision 17df1aa7)
1 /*	$OpenBSD: kbd.c,v 1.24 2008/06/14 07:38:53 kjell Exp $	*/
2 
3 /* This file is in the public domain. */
4 
5 /*
6  *	Terminal independent keyboard handling.
7  */
8 
9 #include "def.h"
10 #include "kbd.h"
11 #include "key.h"
12 
13 #ifndef NO_MACRO
14 #include "macro.h"
15 #endif /* !NO_MACRO */
16 
17 #ifndef METABIT
18 #define METABIT 0x80
19 #endif /* !METABIT */
20 
21 #ifndef NO_DPROMPT
22 #define PROMPTL 80
23 char	 prompt[PROMPTL] = "", *promptp = prompt;
24 #endif /* !NO_DPROMPT */
25 
26 static int mgwrap(PF, int, int);
27 
28 static int	 use_metakey = TRUE;
29 static int	 pushed = FALSE;
30 static int	 pushedc;
31 
32 struct map_element	*ele;
33 
34 struct key key;
35 
36 /*
37  * Toggle the value of use_metakey
38  */
39 int
40 do_meta(int f, int n)
41 {
42 	if (f & FFARG)
43 		use_metakey = n > 0;
44 	else
45 		use_metakey = !use_metakey;
46 	ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis");
47 	return (TRUE);
48 }
49 
50 static int	 bs_map = 0;
51 
52 /*
53  * Toggle backspace mapping
54  */
55 int
56 bsmap(int f, int n)
57 {
58 	if (f & FFARG)
59 		bs_map = n > 0;
60 	else
61 		bs_map = !bs_map;
62 	ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis");
63 	return (TRUE);
64 }
65 
66 void
67 ungetkey(int c)
68 {
69 	if (use_metakey && pushed && c == CCHR('['))
70 		pushedc |= METABIT;
71 	else
72 		pushedc = c;
73 	pushed = TRUE;
74 }
75 
76 int
77 getkey(int flag)
78 {
79 	int	 c;
80 
81 #ifndef NO_DPROMPT
82 	if (flag && !pushed) {
83 		if (prompt[0] != '\0' && ttwait(2000)) {
84 			/* avoid problems with % */
85 			ewprintf("%s", prompt);
86 			/* put the cursor back */
87 			update();
88 			epresf = KCLEAR;
89 		}
90 		if (promptp > prompt)
91 			*(promptp - 1) = ' ';
92 	}
93 #endif /* !NO_DPROMPT */
94 	if (pushed) {
95 		c = pushedc;
96 		pushed = FALSE;
97 	} else
98 		c = ttgetc();
99 
100 	if (bs_map) {
101 		if (c == CCHR('H'))
102 			c = CCHR('?');
103 		else if (c == CCHR('?'))
104 			c = CCHR('H');
105 	}
106 	if (use_metakey && (c & METABIT)) {
107 		pushedc = c & ~METABIT;
108 		pushed = TRUE;
109 		c = CCHR('[');
110 	}
111 #ifndef NO_DPROMPT
112 	if (flag && promptp < &prompt[PROMPTL - 5]) {
113 		promptp = getkeyname(promptp,
114 		    sizeof(prompt) - (promptp - prompt) - 1, c);
115 		*promptp++ = '-';
116 		*promptp = '\0';
117 	}
118 #endif /* !NO_DPROMPT */
119 	return (c);
120 }
121 
122 /*
123  * doscan scans a keymap for a keyboard character and returns a pointer
124  * to the function associated with that character.  Sets ele to the
125  * keymap element the keyboard was found in as a side effect.
126  */
127 PF
128 doscan(KEYMAP *map, int c, KEYMAP **newmap)
129 {
130 	struct map_element	*elec = &map->map_element[0];
131 	struct map_element	*last = &map->map_element[map->map_num];
132 	PF		 ret;
133 
134 	while (elec < last && c > elec->k_num)
135 		elec++;
136 
137 	/* used by prefix and binding code */
138 	ele = elec;
139 	if (elec >= last || c < elec->k_base)
140 		ret = map->map_default;
141 	else
142 		ret = elec->k_funcp[c - elec->k_base];
143 	if (ret == NULL && newmap != NULL)
144 		*newmap = elec->k_prefmap;
145 
146 	return (ret);
147 }
148 
149 int
150 doin(void)
151 {
152 	KEYMAP	*curmap;
153 	PF	 funct;
154 
155 #ifndef NO_DPROMPT
156 	*(promptp = prompt) = '\0';
157 #endif /* !NO_DPROMPT */
158 	curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
159 	key.k_count = 0;
160 	while ((funct = doscan(curmap, (key.k_chars[key.k_count++] =
161 	    getkey(TRUE)), &curmap)) == NULL)
162 		/* nothing */;
163 #ifndef NO_MACRO
164 	if (macrodef && macrocount < MAXMACRO)
165 		macro[macrocount++].m_funct = funct;
166 #endif /* !NO_MACRO */
167 	return (mgwrap(funct, 0, 1));
168 }
169 
170 int
171 rescan(int f, int n)
172 {
173 	int	 c;
174 	KEYMAP	*curmap;
175 	int	 i;
176 	PF	 fp = NULL;
177 	int	 md = curbp->b_nmodes;
178 
179 	for (;;) {
180 		if (ISUPPER(key.k_chars[key.k_count - 1])) {
181 			c = TOLOWER(key.k_chars[key.k_count - 1]);
182 			curmap = curbp->b_modes[md]->p_map;
183 			for (i = 0; i < key.k_count - 1; i++) {
184 				if ((fp = doscan(curmap, (key.k_chars[i]),
185 				    &curmap)) != NULL)
186 					break;
187 			}
188 			if (fp == NULL) {
189 				if ((fp = doscan(curmap, c, NULL)) == NULL)
190 					while ((fp = doscan(curmap,
191 					    key.k_chars[key.k_count++] =
192 					    getkey(TRUE), &curmap)) == NULL)
193 						/* nothing */;
194 				if (fp != rescan) {
195 #ifndef NO_MACRO
196 					if (macrodef && macrocount <= MAXMACRO)
197 						macro[macrocount - 1].m_funct
198 						    = fp;
199 #endif /* !NO_MACRO */
200 
201 					return (mgwrap(fp, f, n));
202 				}
203 			}
204 		}
205 		/* try previous mode */
206 		if (--md < 0)
207 			return (ABORT);
208 		curmap = curbp->b_modes[md]->p_map;
209 		for (i = 0; i < key.k_count; i++) {
210 			if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
211 				break;
212 		}
213 		if (fp == NULL) {
214 			while ((fp = doscan(curmap, key.k_chars[i++] =
215 			    getkey(TRUE), &curmap)) == NULL)
216 				/* nothing */;
217 			key.k_count = i;
218 		}
219 		if (fp != rescan && i >= key.k_count - 1) {
220 #ifndef NO_MACRO
221 			if (macrodef && macrocount <= MAXMACRO)
222 				macro[macrocount - 1].m_funct = fp;
223 #endif /* !NO_MACRO */
224 			return (mgwrap(fp, f, n));
225 		}
226 	}
227 }
228 
229 int
230 universal_argument(int f, int n)
231 {
232 	KEYMAP	*curmap;
233 	PF	 funct;
234 	int	 c, nn = 4;
235 
236 	if (f & FFUNIV)
237 		nn *= n;
238 	for (;;) {
239 		key.k_chars[0] = c = getkey(TRUE);
240 		key.k_count = 1;
241 		if (c == '-')
242 			return (negative_argument(f, nn));
243 		if (c >= '0' && c <= '9')
244 			return (digit_argument(f, nn));
245 		curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
246 		while ((funct = doscan(curmap, c, &curmap)) == NULL) {
247 			key.k_chars[key.k_count++] = c = getkey(TRUE);
248 		}
249 		if (funct != universal_argument) {
250 #ifndef NO_MACRO
251 			if (macrodef && macrocount < MAXMACRO - 1) {
252 				if (f & FFARG)
253 					macrocount--;
254 				macro[macrocount++].m_count = nn;
255 				macro[macrocount++].m_funct = funct;
256 			}
257 #endif /* !NO_MACRO */
258 			return (mgwrap(funct, FFUNIV, nn));
259 		}
260 		nn <<= 2;
261 	}
262 }
263 
264 /* ARGSUSED */
265 int
266 digit_argument(int f, int n)
267 {
268 	KEYMAP	*curmap;
269 	PF	 funct;
270 	int	 nn, c;
271 
272 	nn = key.k_chars[key.k_count - 1] - '0';
273 	for (;;) {
274 		c = getkey(TRUE);
275 		if (c < '0' || c > '9')
276 			break;
277 		nn *= 10;
278 		nn += c - '0';
279 	}
280 	key.k_chars[0] = c;
281 	key.k_count = 1;
282 	curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
283 	while ((funct = doscan(curmap, c, &curmap)) == NULL) {
284 		key.k_chars[key.k_count++] = c = getkey(TRUE);
285 	}
286 #ifndef NO_MACRO
287 	if (macrodef && macrocount < MAXMACRO - 1) {
288 		if (f & FFARG)
289 			macrocount--;
290 		else
291 			macro[macrocount - 1].m_funct = universal_argument;
292 		macro[macrocount++].m_count = nn;
293 		macro[macrocount++].m_funct = funct;
294 	}
295 #endif /* !NO_MACRO */
296 	return (mgwrap(funct, FFOTHARG, nn));
297 }
298 
299 int
300 negative_argument(int f, int n)
301 {
302 	KEYMAP	*curmap;
303 	PF	 funct;
304 	int	 c;
305 	int	 nn = 0;
306 
307 	for (;;) {
308 		c = getkey(TRUE);
309 		if (c < '0' || c > '9')
310 			break;
311 		nn *= 10;
312 		nn += c - '0';
313 	}
314 	if (nn)
315 		nn = -nn;
316 	else
317 		nn = -n;
318 	key.k_chars[0] = c;
319 	key.k_count = 1;
320 	curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
321 	while ((funct = doscan(curmap, c, &curmap)) == NULL) {
322 		key.k_chars[key.k_count++] = c = getkey(TRUE);
323 	}
324 #ifndef NO_MACRO
325 	if (macrodef && macrocount < MAXMACRO - 1) {
326 		if (f & FFARG)
327 			macrocount--;
328 		else
329 			macro[macrocount - 1].m_funct = universal_argument;
330 		macro[macrocount++].m_count = nn;
331 		macro[macrocount++].m_funct = funct;
332 	}
333 #endif /* !NO_MACRO */
334 	return (mgwrap(funct, FFNEGARG, nn));
335 }
336 
337 /*
338  * Insert a character.	While defining a macro, create a "LINE" containing
339  * all inserted characters.
340  */
341 int
342 selfinsert(int f, int n)
343 {
344 #ifndef NO_MACRO
345 	struct line	*lp;
346 #endif /* !NO_MACRO */
347 	int	 c;
348 	int	 count;
349 
350 	if (n < 0)
351 		return (FALSE);
352 	if (n == 0)
353 		return (TRUE);
354 	c = key.k_chars[key.k_count - 1];
355 #ifndef NO_MACRO
356 	if (macrodef && macrocount < MAXMACRO) {
357 		if (f & FFARG)
358 			macrocount -= 2;
359 
360 		/* last command was insert -- tack on the end */
361 		if (lastflag & CFINS) {
362 			macrocount--;
363 			/* Ensure the line can handle the new characters */
364 			if (maclcur->l_size < maclcur->l_used + n) {
365 				if (lrealloc(maclcur, maclcur->l_used + n) ==
366 				    FALSE)
367 					return (FALSE);
368 			}
369 			maclcur->l_used += n;
370 			/* Copy in the new data */
371 			for (count = maclcur->l_used - n;
372 			    count < maclcur->l_used; count++)
373 				maclcur->l_text[count] = c;
374 		} else {
375 			macro[macrocount - 1].m_funct = insert;
376 			if ((lp = lalloc(n)) == NULL)
377 				return (FALSE);
378 			lp->l_bp = maclcur;
379 			lp->l_fp = maclcur->l_fp;
380 			maclcur->l_fp = lp;
381 			maclcur = lp;
382 			for (count = 0; count < n; count++)
383 				lp->l_text[count] = c;
384 		}
385 		thisflag |= CFINS;
386 	}
387 #endif /* !NO_MACRO */
388 	if (c == '\n') {
389 		do {
390 			count = lnewline();
391 		} while (--n && count == TRUE);
392 		return (count);
393 	}
394 
395 	/* overwrite mode */
396 	if (curbp->b_flag & BFOVERWRITE) {
397 		lchange(WFEDIT);
398 		while (curwp->w_doto < llength(curwp->w_dotp) && n--)
399 			lputc(curwp->w_dotp, curwp->w_doto++, c);
400 		if (n <= 0)
401 			return (TRUE);
402 	}
403 	return (linsert(n, c));
404 }
405 
406 /*
407  * This could be implemented as a keymap with everything defined as self-insert.
408  */
409 int
410 quote(int f, int n)
411 {
412 	int	 c;
413 
414 	key.k_count = 1;
415 	if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') {
416 		key.k_chars[0] -= '0';
417 		if ((c = getkey(TRUE)) >= '0' && c <= '7') {
418 			key.k_chars[0] <<= 3;
419 			key.k_chars[0] += c - '0';
420 			if ((c = getkey(TRUE)) >= '0' && c <= '7') {
421 				key.k_chars[0] <<= 3;
422 				key.k_chars[0] += c - '0';
423 			} else
424 				ungetkey(c);
425 		} else
426 			ungetkey(c);
427 	}
428 	return (selfinsert(f, n));
429 }
430 
431 /*
432  * Wraper function to count invocation repeats.
433  * We ignore any function whose sole purpose is to get us
434  * to the intended function.
435  */
436 static int
437 mgwrap(PF funct, int f, int n)
438 {
439 	static	 PF ofp;
440 
441 	if (funct != rescan &&
442 	    funct != negative_argument &&
443 	    funct != digit_argument &&
444 	    funct != universal_argument) {
445 		if (funct == ofp)
446 			rptcount++;
447 		else
448 			rptcount = 0;
449 		ofp = funct;
450 	}
451 
452 	return ((*funct)(f, n));
453 }
454