Changes in uspace/app/bdsh/input.c [3041fef1:bc77bfa] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/bdsh/input.c
r3041fef1 rbc77bfa 36 36 #include <io/keycode.h> 37 37 #include <io/style.h> 38 #include <io/color.h> 38 39 #include <vfs/vfs.h> 40 #include <clipboard.h> 41 #include <macros.h> 39 42 #include <errno.h> 40 43 #include <assert.h> … … 50 53 #define HISTORY_LEN 10 51 54 55 /** Text input field. */ 52 56 typedef struct { 53 wchar_t buffer[INPUT_MAX]; 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 */ 54 60 int col0, row0; 61 /** Screen dimensions */ 55 62 int con_cols, con_rows; 63 /** Number of characters in @c buffer */ 56 64 int nc; 65 /** Caret position within buffer */ 57 66 int pos; 58 67 /** Selection mark position within buffer */ 68 int sel_start; 69 70 /** History (dynamically allocated strings) */ 59 71 char *history[1 + HISTORY_LEN]; 72 /** Number of entries in @c history, not counting [0] */ 60 73 int hnum; 74 /** Current position in history */ 61 75 int hpos; 76 /** Exit flag */ 77 bool done; 62 78 } tinput_t; 63 79 80 /** Seek direction */ 64 81 typedef enum { 65 82 seek_backward = -1, … … 70 87 71 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); 72 100 73 101 /* Tokenizes input from console, sees if the first word is a built-in, if so … … 123 151 static void tinput_display_tail(tinput_t *ti, int start, int pad) 124 152 { 125 int i; 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); 126 158 127 159 console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols, 128 160 ti->row0 + (ti->col0 + start) / ti->con_cols); 129 printf("%ls", ti->buffer + start); 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 130 191 for (i = 0; i < pad; ++i) 131 192 putchar(' '); … … 151 212 width = ti->col0 + ti->nc; 152 213 rows = (width / ti->con_cols) + 1; 153 214 154 215 /* Update row0 if the screen scrolled. */ 155 216 if (ti->row0 + rows > ti->con_rows) … … 180 241 ti->nc += 1; 181 242 ti->buffer[ti->nc] = '\0'; 243 ti->sel_start = ti->pos; 182 244 183 245 tinput_display_tail(ti, ti->pos - 1, 0); … … 186 248 } 187 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 188 294 static void tinput_backspace(tinput_t *ti) 189 295 { 190 296 int i; 297 298 if (tinput_sel_active(ti)) { 299 tinput_sel_delete(ti); 300 return; 301 } 191 302 192 303 if (ti->pos == 0) … … 198 309 ti->nc -= 1; 199 310 ti->buffer[ti->nc] = '\0'; 311 ti->sel_start = ti->pos; 200 312 201 313 tinput_display_tail(ti, ti->pos, 1); … … 205 317 static void tinput_delete(tinput_t *ti) 206 318 { 319 if (tinput_sel_active(ti)) { 320 tinput_sel_delete(ti); 321 return; 322 } 323 207 324 if (ti->pos == ti->nc) 208 325 return; 209 326 210 327 ti->pos += 1; 328 ti->sel_start = ti->pos; 329 211 330 tinput_backspace(ti); 212 331 } 213 332 214 static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir) 215 { 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 216 337 if (dir == seek_forward) { 217 338 if (ti->pos < ti->nc) … … 222 343 } 223 344 224 tinput_position_caret(ti); 225 } 226 227 static void tinput_seek_word(tinput_t *ti, seek_dir_t dir) 228 { 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 229 352 if (dir == seek_forward) { 230 353 if (ti->pos == ti->nc) … … 258 381 } 259 382 260 tinput_position_caret(ti); 261 } 262 263 static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir) 264 { 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 265 390 if (dir == seek_forward) { 266 391 if (ti->pos + ti->con_cols <= ti->nc) … … 271 396 } 272 397 273 tinput_position_caret(ti); 274 } 275 276 static void tinput_seek_max(tinput_t *ti, seek_dir_t dir) 277 { 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 278 405 if (dir == seek_backward) 279 406 ti->pos = 0; … … 281 408 ti->pos = ti->nc; 282 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 } 283 432 tinput_position_caret(ti); 284 433 } … … 311 460 ti->nc = wstr_length(ti->buffer); 312 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 wchar_t tmp_c; 511 char *str; 512 513 tinput_sel_get_bounds(ti, &sa, &sb); 514 515 if (sb < ti->nc) { 516 tmp_c = ti->buffer[sb]; 517 ti->buffer[sb] = '\0'; 518 } 519 520 str = wstr_to_astr(ti->buffer + sa); 521 522 if (sb < ti->nc) 523 ti->buffer[sb] = tmp_c; 524 525 if (str == NULL) 526 goto error; 527 528 if (clipboard_put_str(str) != EOK) 529 goto error; 530 531 free(str); 532 return; 533 error: 534 return; 535 /* TODO: Give the user some warning. */ 536 } 537 538 static void tinput_paste_from_cb(tinput_t *ti) 539 { 540 char *str; 541 int rc; 542 543 rc = clipboard_get_str(&str); 544 if (rc != EOK || str == NULL) 545 return; /* TODO: Give the user some warning. */ 546 547 tinput_insert_string(ti, str); 548 free(str); 313 549 } 314 550 … … 337 573 } 338 574 575 /** Initialize text input field. 576 * 577 * Must be called before using the field. It clears the history. 578 */ 339 579 static void tinput_init(tinput_t *ti) 340 580 { … … 344 584 } 345 585 586 /** Read in one line of input. */ 346 587 static char *tinput_read(tinput_t *ti) 347 588 { … … 356 597 return NULL; 357 598 358 ti->pos = 0;599 ti->pos = ti->sel_start = 0; 359 600 ti->nc = 0; 360 601 ti->buffer[0] = '\0'; 361 362 while (true) { 602 ti->done = false; 603 604 while (!ti->done) { 363 605 fflush(stdout); 364 606 if (!console_get_event(fphone(stdin), &ev)) 365 607 return NULL; 366 608 367 609 if (ev.type != KEY_PRESS) 368 610 continue; … … 370 612 if ((ev.mods & KM_CTRL) != 0 && 371 613 (ev.mods & (KM_ALT | KM_SHIFT)) == 0) { 372 switch (ev.key) { 373 case KC_LEFT: 374 tinput_seek_word(ti, seek_backward); 375 break; 376 case KC_RIGHT: 377 tinput_seek_word(ti, seek_forward); 378 break; 379 case KC_UP: 380 tinput_seek_vertical(ti, seek_backward); 381 break; 382 case KC_DOWN: 383 tinput_seek_vertical(ti, seek_forward); 384 break; 385 } 614 tinput_key_ctrl(ti, &ev); 386 615 } 387 616 617 if ((ev.mods & KM_SHIFT) != 0 && 618 (ev.mods & (KM_CTRL | KM_ALT)) == 0) { 619 tinput_key_shift(ti, &ev); 620 } 621 622 if ((ev.mods & KM_CTRL) != 0 && 623 (ev.mods & KM_SHIFT) != 0 && 624 (ev.mods & KM_ALT) == 0) { 625 tinput_key_ctrl_shift(ti, &ev); 626 } 627 388 628 if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) { 389 switch (ev.key) { 390 case KC_ENTER: 391 case KC_NENTER: 392 goto done; 393 case KC_BACKSPACE: 394 tinput_backspace(ti); 395 break; 396 case KC_DELETE: 397 tinput_delete(ti); 398 break; 399 case KC_LEFT: 400 tinput_seek_cell(ti, seek_backward); 401 break; 402 case KC_RIGHT: 403 tinput_seek_cell(ti, seek_forward); 404 break; 405 case KC_HOME: 406 tinput_seek_max(ti, seek_backward); 407 break; 408 case KC_END: 409 tinput_seek_max(ti, seek_forward); 410 break; 411 case KC_UP: 412 tinput_history_seek(ti, +1); 413 break; 414 case KC_DOWN: 415 tinput_history_seek(ti, -1); 416 break; 417 } 629 tinput_key_unmod(ti, &ev); 418 630 } 419 631 420 632 if (ev.c >= ' ') { 633 tinput_sel_delete(ti); 421 634 tinput_insert_char(ti, ev.c); 422 635 } 423 636 } 424 637 425 done:426 638 ti->pos = ti->nc; 427 639 tinput_position_caret(ti); … … 435 647 436 648 return str; 649 } 650 651 static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev) 652 { 653 switch (ev->key) { 654 case KC_LEFT: 655 tinput_seek_word(ti, seek_backward, false); 656 break; 657 case KC_RIGHT: 658 tinput_seek_word(ti, seek_forward, false); 659 break; 660 case KC_UP: 661 tinput_seek_vertical(ti, seek_backward, false); 662 break; 663 case KC_DOWN: 664 tinput_seek_vertical(ti, seek_forward, false); 665 break; 666 case KC_X: 667 tinput_sel_copy_to_cb(ti); 668 tinput_sel_delete(ti); 669 break; 670 case KC_C: 671 tinput_sel_copy_to_cb(ti); 672 break; 673 case KC_V: 674 tinput_sel_delete(ti); 675 tinput_paste_from_cb(ti); 676 break; 677 case KC_A: 678 tinput_sel_all(ti); 679 break; 680 default: 681 break; 682 } 683 } 684 685 static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev) 686 { 687 switch (ev->key) { 688 case KC_LEFT: 689 tinput_seek_word(ti, seek_backward, true); 690 break; 691 case KC_RIGHT: 692 tinput_seek_word(ti, seek_forward, true); 693 break; 694 case KC_UP: 695 tinput_seek_vertical(ti, seek_backward, true); 696 break; 697 case KC_DOWN: 698 tinput_seek_vertical(ti, seek_forward, true); 699 break; 700 default: 701 break; 702 } 703 } 704 705 static void tinput_key_shift(tinput_t *ti, console_event_t *ev) 706 { 707 switch (ev->key) { 708 case KC_LEFT: 709 tinput_seek_cell(ti, seek_backward, true); 710 break; 711 case KC_RIGHT: 712 tinput_seek_cell(ti, seek_forward, true); 713 break; 714 case KC_UP: 715 tinput_seek_vertical(ti, seek_backward, true); 716 break; 717 case KC_DOWN: 718 tinput_seek_vertical(ti, seek_forward, true); 719 break; 720 case KC_HOME: 721 tinput_seek_max(ti, seek_backward, true); 722 break; 723 case KC_END: 724 tinput_seek_max(ti, seek_forward, true); 725 break; 726 default: 727 break; 728 } 729 } 730 731 static void tinput_key_unmod(tinput_t *ti, console_event_t *ev) 732 { 733 switch (ev->key) { 734 case KC_ENTER: 735 case KC_NENTER: 736 ti->done = true; 737 break; 738 case KC_BACKSPACE: 739 tinput_backspace(ti); 740 break; 741 case KC_DELETE: 742 tinput_delete(ti); 743 break; 744 case KC_LEFT: 745 tinput_seek_cell(ti, seek_backward, false); 746 break; 747 case KC_RIGHT: 748 tinput_seek_cell(ti, seek_forward, false); 749 break; 750 case KC_HOME: 751 tinput_seek_max(ti, seek_backward, false); 752 break; 753 case KC_END: 754 tinput_seek_max(ti, seek_forward, false); 755 break; 756 case KC_UP: 757 tinput_history_seek(ti, +1); 758 break; 759 case KC_DOWN: 760 tinput_history_seek(ti, -1); 761 break; 762 default: 763 break; 764 } 437 765 } 438 766
Note:
See TracChangeset
for help on using the changeset viewer.