Annotation of src/usr.bin/mg/kbd.c, Revision 1.24
1.24 ! kjell 1: /* $OpenBSD: kbd.c,v 1.23 2006/12/21 18:06:02 kjell Exp $ */
1.17 kjell 2:
3: /* This file is in the public domain. */
1.4 niklas 4:
1.1 deraadt 5: /*
1.3 millert 6: * Terminal independent keyboard handling.
1.1 deraadt 7: */
8:
1.3 millert 9: #include "def.h"
10: #include "kbd.h"
11: #include "key.h"
1.1 deraadt 12:
13: #ifndef NO_MACRO
14: #include "macro.h"
1.3 millert 15: #endif /* !NO_MACRO */
1.1 deraadt 16:
17: #ifndef METABIT
18: #define METABIT 0x80
1.3 millert 19: #endif /* !METABIT */
20:
21: #ifndef NO_DPROMPT
22: #define PROMPTL 80
1.9 mickey 23: char prompt[PROMPTL] = "", *promptp = prompt;
1.3 millert 24: #endif /* !NO_DPROMPT */
1.1 deraadt 25:
1.24 ! kjell 26: static int mgwrap(PF, int, int);
! 27:
1.3 millert 28: static int use_metakey = TRUE;
29: static int pushed = FALSE;
30: static int pushedc;
31:
1.18 deraadt 32: struct map_element *ele;
1.15 vincent 33:
34: struct key key;
1.1 deraadt 35:
36: /*
37: * Toggle the value of use_metakey
38: */
1.2 millert 39: int
1.14 vincent 40: do_meta(int f, int n)
1.1 deraadt 41: {
1.2 millert 42: if (f & FFARG)
43: use_metakey = n > 0;
44: else
45: use_metakey = !use_metakey;
1.1 deraadt 46: ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis");
1.16 db 47: return (TRUE);
1.1 deraadt 48: }
49:
1.23 kjell 50: static int bs_map = 0;
51:
1.1 deraadt 52: /*
53: * Toggle backspace mapping
54: */
1.2 millert 55: int
1.14 vincent 56: bsmap(int f, int n)
1.1 deraadt 57: {
1.2 millert 58: if (f & FFARG)
59: bs_map = n > 0;
60: else
61: bs_map = !bs_map;
1.1 deraadt 62: ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis");
1.16 db 63: return (TRUE);
1.1 deraadt 64: }
65:
1.8 art 66: void
1.14 vincent 67: ungetkey(int c)
1.1 deraadt 68: {
1.2 millert 69: if (use_metakey && pushed && c == CCHR('['))
70: pushedc |= METABIT;
1.1 deraadt 71: else
72: pushedc = c;
73: pushed = TRUE;
74: }
75:
1.2 millert 76: int
1.14 vincent 77: getkey(int flag)
1.1 deraadt 78: {
1.3 millert 79: int c;
1.1 deraadt 80:
81: #ifndef NO_DPROMPT
1.2 millert 82: if (flag && !pushed) {
1.5 art 83: if (prompt[0] != '\0' && ttwait(2000)) {
1.3 millert 84: /* avoid problems with % */
85: ewprintf("%s", prompt);
86: /* put the cursor back */
87: update();
1.22 kjell 88: epresf = KCLEAR;
1.1 deraadt 89: }
1.2 millert 90: if (promptp > prompt)
91: *(promptp - 1) = ' ';
1.1 deraadt 92: }
1.3 millert 93: #endif /* !NO_DPROMPT */
1.2 millert 94: if (pushed) {
1.1 deraadt 95: c = pushedc;
96: pushed = FALSE;
1.2 millert 97: } else
1.12 deraadt 98: c = ttgetc();
1.23 kjell 99:
100: if (bs_map) {
1.2 millert 101: if (c == CCHR('H'))
102: c = CCHR('?');
103: else if (c == CCHR('?'))
104: c = CCHR('H');
1.23 kjell 105: }
1.2 millert 106: if (use_metakey && (c & METABIT)) {
1.1 deraadt 107: pushedc = c & ~METABIT;
108: pushed = TRUE;
109: c = CCHR('[');
110: }
111: #ifndef NO_DPROMPT
1.2 millert 112: if (flag && promptp < &prompt[PROMPTL - 5]) {
1.20 kjell 113: promptp = getkeyname(promptp,
1.9 mickey 114: sizeof(prompt) - (promptp - prompt) - 1, c);
1.2 millert 115: *promptp++ = '-';
116: *promptp = '\0';
1.1 deraadt 117: }
1.3 millert 118: #endif /* !NO_DPROMPT */
1.16 db 119: return (c);
1.1 deraadt 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: */
1.2 millert 127: PF
1.14 vincent 128: doscan(KEYMAP *map, int c, KEYMAP **newmap)
1.2 millert 129: {
1.18 deraadt 130: struct map_element *elec = &map->map_element[0];
131: struct map_element *last = &map->map_element[map->map_num];
1.16 db 132: PF ret;
1.1 deraadt 133:
1.2 millert 134: while (elec < last && c > elec->k_num)
135: elec++;
1.3 millert 136:
137: /* used by prefix and binding code */
138: ele = elec;
1.2 millert 139: if (elec >= last || c < elec->k_base)
1.7 art 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:
1.16 db 146: return (ret);
1.1 deraadt 147: }
148:
1.2 millert 149: int
1.14 vincent 150: doin(void)
1.1 deraadt 151: {
1.3 millert 152: KEYMAP *curmap;
153: PF funct;
1.1 deraadt 154:
155: #ifndef NO_DPROMPT
1.2 millert 156: *(promptp = prompt) = '\0';
1.3 millert 157: #endif /* !NO_DPROMPT */
1.2 millert 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++] =
1.7 art 161: getkey(TRUE)), &curmap)) == NULL)
1.16 db 162: /* nothing */;
1.1 deraadt 163: #ifndef NO_MACRO
1.2 millert 164: if (macrodef && macrocount < MAXMACRO)
165: macro[macrocount++].m_funct = funct;
1.3 millert 166: #endif /* !NO_MACRO */
1.24 ! kjell 167: return (mgwrap(funct, 0, 1));
1.1 deraadt 168: }
169:
1.2 millert 170: int
1.14 vincent 171: rescan(int f, int n)
1.1 deraadt 172: {
1.3 millert 173: int c;
174: KEYMAP *curmap;
175: int i;
176: PF fp = NULL;
1.21 kjell 177: int md = curbp->b_nmodes;
1.2 millert 178:
179: for (;;) {
180: if (ISUPPER(key.k_chars[key.k_count - 1])) {
181: c = TOLOWER(key.k_chars[key.k_count - 1]);
1.21 kjell 182: curmap = curbp->b_modes[md]->p_map;
1.2 millert 183: for (i = 0; i < key.k_count - 1; i++) {
1.24 ! kjell 184: if ((fp = doscan(curmap, (key.k_chars[i]),
! 185: &curmap)) != NULL)
1.2 millert 186: break;
187: }
1.6 art 188: if (fp == NULL) {
1.7 art 189: if ((fp = doscan(curmap, c, NULL)) == NULL)
1.2 millert 190: while ((fp = doscan(curmap,
191: key.k_chars[key.k_count++] =
1.7 art 192: getkey(TRUE), &curmap)) == NULL)
1.16 db 193: /* nothing */;
1.2 millert 194: if (fp != rescan) {
195: #ifndef NO_MACRO
196: if (macrodef && macrocount <= MAXMACRO)
1.10 mickey 197: macro[macrocount - 1].m_funct
1.3 millert 198: = fp;
199: #endif /* !NO_MACRO */
1.24 ! kjell 200:
! 201: return (mgwrap(fp, f, n));
1.2 millert 202: }
203: }
204: }
205: /* try previous mode */
1.21 kjell 206: if (--md < 0)
1.16 db 207: return (ABORT);
1.21 kjell 208: curmap = curbp->b_modes[md]->p_map;
1.2 millert 209: for (i = 0; i < key.k_count; i++) {
1.7 art 210: if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
1.2 millert 211: break;
212: }
1.6 art 213: if (fp == NULL) {
1.10 mickey 214: while ((fp = doscan(curmap, key.k_chars[i++] =
1.7 art 215: getkey(TRUE), &curmap)) == NULL)
1.16 db 216: /* nothing */;
1.2 millert 217: key.k_count = i;
218: }
219: if (fp != rescan && i >= key.k_count - 1) {
1.1 deraadt 220: #ifndef NO_MACRO
1.2 millert 221: if (macrodef && macrocount <= MAXMACRO)
222: macro[macrocount - 1].m_funct = fp;
1.3 millert 223: #endif /* !NO_MACRO */
1.24 ! kjell 224: return (mgwrap(fp, f, n));
1.1 deraadt 225: }
226: }
1.2 millert 227: }
228:
229: int
1.14 vincent 230: universal_argument(int f, int n)
1.2 millert 231: {
1.3 millert 232: KEYMAP *curmap;
233: PF funct;
1.16 db 234: int c, nn = 4;
1.2 millert 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 == '-')
1.16 db 242: return (negative_argument(f, nn));
1.2 millert 243: if (c >= '0' && c <= '9')
1.16 db 244: return (digit_argument(f, nn));
1.2 millert 245: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 246: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 247: key.k_chars[key.k_count++] = c = getkey(TRUE);
248: }
249: if (funct != universal_argument) {
1.1 deraadt 250: #ifndef NO_MACRO
1.2 millert 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: }
1.3 millert 257: #endif /* !NO_MACRO */
1.24 ! kjell 258: return (mgwrap(funct, FFUNIV, nn));
1.2 millert 259: }
260: nn <<= 2;
1.1 deraadt 261: }
262: }
263:
1.2 millert 264: /* ARGSUSED */
265: int
1.14 vincent 266: digit_argument(int f, int n)
1.1 deraadt 267: {
1.3 millert 268: KEYMAP *curmap;
269: PF funct;
270: int nn, c;
1.2 millert 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;
1.1 deraadt 281: key.k_count = 1;
282: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 283: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 284: key.k_chars[key.k_count++] = c = getkey(TRUE);
1.1 deraadt 285: }
286: #ifndef NO_MACRO
1.2 millert 287: if (macrodef && macrocount < MAXMACRO - 1) {
288: if (f & FFARG)
289: macrocount--;
290: else
291: macro[macrocount - 1].m_funct = universal_argument;
1.1 deraadt 292: macro[macrocount++].m_count = nn;
293: macro[macrocount++].m_funct = funct;
294: }
1.3 millert 295: #endif /* !NO_MACRO */
1.24 ! kjell 296: return (mgwrap(funct, FFOTHARG, nn));
1.1 deraadt 297: }
298:
1.2 millert 299: int
1.14 vincent 300: negative_argument(int f, int n)
1.1 deraadt 301: {
1.3 millert 302: KEYMAP *curmap;
303: PF funct;
304: int c;
305: int nn = 0;
1.2 millert 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;
1.7 art 321: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 322: key.k_chars[key.k_count++] = c = getkey(TRUE);
323: }
1.1 deraadt 324: #ifndef NO_MACRO
1.2 millert 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: }
1.3 millert 333: #endif /* !NO_MACRO */
1.24 ! kjell 334: return (mgwrap(funct, FFNEGARG, nn));
1.1 deraadt 335: }
336:
337: /*
338: * Insert a character. While defining a macro, create a "LINE" containing
339: * all inserted characters.
340: */
1.2 millert 341: int
1.14 vincent 342: selfinsert(int f, int n)
1.1 deraadt 343: {
344: #ifndef NO_MACRO
1.18 deraadt 345: struct line *lp;
1.3 millert 346: #endif /* !NO_MACRO */
347: int c;
348: int count;
1.1 deraadt 349:
1.2 millert 350: if (n < 0)
1.16 db 351: return (FALSE);
1.2 millert 352: if (n == 0)
1.16 db 353: return (TRUE);
1.2 millert 354: c = key.k_chars[key.k_count - 1];
1.1 deraadt 355: #ifndef NO_MACRO
1.2 millert 356: if (macrodef && macrocount < MAXMACRO) {
357: if (f & FFARG)
358: macrocount -= 2;
1.3 millert 359:
360: /* last command was insert -- tack on the end */
361: if (lastflag & CFINS) {
1.2 millert 362: macrocount--;
1.11 vincent 363: /* Ensure the line can handle the new characters */
1.2 millert 364: if (maclcur->l_size < maclcur->l_used + n) {
1.11 vincent 365: if (lrealloc(maclcur, maclcur->l_used + n) ==
366: FALSE)
1.16 db 367: return (FALSE);
1.2 millert 368: }
1.11 vincent 369: maclcur->l_used += n;
370: /* Copy in the new data */
371: for (count = maclcur->l_used - n;
1.13 deraadt 372: count < maclcur->l_used; count++)
1.11 vincent 373: maclcur->l_text[count] = c;
1.2 millert 374: } else {
375: macro[macrocount - 1].m_funct = insert;
1.11 vincent 376: if ((lp = lalloc(n)) == NULL)
1.16 db 377: return (FALSE);
1.2 millert 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: }
1.3 millert 387: #endif /* !NO_MACRO */
1.2 millert 388: if (c == '\n') {
389: do {
390: count = lnewline();
391: } while (--n && count == TRUE);
1.16 db 392: return (count);
1.2 millert 393: }
1.3 millert 394:
395: /* overwrite mode */
396: if (curbp->b_flag & BFOVERWRITE) {
1.2 millert 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)
1.16 db 401: return (TRUE);
1.2 millert 402: }
1.16 db 403: return (linsert(n, c));
1.1 deraadt 404: }
405:
406: /*
1.16 db 407: * This could be implemented as a keymap with everything defined as self-insert.
1.1 deraadt 408: */
1.2 millert 409: int
1.14 vincent 410: quote(int f, int n)
1.1 deraadt 411: {
1.3 millert 412: int c;
1.1 deraadt 413:
1.2 millert 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: }
1.16 db 428: return (selfinsert(f, n));
1.24 ! kjell 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));
1.1 deraadt 453: }