X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fkbd.c;fp=mg%2Fkbd.c;h=0eb3c3608536894e487674ec0fa606f2346914e9;hp=0000000000000000000000000000000000000000;hb=a9843085ec916c175bd245a8398f30e6cc03f984;hpb=26fe4e09c6c3c250334fdeed60ce3061febecde2 diff --git a/mg/kbd.c b/mg/kbd.c new file mode 100644 index 0000000..0eb3c36 --- /dev/null +++ b/mg/kbd.c @@ -0,0 +1,436 @@ +/* $OpenBSD: kbd.c,v 1.25 2012/04/12 04:47:59 lum Exp $ */ + +/* This file is in the public domain. */ + +/* + * Terminal independent keyboard handling. + */ + +#include "def.h" +#include "kbd.h" +#include "key.h" +#include "macro.h" + +#ifndef METABIT +#define METABIT 0x80 +#endif /* !METABIT */ + +#ifndef NO_DPROMPT +#define PROMPTL 80 +char prompt[PROMPTL] = "", *promptp = prompt; +#endif /* !NO_DPROMPT */ + +static int mgwrap(PF, int, int); + +static int use_metakey = TRUE; +static int pushed = FALSE; +static int pushedc; + +struct map_element *ele; + +struct key key; + +/* + * Toggle the value of use_metakey + */ +int +do_meta(int f, int n) +{ + if (f & FFARG) + use_metakey = n > 0; + else + use_metakey = !use_metakey; + ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis"); + return (TRUE); +} + +static int bs_map = 0; + +/* + * Toggle backspace mapping + */ +int +bsmap(int f, int n) +{ + if (f & FFARG) + bs_map = n > 0; + else + bs_map = !bs_map; + ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis"); + return (TRUE); +} + +void +ungetkey(int c) +{ + if (use_metakey && pushed && c == CCHR('[')) + pushedc |= METABIT; + else + pushedc = c; + pushed = TRUE; +} + +int +getkey(int flag) +{ + int c; + +#ifndef NO_DPROMPT + if (flag && !pushed) { + if (prompt[0] != '\0' && ttwait(2000)) { + /* avoid problems with % */ + ewprintf("%s", prompt); + /* put the cursor back */ + update(); + epresf = KCLEAR; + } + if (promptp > prompt) + *(promptp - 1) = ' '; + } +#endif /* !NO_DPROMPT */ + if (pushed) { + c = pushedc; + pushed = FALSE; + } else + c = ttgetc(); + + if (bs_map) { + if (c == CCHR('H')) + c = CCHR('?'); + else if (c == CCHR('?')) + c = CCHR('H'); + } + if (use_metakey && (c & METABIT)) { + pushedc = c & ~METABIT; + pushed = TRUE; + c = CCHR('['); + } +#ifndef NO_DPROMPT + if (flag && promptp < &prompt[PROMPTL - 5]) { + promptp = getkeyname(promptp, + sizeof(prompt) - (promptp - prompt) - 1, c); + *promptp++ = '-'; + *promptp = '\0'; + } +#endif /* !NO_DPROMPT */ + return (c); +} + +/* + * doscan scans a keymap for a keyboard character and returns a pointer + * to the function associated with that character. Sets ele to the + * keymap element the keyboard was found in as a side effect. + */ +PF +doscan(KEYMAP *map, int c, KEYMAP **newmap) +{ + struct map_element *elec = &map->map_element[0]; + struct map_element *last = &map->map_element[map->map_num]; + PF ret; + + while (elec < last && c > elec->k_num) + elec++; + + /* used by prefix and binding code */ + ele = elec; + if (elec >= last || c < elec->k_base) + ret = map->map_default; + else + ret = elec->k_funcp[c - elec->k_base]; + if (ret == NULL && newmap != NULL) + *newmap = elec->k_prefmap; + + return (ret); +} + +int +doin(void) +{ + KEYMAP *curmap; + PF funct; + +#ifndef NO_DPROMPT + *(promptp = prompt) = '\0'; +#endif /* !NO_DPROMPT */ + curmap = curbp->b_modes[curbp->b_nmodes]->p_map; + key.k_count = 0; + while ((funct = doscan(curmap, (key.k_chars[key.k_count++] = + getkey(TRUE)), &curmap)) == NULL) + /* nothing */; + + if (macrodef && macrocount < MAXMACRO) + macro[macrocount++].m_funct = funct; + + return (mgwrap(funct, 0, 1)); +} + +int +rescan(int f, int n) +{ + int c; + KEYMAP *curmap; + int i; + PF fp = NULL; + int md = curbp->b_nmodes; + + for (;;) { + if (ISUPPER(key.k_chars[key.k_count - 1])) { + c = TOLOWER(key.k_chars[key.k_count - 1]); + curmap = curbp->b_modes[md]->p_map; + for (i = 0; i < key.k_count - 1; i++) { + if ((fp = doscan(curmap, (key.k_chars[i]), + &curmap)) != NULL) + break; + } + if (fp == NULL) { + if ((fp = doscan(curmap, c, NULL)) == NULL) + while ((fp = doscan(curmap, + key.k_chars[key.k_count++] = + getkey(TRUE), &curmap)) == NULL) + /* nothing */; + if (fp != rescan) { + if (macrodef && macrocount <= MAXMACRO) + macro[macrocount - 1].m_funct + = fp; + return (mgwrap(fp, f, n)); + } + } + } + /* try previous mode */ + if (--md < 0) + return (ABORT); + curmap = curbp->b_modes[md]->p_map; + for (i = 0; i < key.k_count; i++) { + if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL) + break; + } + if (fp == NULL) { + while ((fp = doscan(curmap, key.k_chars[i++] = + getkey(TRUE), &curmap)) == NULL) + /* nothing */; + key.k_count = i; + } + if (fp != rescan && i >= key.k_count - 1) { + if (macrodef && macrocount <= MAXMACRO) + macro[macrocount - 1].m_funct = fp; + return (mgwrap(fp, f, n)); + } + } +} + +int +universal_argument(int f, int n) +{ + KEYMAP *curmap; + PF funct; + int c, nn = 4; + + if (f & FFUNIV) + nn *= n; + for (;;) { + key.k_chars[0] = c = getkey(TRUE); + key.k_count = 1; + if (c == '-') + return (negative_argument(f, nn)); + if (c >= '0' && c <= '9') + return (digit_argument(f, nn)); + curmap = curbp->b_modes[curbp->b_nmodes]->p_map; + while ((funct = doscan(curmap, c, &curmap)) == NULL) { + key.k_chars[key.k_count++] = c = getkey(TRUE); + } + if (funct != universal_argument) { + if (macrodef && macrocount < MAXMACRO - 1) { + if (f & FFARG) + macrocount--; + macro[macrocount++].m_count = nn; + macro[macrocount++].m_funct = funct; + } + return (mgwrap(funct, FFUNIV, nn)); + } + nn <<= 2; + } +} + +/* ARGSUSED */ +int +digit_argument(int f, int n) +{ + KEYMAP *curmap; + PF funct; + int nn, c; + + nn = key.k_chars[key.k_count - 1] - '0'; + for (;;) { + c = getkey(TRUE); + if (c < '0' || c > '9') + break; + nn *= 10; + nn += c - '0'; + } + key.k_chars[0] = c; + key.k_count = 1; + curmap = curbp->b_modes[curbp->b_nmodes]->p_map; + while ((funct = doscan(curmap, c, &curmap)) == NULL) { + key.k_chars[key.k_count++] = c = getkey(TRUE); + } + if (macrodef && macrocount < MAXMACRO - 1) { + if (f & FFARG) + macrocount--; + else + macro[macrocount - 1].m_funct = universal_argument; + macro[macrocount++].m_count = nn; + macro[macrocount++].m_funct = funct; + } + return (mgwrap(funct, FFOTHARG, nn)); +} + +int +negative_argument(int f, int n) +{ + KEYMAP *curmap; + PF funct; + int c; + int nn = 0; + + for (;;) { + c = getkey(TRUE); + if (c < '0' || c > '9') + break; + nn *= 10; + nn += c - '0'; + } + if (nn) + nn = -nn; + else + nn = -n; + key.k_chars[0] = c; + key.k_count = 1; + curmap = curbp->b_modes[curbp->b_nmodes]->p_map; + while ((funct = doscan(curmap, c, &curmap)) == NULL) { + key.k_chars[key.k_count++] = c = getkey(TRUE); + } + if (macrodef && macrocount < MAXMACRO - 1) { + if (f & FFARG) + macrocount--; + else + macro[macrocount - 1].m_funct = universal_argument; + macro[macrocount++].m_count = nn; + macro[macrocount++].m_funct = funct; + } + return (mgwrap(funct, FFNEGARG, nn)); +} + +/* + * Insert a character. While defining a macro, create a "LINE" containing + * all inserted characters. + */ +int +selfinsert(int f, int n) +{ + struct line *lp; + int c; + int count; + + if (n < 0) + return (FALSE); + if (n == 0) + return (TRUE); + c = key.k_chars[key.k_count - 1]; + + if (macrodef && macrocount < MAXMACRO) { + if (f & FFARG) + macrocount -= 2; + + /* last command was insert -- tack on the end */ + if (lastflag & CFINS) { + macrocount--; + /* Ensure the line can handle the new characters */ + if (maclcur->l_size < maclcur->l_used + n) { + if (lrealloc(maclcur, maclcur->l_used + n) == + FALSE) + return (FALSE); + } + maclcur->l_used += n; + /* Copy in the new data */ + for (count = maclcur->l_used - n; + count < maclcur->l_used; count++) + maclcur->l_text[count] = c; + } else { + macro[macrocount - 1].m_funct = insert; + if ((lp = lalloc(n)) == NULL) + return (FALSE); + lp->l_bp = maclcur; + lp->l_fp = maclcur->l_fp; + maclcur->l_fp = lp; + maclcur = lp; + for (count = 0; count < n; count++) + lp->l_text[count] = c; + } + thisflag |= CFINS; + } + if (c == '\n') { + do { + count = lnewline(); + } while (--n && count == TRUE); + return (count); + } + + /* overwrite mode */ + if (curbp->b_flag & BFOVERWRITE) { + lchange(WFEDIT); + while (curwp->w_doto < llength(curwp->w_dotp) && n--) + lputc(curwp->w_dotp, curwp->w_doto++, c); + if (n <= 0) + return (TRUE); + } + return (linsert(n, c)); +} + +/* + * This could be implemented as a keymap with everything defined as self-insert. + */ +int +quote(int f, int n) +{ + int c; + + key.k_count = 1; + if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') { + key.k_chars[0] -= '0'; + if ((c = getkey(TRUE)) >= '0' && c <= '7') { + key.k_chars[0] <<= 3; + key.k_chars[0] += c - '0'; + if ((c = getkey(TRUE)) >= '0' && c <= '7') { + key.k_chars[0] <<= 3; + key.k_chars[0] += c - '0'; + } else + ungetkey(c); + } else + ungetkey(c); + } + return (selfinsert(f, n)); +} + +/* + * Wraper function to count invocation repeats. + * We ignore any function whose sole purpose is to get us + * to the intended function. + */ +static int +mgwrap(PF funct, int f, int n) +{ + static PF ofp; + + if (funct != rescan && + funct != negative_argument && + funct != digit_argument && + funct != universal_argument) { + if (funct == ofp) + rptcount++; + else + rptcount = 0; + ofp = funct; + } + + return ((*funct)(f, n)); +}