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