Changes in uspace/app/bdsh/input.c [bc77bfa:5db9084] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/bdsh/input.c
rbc77bfa r5db9084 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 … … 32 31 #include <stdio.h> 33 32 #include <stdlib.h> 34 #include <str ing.h>33 #include <str.h> 35 34 #include <io/console.h> 36 35 #include <io/keycode.h> … … 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 10 53 extern volatile unsigned int cli_quit; 54 54 55 55 /** 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); 56 static tinput_t *tinput; 100 57 101 58 /* Tokenizes input from console, sees if the first word is a built-in, if so … … 149 106 } 150 107 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 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) 108 void get_input(cliuser_t *usr) 539 109 { 540 110 char *str; 541 111 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);549 }550 551 static void tinput_history_seek(tinput_t *ti, int offs)552 {553 int pad;554 555 if (ti->hpos + offs < 0 || ti->hpos + offs > ti->hnum)556 return;557 558 if (ti->history[ti->hpos] != NULL) {559 free(ti->history[ti->hpos]);560 ti->history[ti->hpos] = NULL;561 }562 563 ti->history[ti->hpos] = tinput_get_str(ti);564 ti->hpos += offs;565 566 pad = ti->nc - str_length(ti->history[ti->hpos]);567 if (pad < 0) pad = 0;568 569 tinput_set_str(ti, ti->history[ti->hpos]);570 tinput_display_tail(ti, 0, pad);571 tinput_update_origin(ti);572 tinput_position_caret(ti);573 }574 575 /** Initialize text input field.576 *577 * Must be called before using the field. It clears the history.578 */579 static void tinput_init(tinput_t *ti)580 {581 ti->hnum = 0;582 ti->hpos = 0;583 ti->history[0] = NULL;584 }585 586 /** Read in one line of input. */587 static char *tinput_read(tinput_t *ti)588 {589 console_event_t ev;590 char *str;591 592 fflush(stdout);593 594 if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)595 return NULL;596 if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)597 return NULL;598 599 ti->pos = ti->sel_start = 0;600 ti->nc = 0;601 ti->buffer[0] = '\0';602 ti->done = false;603 604 while (!ti->done) {605 fflush(stdout);606 if (!console_get_event(fphone(stdin), &ev))607 return NULL;608 609 if (ev.type != KEY_PRESS)610 continue;611 612 if ((ev.mods & KM_CTRL) != 0 &&613 (ev.mods & (KM_ALT | KM_SHIFT)) == 0) {614 tinput_key_ctrl(ti, &ev);615 }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 628 if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {629 tinput_key_unmod(ti, &ev);630 }631 632 if (ev.c >= ' ') {633 tinput_sel_delete(ti);634 tinput_insert_char(ti, ev.c);635 }636 }637 638 ti->pos = ti->nc;639 tinput_position_caret(ti);640 putchar('\n');641 642 str = tinput_get_str(ti);643 if (str_cmp(str, "") != 0)644 tinput_history_insert(ti, str);645 646 ti->hpos = 0;647 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 }765 }766 767 void get_input(cliuser_t *usr)768 {769 char *str;770 112 771 113 fflush(stdout); … … 775 117 console_set_style(fphone(stdout), STYLE_NORMAL); 776 118 777 str = tinput_read(&tinput); 119 rc = tinput_read(tinput, &str); 120 if (rc == ENOENT) { 121 /* User requested exit */ 122 cli_quit = 1; 123 putchar('\n'); 124 return; 125 } 126 127 if (rc != EOK) { 128 /* Error in communication with console */ 129 return; 130 } 778 131 779 132 /* Check for empty input. */ … … 787 140 } 788 141 789 voidinput_init(void)142 int input_init(void) 790 143 { 791 tinput_init(&tinput); 144 tinput = tinput_new(); 145 if (tinput == NULL) { 146 printf("Failed to initialize input.\n"); 147 return 1; 148 } 149 150 return 0; 792 151 }
Note:
See TracChangeset
for help on using the changeset viewer.