Changes in uspace/app/bdsh/input.c [19f857a:36a75a2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/bdsh/input.c
r19f857a r36a75a2 1 1 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> 2 2 * All rights reserved. 3 * Copyright (c) 2008, Jiri Svoboda - All Rights Reserved4 3 * 5 4 * Redistribution and use in source and binary forms, with or without … … 43 42 #include <assert.h> 44 43 #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 1054 55 53 /** Text input field. */ 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); 54 static tinput_t *tinput; 100 55 101 56 /* Tokenizes input from console, sees if the first word is a built-in, if so … … 149 104 } 150 105 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 else408 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 } else520 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 764 106 void get_input(cliuser_t *usr) 765 107 { … … 772 114 console_set_style(fphone(stdout), STYLE_NORMAL); 773 115 774 str = tinput_read( &tinput);116 str = tinput_read(tinput); 775 117 776 118 /* Check for empty input. */ … … 784 126 } 785 127 786 voidinput_init(void)128 int input_init(void) 787 129 { 788 tinput_init(&tinput); 130 tinput = tinput_new(); 131 if (tinput == NULL) { 132 printf("Failed to initialize input.\n"); 133 return 1; 134 } 135 136 return 0; 789 137 }
Note:
See TracChangeset
for help on using the changeset viewer.