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