Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/input.c

    rbc77bfa r3041fef1  
    3636#include <io/keycode.h>
    3737#include <io/style.h>
    38 #include <io/color.h>
    3938#include <vfs/vfs.h>
    40 #include <clipboard.h>
    41 #include <macros.h>
    4239#include <errno.h>
    4340#include <assert.h>
     
    5350#define HISTORY_LEN 10
    5451
    55 /** Text input field. */
    5652typedef 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 */
     53        wchar_t buffer[INPUT_MAX];
    6054        int col0, row0;
    61         /** Screen dimensions */
    6255        int con_cols, con_rows;
    63         /** Number of characters in @c buffer */
    6456        int nc;
    65         /** Caret position within buffer */
    6657        int pos;
    67         /** Selection mark position within buffer */
    68         int sel_start;
    69 
    70         /** History (dynamically allocated strings) */
     58
    7159        char *history[1 + HISTORY_LEN];
    72         /** Number of entries in @c history, not counting [0] */
    7360        int hnum;
    74         /** Current position in history */
    7561        int hpos;
    76         /** Exit flag */
    77         bool done;
    7862} tinput_t;
    7963
    80 /** Seek direction */
    8164typedef enum {
    8265        seek_backward = -1,
     
    8770
    8871static 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);
    10072
    10173/* Tokenizes input from console, sees if the first word is a built-in, if so
     
    151123static void tinput_display_tail(tinput_t *ti, int start, int pad)
    152124{
    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);
     125        int i;
    158126
    159127        console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols,
    160128            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 
     129        printf("%ls", ti->buffer + start);
    191130        for (i = 0; i < pad; ++i)
    192131                putchar(' ');
     
    212151        width = ti->col0 + ti->nc;
    213152        rows = (width / ti->con_cols) + 1;
    214 
     153 
    215154        /* Update row0 if the screen scrolled. */
    216155        if (ti->row0 + rows > ti->con_rows)
     
    241180        ti->nc += 1;
    242181        ti->buffer[ti->nc] = '\0';
    243         ti->sel_start = ti->pos;
    244182
    245183        tinput_display_tail(ti, ti->pos - 1, 0);
     
    248186}
    249187
    250 static void tinput_insert_string(tinput_t *ti, const char *str)
     188static void tinput_backspace(tinput_t *ti)
    251189{
    252190        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         }
    302191
    303192        if (ti->pos == 0)
     
    309198        ti->nc -= 1;
    310199        ti->buffer[ti->nc] = '\0';
    311         ti->sel_start = ti->pos;
    312200
    313201        tinput_display_tail(ti, ti->pos, 1);
     
    317205static void tinput_delete(tinput_t *ti)
    318206{
    319         if (tinput_sel_active(ti)) {
    320                 tinput_sel_delete(ti);
    321                 return;
    322         }
    323 
    324207        if (ti->pos == ti->nc)
    325208                return;
    326209
    327210        ti->pos += 1;
    328         ti->sel_start = ti->pos;
    329 
    330211        tinput_backspace(ti);
    331212}
    332213
    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 
     214static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir)
     215{
    337216        if (dir == seek_forward) {
    338217                if (ti->pos < ti->nc)
     
    343222        }
    344223
    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 
     224        tinput_position_caret(ti);
     225}
     226
     227static void tinput_seek_word(tinput_t *ti, seek_dir_t dir)
     228{
    352229        if (dir == seek_forward) {
    353230                if (ti->pos == ti->nc)
     
    381258        }
    382259
    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 
     260        tinput_position_caret(ti);
     261}
     262
     263static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir)
     264{
    390265        if (dir == seek_forward) {
    391266                if (ti->pos + ti->con_cols <= ti->nc)
     
    396271        }
    397272
    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 
     273        tinput_position_caret(ti);
     274}
     275
     276static void tinput_seek_max(tinput_t *ti, seek_dir_t dir)
     277{
    405278        if (dir == seek_backward)
    406279                ti->pos = 0;
     
    408281                ti->pos = ti->nc;
    409282
    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         }
    432283        tinput_position_caret(ti);
    433284}
     
    460311        ti->nc = wstr_length(ti->buffer);
    461312        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);
    549313}
    550314
     
    573337}
    574338
    575 /** Initialize text input field.
    576  *
    577  * Must be called before using the field. It clears the history.
    578  */
    579339static void tinput_init(tinput_t *ti)
    580340{
     
    584344}
    585345
    586 /** Read in one line of input. */
    587346static char *tinput_read(tinput_t *ti)
    588347{
     
    597356                return NULL;
    598357
    599         ti->pos = ti->sel_start = 0;
     358        ti->pos = 0;
    600359        ti->nc = 0;
    601360        ti->buffer[0] = '\0';
    602         ti->done = false;
    603 
    604         while (!ti->done) {
     361
     362        while (true) {
    605363                fflush(stdout);
    606364                if (!console_get_event(fphone(stdin), &ev))
    607365                        return NULL;
    608 
     366               
    609367                if (ev.type != KEY_PRESS)
    610368                        continue;
     
    612370                if ((ev.mods & KM_CTRL) != 0 &&
    613371                    (ev.mods & (KM_ALT | KM_SHIFT)) == 0) {
    614                         tinput_key_ctrl(ti, &ev);
     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                        }
    615386                }
    616387
    617                 if ((ev.mods & KM_SHIFT) != 0 &&
    618                     (ev.mods & (KM_CTRL | KM_ALT)) == 0) {
    619                         tinput_key_shift(ti, &ev);
     388                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                        }
    620418                }
    621419
    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 
    632420                if (ev.c >= ' ') {
    633                         tinput_sel_delete(ti);
    634421                        tinput_insert_char(ti, ev.c);
    635422                }
    636423        }
    637424
     425done:
    638426        ti->pos = ti->nc;
    639427        tinput_position_caret(ti);
     
    647435
    648436        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         }
    765437}
    766438
Note: See TracChangeset for help on using the changeset viewer.