Changes in uspace/app/bdsh/input.c [36a75a2:19f857a] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/bdsh/input.c
r36a75a2 r19f857a 1 1 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> 2 2 * All rights reserved. 3 * Copyright (c) 2008, Jiri Svoboda - All Rights Reserved 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 42 43 #include <assert.h> 43 44 #include <bool.h> 44 #include <tinput.h>45 45 46 46 #include "config.h" … … 51 51 #include "exec.h" 52 52 53 #define HISTORY_LEN 10 54 53 55 /** Text input field. */ 54 static tinput_t *tinput; 56 typedef struct { 57 /** Buffer holding text currently being edited */ 58 wchar_t buffer[INPUT_MAX + 1]; 59 /** Screen coordinates of the top-left corner of the text field */ 60 int col0, row0; 61 /** Screen dimensions */ 62 int con_cols, con_rows; 63 /** Number of characters in @c buffer */ 64 int nc; 65 /** Caret position within buffer */ 66 int pos; 67 /** Selection mark position within buffer */ 68 int sel_start; 69 70 /** History (dynamically allocated strings) */ 71 char *history[1 + HISTORY_LEN]; 72 /** Number of entries in @c history, not counting [0] */ 73 int hnum; 74 /** Current position in history */ 75 int hpos; 76 /** Exit flag */ 77 bool done; 78 } tinput_t; 79 80 /** Seek direction */ 81 typedef enum { 82 seek_backward = -1, 83 seek_forward = 1 84 } seek_dir_t; 85 86 static tinput_t tinput; 87 88 static char *tinput_read(tinput_t *ti); 89 static void tinput_insert_string(tinput_t *ti, const char *str); 90 static void tinput_sel_get_bounds(tinput_t *ti, int *sa, int *sb); 91 static bool tinput_sel_active(tinput_t *ti); 92 static void tinput_sel_all(tinput_t *ti); 93 static void tinput_sel_delete(tinput_t *ti); 94 static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev); 95 static void tinput_key_shift(tinput_t *ti, console_event_t *ev); 96 static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev); 97 static void tinput_key_unmod(tinput_t *ti, console_event_t *ev); 98 static void tinput_pre_seek(tinput_t *ti, bool shift_held); 99 static void tinput_post_seek(tinput_t *ti, bool shift_held); 55 100 56 101 /* Tokenizes input from console, sees if the first word is a built-in, if so … … 104 149 } 105 150 151 static void tinput_display_tail(tinput_t *ti, int start, int pad) 152 { 153 static wchar_t dbuf[INPUT_MAX + 1]; 154 int sa, sb; 155 int i, p; 156 157 tinput_sel_get_bounds(ti, &sa, &sb); 158 159 console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols, 160 ti->row0 + (ti->col0 + start) / ti->con_cols); 161 console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); 162 163 p = start; 164 if (p < sa) { 165 memcpy(dbuf, ti->buffer + p, (sa - p) * sizeof(wchar_t)); 166 dbuf[sa - p] = '\0'; 167 printf("%ls", dbuf); 168 p = sa; 169 } 170 171 if (p < sb) { 172 fflush(stdout); 173 console_set_color(fphone(stdout), COLOR_BLACK, COLOR_RED, 0); 174 memcpy(dbuf, ti->buffer + p, 175 (sb - p) * sizeof(wchar_t)); 176 dbuf[sb - p] = '\0'; 177 printf("%ls", dbuf); 178 p = sb; 179 } 180 181 fflush(stdout); 182 console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0); 183 184 if (p < ti->nc) { 185 memcpy(dbuf, ti->buffer + p, 186 (ti->nc - p) * sizeof(wchar_t)); 187 dbuf[ti->nc - p] = '\0'; 188 printf("%ls", dbuf); 189 } 190 191 for (i = 0; i < pad; ++i) 192 putchar(' '); 193 fflush(stdout); 194 } 195 196 static char *tinput_get_str(tinput_t *ti) 197 { 198 return wstr_to_astr(ti->buffer); 199 } 200 201 static void tinput_position_caret(tinput_t *ti) 202 { 203 console_goto(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols, 204 ti->row0 + (ti->col0 + ti->pos) / ti->con_cols); 205 } 206 207 /** Update row0 in case the screen could have scrolled. */ 208 static void tinput_update_origin(tinput_t *ti) 209 { 210 int width, rows; 211 212 width = ti->col0 + ti->nc; 213 rows = (width / ti->con_cols) + 1; 214 215 /* Update row0 if the screen scrolled. */ 216 if (ti->row0 + rows > ti->con_rows) 217 ti->row0 = ti->con_rows - rows; 218 } 219 220 static void tinput_insert_char(tinput_t *ti, wchar_t c) 221 { 222 int i; 223 int new_width, new_height; 224 225 if (ti->nc == INPUT_MAX) 226 return; 227 228 new_width = ti->col0 + ti->nc + 1; 229 if (new_width % ti->con_cols == 0) { 230 /* Advancing to new line. */ 231 new_height = (new_width / ti->con_cols) + 1; 232 if (new_height >= ti->con_rows) 233 return; /* Disallow text longer than 1 page for now. */ 234 } 235 236 for (i = ti->nc; i > ti->pos; --i) 237 ti->buffer[i] = ti->buffer[i - 1]; 238 239 ti->buffer[ti->pos] = c; 240 ti->pos += 1; 241 ti->nc += 1; 242 ti->buffer[ti->nc] = '\0'; 243 ti->sel_start = ti->pos; 244 245 tinput_display_tail(ti, ti->pos - 1, 0); 246 tinput_update_origin(ti); 247 tinput_position_caret(ti); 248 } 249 250 static void tinput_insert_string(tinput_t *ti, const char *str) 251 { 252 int i; 253 int new_width, new_height; 254 int ilen; 255 wchar_t c; 256 size_t off; 257 258 ilen = min((ssize_t) str_length(str), INPUT_MAX - ti->nc); 259 if (ilen == 0) 260 return; 261 262 new_width = ti->col0 + ti->nc + ilen; 263 new_height = (new_width / ti->con_cols) + 1; 264 if (new_height >= ti->con_rows) 265 return; /* Disallow text longer than 1 page for now. */ 266 267 for (i = ti->nc - 1; i >= ti->pos; --i) 268 ti->buffer[i + ilen] = ti->buffer[i]; 269 270 off = 0; i = 0; 271 while (i < ilen) { 272 c = str_decode(str, &off, STR_NO_LIMIT); 273 if (c == '\0') 274 break; 275 276 /* Filter out non-printable chars. */ 277 if (c < 32) 278 c = 32; 279 280 ti->buffer[ti->pos + i] = c; 281 ++i; 282 } 283 284 ti->pos += ilen; 285 ti->nc += ilen; 286 ti->buffer[ti->nc] = '\0'; 287 ti->sel_start = ti->pos; 288 289 tinput_display_tail(ti, ti->pos - ilen, 0); 290 tinput_update_origin(ti); 291 tinput_position_caret(ti); 292 } 293 294 static void tinput_backspace(tinput_t *ti) 295 { 296 int i; 297 298 if (tinput_sel_active(ti)) { 299 tinput_sel_delete(ti); 300 return; 301 } 302 303 if (ti->pos == 0) 304 return; 305 306 for (i = ti->pos; i < ti->nc; ++i) 307 ti->buffer[i - 1] = ti->buffer[i]; 308 ti->pos -= 1; 309 ti->nc -= 1; 310 ti->buffer[ti->nc] = '\0'; 311 ti->sel_start = ti->pos; 312 313 tinput_display_tail(ti, ti->pos, 1); 314 tinput_position_caret(ti); 315 } 316 317 static void tinput_delete(tinput_t *ti) 318 { 319 if (tinput_sel_active(ti)) { 320 tinput_sel_delete(ti); 321 return; 322 } 323 324 if (ti->pos == ti->nc) 325 return; 326 327 ti->pos += 1; 328 ti->sel_start = ti->pos; 329 330 tinput_backspace(ti); 331 } 332 333 static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir, bool shift_held) 334 { 335 tinput_pre_seek(ti, shift_held); 336 337 if (dir == seek_forward) { 338 if (ti->pos < ti->nc) 339 ti->pos += 1; 340 } else { 341 if (ti->pos > 0) 342 ti->pos -= 1; 343 } 344 345 tinput_post_seek(ti, shift_held); 346 } 347 348 static void tinput_seek_word(tinput_t *ti, seek_dir_t dir, bool shift_held) 349 { 350 tinput_pre_seek(ti, shift_held); 351 352 if (dir == seek_forward) { 353 if (ti->pos == ti->nc) 354 return; 355 356 while (1) { 357 ti->pos += 1; 358 359 if (ti->pos == ti->nc) 360 break; 361 362 if (ti->buffer[ti->pos - 1] == ' ' && 363 ti->buffer[ti->pos] != ' ') 364 break; 365 } 366 } else { 367 if (ti->pos == 0) 368 return; 369 370 while (1) { 371 ti->pos -= 1; 372 373 if (ti->pos == 0) 374 break; 375 376 if (ti->buffer[ti->pos - 1] == ' ' && 377 ti->buffer[ti->pos] != ' ') 378 break; 379 } 380 381 } 382 383 tinput_post_seek(ti, shift_held); 384 } 385 386 static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir, bool shift_held) 387 { 388 tinput_pre_seek(ti, shift_held); 389 390 if (dir == seek_forward) { 391 if (ti->pos + ti->con_cols <= ti->nc) 392 ti->pos = ti->pos + ti->con_cols; 393 } else { 394 if (ti->pos - ti->con_cols >= 0) 395 ti->pos = ti->pos - ti->con_cols; 396 } 397 398 tinput_post_seek(ti, shift_held); 399 } 400 401 static void tinput_seek_max(tinput_t *ti, seek_dir_t dir, bool shift_held) 402 { 403 tinput_pre_seek(ti, shift_held); 404 405 if (dir == seek_backward) 406 ti->pos = 0; 407 else 408 ti->pos = ti->nc; 409 410 tinput_post_seek(ti, shift_held); 411 } 412 413 static void tinput_pre_seek(tinput_t *ti, bool shift_held) 414 { 415 if (tinput_sel_active(ti) && !shift_held) { 416 /* Unselect and redraw. */ 417 ti->sel_start = ti->pos; 418 tinput_display_tail(ti, 0, 0); 419 tinput_position_caret(ti); 420 } 421 } 422 423 static void tinput_post_seek(tinput_t *ti, bool shift_held) 424 { 425 if (shift_held) { 426 /* Selecting text. Need redraw. */ 427 tinput_display_tail(ti, 0, 0); 428 } else { 429 /* Shift not held. Keep selection empty. */ 430 ti->sel_start = ti->pos; 431 } 432 tinput_position_caret(ti); 433 } 434 435 static void tinput_history_insert(tinput_t *ti, char *str) 436 { 437 int i; 438 439 if (ti->hnum < HISTORY_LEN) { 440 ti->hnum += 1; 441 } else { 442 if (ti->history[HISTORY_LEN] != NULL) 443 free(ti->history[HISTORY_LEN]); 444 } 445 446 for (i = ti->hnum; i > 1; --i) 447 ti->history[i] = ti->history[i - 1]; 448 449 ti->history[1] = str_dup(str); 450 451 if (ti->history[0] != NULL) { 452 free(ti->history[0]); 453 ti->history[0] = NULL; 454 } 455 } 456 457 static void tinput_set_str(tinput_t *ti, char *str) 458 { 459 str_to_wstr(ti->buffer, INPUT_MAX, str); 460 ti->nc = wstr_length(ti->buffer); 461 ti->pos = ti->nc; 462 ti->sel_start = ti->pos; 463 } 464 465 static void tinput_sel_get_bounds(tinput_t *ti, int *sa, int *sb) 466 { 467 if (ti->sel_start < ti->pos) { 468 *sa = ti->sel_start; 469 *sb = ti->pos; 470 } else { 471 *sa = ti->pos; 472 *sb = ti->sel_start; 473 } 474 } 475 476 static bool tinput_sel_active(tinput_t *ti) 477 { 478 return ti->sel_start != ti->pos; 479 } 480 481 static void tinput_sel_all(tinput_t *ti) 482 { 483 ti->sel_start = 0; 484 ti->pos = ti->nc; 485 tinput_display_tail(ti, 0, 0); 486 tinput_position_caret(ti); 487 } 488 489 static void tinput_sel_delete(tinput_t *ti) 490 { 491 int sa, sb; 492 493 tinput_sel_get_bounds(ti, &sa, &sb); 494 if (sa == sb) 495 return; 496 497 memmove(ti->buffer + sa, ti->buffer + sb, 498 (ti->nc - sb) * sizeof(wchar_t)); 499 ti->pos = ti->sel_start = sa; 500 ti->nc -= (sb - sa); 501 ti->buffer[ti->nc] = '\0'; 502 503 tinput_display_tail(ti, sa, sb - sa); 504 tinput_position_caret(ti); 505 } 506 507 static void tinput_sel_copy_to_cb(tinput_t *ti) 508 { 509 int sa, sb; 510 char *str; 511 512 tinput_sel_get_bounds(ti, &sa, &sb); 513 514 if (sb < ti->nc) { 515 wchar_t tmp_c = ti->buffer[sb]; 516 ti->buffer[sb] = '\0'; 517 str = wstr_to_astr(ti->buffer + sa); 518 ti->buffer[sb] = tmp_c; 519 } else 520 str = wstr_to_astr(ti->buffer + sa); 521 522 if (str == NULL) 523 goto error; 524 525 if (clipboard_put_str(str) != EOK) 526 goto error; 527 528 free(str); 529 return; 530 error: 531 return; 532 /* TODO: Give the user some warning. */ 533 } 534 535 static void tinput_paste_from_cb(tinput_t *ti) 536 { 537 char *str; 538 int rc; 539 540 rc = clipboard_get_str(&str); 541 if (rc != EOK || str == NULL) 542 return; /* TODO: Give the user some warning. */ 543 544 tinput_insert_string(ti, str); 545 free(str); 546 } 547 548 static void tinput_history_seek(tinput_t *ti, int offs) 549 { 550 int pad; 551 552 if (ti->hpos + offs < 0 || ti->hpos + offs > ti->hnum) 553 return; 554 555 if (ti->history[ti->hpos] != NULL) { 556 free(ti->history[ti->hpos]); 557 ti->history[ti->hpos] = NULL; 558 } 559 560 ti->history[ti->hpos] = tinput_get_str(ti); 561 ti->hpos += offs; 562 563 pad = ti->nc - str_length(ti->history[ti->hpos]); 564 if (pad < 0) pad = 0; 565 566 tinput_set_str(ti, ti->history[ti->hpos]); 567 tinput_display_tail(ti, 0, pad); 568 tinput_update_origin(ti); 569 tinput_position_caret(ti); 570 } 571 572 /** Initialize text input field. 573 * 574 * Must be called before using the field. It clears the history. 575 */ 576 static void tinput_init(tinput_t *ti) 577 { 578 ti->hnum = 0; 579 ti->hpos = 0; 580 ti->history[0] = NULL; 581 } 582 583 /** Read in one line of input. */ 584 static char *tinput_read(tinput_t *ti) 585 { 586 console_event_t ev; 587 char *str; 588 589 fflush(stdout); 590 591 if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK) 592 return NULL; 593 if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK) 594 return NULL; 595 596 ti->pos = ti->sel_start = 0; 597 ti->nc = 0; 598 ti->buffer[0] = '\0'; 599 ti->done = false; 600 601 while (!ti->done) { 602 fflush(stdout); 603 if (!console_get_event(fphone(stdin), &ev)) 604 return NULL; 605 606 if (ev.type != KEY_PRESS) 607 continue; 608 609 if ((ev.mods & KM_CTRL) != 0 && 610 (ev.mods & (KM_ALT | KM_SHIFT)) == 0) { 611 tinput_key_ctrl(ti, &ev); 612 } 613 614 if ((ev.mods & KM_SHIFT) != 0 && 615 (ev.mods & (KM_CTRL | KM_ALT)) == 0) { 616 tinput_key_shift(ti, &ev); 617 } 618 619 if ((ev.mods & KM_CTRL) != 0 && 620 (ev.mods & KM_SHIFT) != 0 && 621 (ev.mods & KM_ALT) == 0) { 622 tinput_key_ctrl_shift(ti, &ev); 623 } 624 625 if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) { 626 tinput_key_unmod(ti, &ev); 627 } 628 629 if (ev.c >= ' ') { 630 tinput_sel_delete(ti); 631 tinput_insert_char(ti, ev.c); 632 } 633 } 634 635 ti->pos = ti->nc; 636 tinput_position_caret(ti); 637 putchar('\n'); 638 639 str = tinput_get_str(ti); 640 if (str_cmp(str, "") != 0) 641 tinput_history_insert(ti, str); 642 643 ti->hpos = 0; 644 645 return str; 646 } 647 648 static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev) 649 { 650 switch (ev->key) { 651 case KC_LEFT: 652 tinput_seek_word(ti, seek_backward, false); 653 break; 654 case KC_RIGHT: 655 tinput_seek_word(ti, seek_forward, false); 656 break; 657 case KC_UP: 658 tinput_seek_vertical(ti, seek_backward, false); 659 break; 660 case KC_DOWN: 661 tinput_seek_vertical(ti, seek_forward, false); 662 break; 663 case KC_X: 664 tinput_sel_copy_to_cb(ti); 665 tinput_sel_delete(ti); 666 break; 667 case KC_C: 668 tinput_sel_copy_to_cb(ti); 669 break; 670 case KC_V: 671 tinput_sel_delete(ti); 672 tinput_paste_from_cb(ti); 673 break; 674 case KC_A: 675 tinput_sel_all(ti); 676 break; 677 default: 678 break; 679 } 680 } 681 682 static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev) 683 { 684 switch (ev->key) { 685 case KC_LEFT: 686 tinput_seek_word(ti, seek_backward, true); 687 break; 688 case KC_RIGHT: 689 tinput_seek_word(ti, seek_forward, true); 690 break; 691 case KC_UP: 692 tinput_seek_vertical(ti, seek_backward, true); 693 break; 694 case KC_DOWN: 695 tinput_seek_vertical(ti, seek_forward, true); 696 break; 697 default: 698 break; 699 } 700 } 701 702 static void tinput_key_shift(tinput_t *ti, console_event_t *ev) 703 { 704 switch (ev->key) { 705 case KC_LEFT: 706 tinput_seek_cell(ti, seek_backward, true); 707 break; 708 case KC_RIGHT: 709 tinput_seek_cell(ti, seek_forward, true); 710 break; 711 case KC_UP: 712 tinput_seek_vertical(ti, seek_backward, true); 713 break; 714 case KC_DOWN: 715 tinput_seek_vertical(ti, seek_forward, true); 716 break; 717 case KC_HOME: 718 tinput_seek_max(ti, seek_backward, true); 719 break; 720 case KC_END: 721 tinput_seek_max(ti, seek_forward, true); 722 break; 723 default: 724 break; 725 } 726 } 727 728 static void tinput_key_unmod(tinput_t *ti, console_event_t *ev) 729 { 730 switch (ev->key) { 731 case KC_ENTER: 732 case KC_NENTER: 733 ti->done = true; 734 break; 735 case KC_BACKSPACE: 736 tinput_backspace(ti); 737 break; 738 case KC_DELETE: 739 tinput_delete(ti); 740 break; 741 case KC_LEFT: 742 tinput_seek_cell(ti, seek_backward, false); 743 break; 744 case KC_RIGHT: 745 tinput_seek_cell(ti, seek_forward, false); 746 break; 747 case KC_HOME: 748 tinput_seek_max(ti, seek_backward, false); 749 break; 750 case KC_END: 751 tinput_seek_max(ti, seek_forward, false); 752 break; 753 case KC_UP: 754 tinput_history_seek(ti, +1); 755 break; 756 case KC_DOWN: 757 tinput_history_seek(ti, -1); 758 break; 759 default: 760 break; 761 } 762 } 763 106 764 void get_input(cliuser_t *usr) 107 765 { … … 114 772 console_set_style(fphone(stdout), STYLE_NORMAL); 115 773 116 str = tinput_read( tinput);774 str = tinput_read(&tinput); 117 775 118 776 /* Check for empty input. */ … … 126 784 } 127 785 128 int input_init(void) 129 { 130 tinput = tinput_new(); 131 if (tinput == NULL) { 132 printf("Failed to initialize input.\n"); 133 return 1; 134 } 135 136 return 0; 137 } 786 void input_init(void) 787 { 788 tinput_init(&tinput); 789 }
Note:
See TracChangeset
for help on using the changeset viewer.