Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/console/console.c

    r28a5ebd r5d1ff11  
    11/*
     2 * Copyright (c) 2021 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Decky
    34 * All rights reserved.
     
    6263typedef struct {
    6364        atomic_flag refcnt;      /**< Connection reference count */
    64         prodcons_t input_pc;  /**< Incoming keyboard events */
     65        prodcons_t input_pc;  /**< Incoming console events */
    6566
    6667        /**
     
    7980        console_caps_t ccaps;  /**< Console capabilities */
    8081
     82        sysarg_t ucols;         /**< Number of columns in user buffer */
     83        sysarg_t urows;         /**< Number of rows in user buffer */
     84        charfield_t *ubuf;      /**< User buffer */
     85
    8186        chargrid_t *frontbuf;    /**< Front buffer */
    8287        frontbuf_handle_t fbid;  /**< Front buffer handle */
     
    9499static sysarg_t cols;
    95100static sysarg_t rows;
     101
     102/** Mouse pointer X coordinate */
     103static int pointer_x;
     104/** Mouse pointer Y coordinate */
     105static int pointer_y;
     106/** Character under mouse cursor */
     107static charfield_t pointer_bg;
     108
     109static int mouse_scale_x = 4;
     110static int mouse_scale_y = 8;
    96111
    97112/** Array of data for virtual consoles */
     
    135150static void cons_set_cursor_visibility(con_srv_t *, bool);
    136151static errno_t cons_get_event(con_srv_t *, cons_event_t *);
     152static errno_t cons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
     153static void cons_unmap(con_srv_t *);
     154static void cons_buf_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
     155    sysarg_t);
    137156
    138157static con_ops_t con_ops = {
     
    151170        .set_rgb_color = cons_set_rgb_color,
    152171        .set_cursor_visibility = cons_set_cursor_visibility,
    153         .get_event = cons_get_event
     172        .get_event = cons_get_event,
     173        .map = cons_map,
     174        .unmap = cons_unmap,
     175        .update = cons_buf_update
    154176};
     177
     178static void pointer_draw(void);
     179static void pointer_undraw(void);
    155180
    156181static console_t *srv_to_console(con_srv_t *srv)
     
    219244
    220245        fibril_mutex_lock(&switch_mtx);
     246        pointer_undraw();
    221247
    222248        if (cons == active_console) {
     
    227253        active_console = cons;
    228254
     255        pointer_draw();
    229256        fibril_mutex_unlock(&switch_mtx);
    230257
    231258        cons_damage(cons);
     259}
     260
     261/** Draw mouse pointer. */
     262static void pointer_draw(void)
     263{
     264        charfield_t *ch;
     265        int col, row;
     266
     267        /* Downscale coordinates to text resolution */
     268        col = pointer_x / mouse_scale_x;
     269        row = pointer_y / mouse_scale_y;
     270
     271        /* Make sure they are in range */
     272        if (col < 0 || row < 0 || col >= (int)cols || row >= (int)rows)
     273                return;
     274
     275        ch = chargrid_charfield_at(active_console->frontbuf, col, row);
     276
     277        /*
     278         * Store background attributes for undrawing the pointer.
     279         * This is necessary as styles cannot be inverted with
     280         * round trip (unlike RGB or INDEX)
     281         */
     282        pointer_bg = *ch;
     283
     284        /* In general the color should be a one's complement of the background */
     285        if (ch->attrs.type == CHAR_ATTR_INDEX) {
     286                ch->attrs.val.index.bgcolor ^= 0xf;
     287                ch->attrs.val.index.fgcolor ^= 0xf;
     288        } else if (ch->attrs.type == CHAR_ATTR_RGB) {
     289                ch->attrs.val.rgb.fgcolor ^= 0xffffff;
     290                ch->attrs.val.rgb.bgcolor ^= 0xffffff;
     291        } else if (ch->attrs.type == CHAR_ATTR_STYLE) {
     292                /* Don't have a proper inverse for each style */
     293                if (ch->attrs.val.style == STYLE_INVERTED)
     294                        ch->attrs.val.style = STYLE_NORMAL;
     295                else
     296                        ch->attrs.val.style = STYLE_INVERTED;
     297        }
     298
     299        /* Make sure the cell gets updated */
     300        ch->flags |= CHAR_FLAG_DIRTY;
     301}
     302
     303/** Undraw mouse pointer. */
     304static void pointer_undraw(void)
     305{
     306        charfield_t *ch;
     307        int col, row;
     308
     309        col = pointer_x / mouse_scale_x;
     310        row = pointer_y / mouse_scale_y;
     311        if (col < 0 || row < 0 || col >= (int)cols || row >= (int)rows)
     312                return;
     313
     314        ch = chargrid_charfield_at(active_console->frontbuf, col, row);
     315        *ch = pointer_bg;
     316        ch->flags |= CHAR_FLAG_DIRTY;
     317}
     318
     319/** Queue console event.
     320 *
     321 * @param cons Console
     322 * @param ev Console event
     323 */
     324static void console_queue_cons_event(console_t *cons, cons_event_t *ev)
     325{
     326        /* Got key press/release event */
     327        cons_event_t *event =
     328            (cons_event_t *) malloc(sizeof(cons_event_t));
     329        if (event == NULL)
     330                return;
     331
     332        *event = *ev;
     333        link_initialize(&event->link);
     334
     335        prodcons_produce(&cons->input_pc, &event->link);
    232336}
    233337
     
    252356    keymod_t mods, char32_t c)
    253357{
     358        cons_event_t event;
     359
    254360        if ((key >= KC_F1) && (key <= KC_F1 + CONSOLE_COUNT) &&
    255361            ((mods & KM_CTRL) == 0)) {
     
    257363        } else {
    258364                /* Got key press/release event */
    259                 kbd_event_t *event =
    260                     (kbd_event_t *) malloc(sizeof(kbd_event_t));
    261                 if (event == NULL) {
    262                         return ENOMEM;
    263                 }
    264 
    265                 link_initialize(&event->link);
    266                 event->type = type;
    267                 event->key = key;
    268                 event->mods = mods;
    269                 event->c = c;
    270 
    271                 prodcons_produce(&active_console->input_pc,
    272                     &event->link);
    273         }
    274 
    275         return EOK;
     365                event.type = CEV_KEY;
     366
     367                event.ev.key.type = type;
     368                event.ev.key.key = key;
     369                event.ev.key.mods = mods;
     370                event.ev.key.c = c;
     371
     372                console_queue_cons_event(active_console, &event);
     373        }
     374
     375        return EOK;
     376}
     377
     378/** Update pointer position.
     379 *
     380 * @param new_x New X coordinate (in pixels)
     381 * @param new_y New Y coordinate (in pixels)
     382 */
     383static void pointer_update(int new_x, int new_y)
     384{
     385        bool upd_pointer;
     386
     387        /* Make sure coordinates are in range */
     388
     389        if (new_x < 0)
     390                new_x = 0;
     391        if (new_x >= (int)cols * mouse_scale_x)
     392                new_x = cols * mouse_scale_x - 1;
     393        if (new_y < 0)
     394                new_y = 0;
     395        if (new_y >= (int)rows * mouse_scale_y)
     396                new_y = rows * mouse_scale_y - 1;
     397
     398        /* Determine if pointer moved to a different character cell */
     399        upd_pointer = (new_x / mouse_scale_x != pointer_x / mouse_scale_x) ||
     400            (new_y / mouse_scale_y != pointer_y / mouse_scale_y);
     401
     402        if (upd_pointer)
     403                pointer_undraw();
     404
     405        /* Store new pointer position */
     406        pointer_x = new_x;
     407        pointer_y = new_y;
     408
     409        if (upd_pointer) {
     410                pointer_draw();
     411                cons_update(active_console);
     412        }
    276413}
    277414
    278415static errno_t input_ev_move(input_t *input, int dx, int dy)
    279416{
     417        pointer_update(pointer_x + dx, pointer_y + dy);
    280418        return EOK;
    281419}
     
    284422    unsigned max_x, unsigned max_y)
    285423{
     424        pointer_update(mouse_scale_x * cols * x / max_x, mouse_scale_y * rows * y / max_y);
    286425        return EOK;
    287426}
     
    289428static errno_t input_ev_button(input_t *input, int bnum, int bpress)
    290429{
     430        cons_event_t event;
     431
     432        event.type = CEV_POS;
     433        event.ev.pos.type = bpress ? POS_PRESS : POS_RELEASE;
     434        event.ev.pos.btn_num = bnum;
     435        event.ev.pos.hpos = pointer_x / mouse_scale_x;
     436        event.ev.pos.vpos = pointer_y / mouse_scale_y;
     437
     438        console_queue_cons_event(active_console, &event);
    291439        return EOK;
    292440}
     
    298446
    299447        fibril_mutex_lock(&cons->mtx);
     448        pointer_undraw();
    300449
    301450        switch (ch) {
     
    315464        }
    316465
     466        pointer_draw();
    317467        fibril_mutex_unlock(&cons->mtx);
    318468
     
    324474{
    325475        fibril_mutex_lock(&cons->mtx);
     476        pointer_undraw();
    326477        chargrid_set_cursor_visibility(cons->frontbuf, visible);
     478        pointer_draw();
    327479        fibril_mutex_unlock(&cons->mtx);
    328480
     
    367519                if (pos < size) {
    368520                        link_t *link = prodcons_consume(&cons->input_pc);
    369                         kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     521                        cons_event_t *event = list_get_instance(link,
     522                            cons_event_t, link);
    370523
    371524                        /* Accept key presses of printable chars only. */
    372                         if ((event->type == KEY_PRESS) && (event->c != 0)) {
    373                                 char32_t tmp[2] = { event->c, 0 };
     525                        if (event->type == CEV_KEY && event->ev.key.type == KEY_PRESS &&
     526                            (event->ev.key.c != 0)) {
     527                                char32_t tmp[2] = { event->ev.key.c, 0 };
    374528                                wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
    375529                                cons->char_remains_len = str_size(cons->char_remains);
     
    408562
    409563        fibril_mutex_lock(&cons->mtx);
     564        pointer_undraw();
    410565        chargrid_clear(cons->frontbuf);
     566        pointer_draw();
    411567        fibril_mutex_unlock(&cons->mtx);
    412568
     
    419575
    420576        fibril_mutex_lock(&cons->mtx);
     577        pointer_undraw();
    421578        chargrid_set_cursor(cons->frontbuf, col, row);
     579        pointer_draw();
    422580        fibril_mutex_unlock(&cons->mtx);
    423581
     
    499657        console_t *cons = srv_to_console(srv);
    500658        link_t *link = prodcons_consume(&cons->input_pc);
    501         kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
    502 
    503         event->type = CEV_KEY;
    504         event->ev.key = *kevent;
    505 
    506         free(kevent);
    507         return EOK;
     659        cons_event_t *cevent = list_get_instance(link, cons_event_t, link);
     660
     661        *event = *cevent;
     662        free(cevent);
     663        return EOK;
     664}
     665
     666/** Create shared buffer for efficient rendering.
     667 *
     668 * @param srv Console server
     669 * @param cols Number of columns in buffer
     670 * @param rows Number of rows in buffer
     671 * @param rbuf Place to store pointer to new sharable buffer
     672 *
     673 * @return EOK on sucess or an error code
     674 */
     675static errno_t cons_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
     676    charfield_t **rbuf)
     677{
     678        console_t *cons = srv_to_console(srv);
     679        void *buf;
     680
     681        fibril_mutex_lock(&cons->mtx);
     682
     683        if (cons->ubuf != NULL) {
     684                fibril_mutex_unlock(&cons->mtx);
     685                return EBUSY;
     686        }
     687
     688        buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
     689            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
     690        if (buf == AS_MAP_FAILED) {
     691                fibril_mutex_unlock(&cons->mtx);
     692                return ENOMEM;
     693        }
     694
     695        cons->ucols = cols;
     696        cons->urows = rows;
     697        cons->ubuf = buf;
     698        fibril_mutex_unlock(&cons->mtx);
     699
     700        *rbuf = buf;
     701        return EOK;
     702}
     703
     704/** Delete shared buffer.
     705 *
     706 * @param srv Console server
     707 */
     708static void cons_unmap(con_srv_t *srv)
     709{
     710        console_t *cons = srv_to_console(srv);
     711        void *buf;
     712
     713        fibril_mutex_lock(&cons->mtx);
     714
     715        buf = cons->ubuf;
     716        cons->ubuf = NULL;
     717
     718        if (buf != NULL)
     719                as_area_destroy(buf);
     720
     721        fibril_mutex_unlock(&cons->mtx);
     722}
     723
     724/** Update area of console from shared buffer.
     725 *
     726 * @param srv Console server
     727 * @param c0 Column coordinate of top-left corner (inclusive)
     728 * @param r0 Row coordinate of top-left corner (inclusive)
     729 * @param c1 Column coordinate of bottom-right corner (exclusive)
     730 * @param r1 Row coordinate of bottom-right corner (exclusive)
     731 */
     732static void cons_buf_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
     733    sysarg_t c1, sysarg_t r1)
     734{
     735        console_t *cons = srv_to_console(srv);
     736        charfield_t *ch;
     737        sysarg_t col, row;
     738
     739        fibril_mutex_lock(&cons->mtx);
     740
     741        if (cons->ubuf == NULL) {
     742                fibril_mutex_unlock(&cons->mtx);
     743                return;
     744        }
     745
     746        /* Make sure we have meaningful coordinates, within bounds */
     747
     748        if (c1 > cons->ucols)
     749                c1 = cons->ucols;
     750        if (c1 > cons->cols)
     751                c1 = cons->cols;
     752        if (c0 >= c1) {
     753                fibril_mutex_unlock(&cons->mtx);
     754                return;
     755        }
     756        if (r1 > cons->urows)
     757                r1 = cons->urows;
     758        if (r1 > cons->rows)
     759                r1 = cons->rows;
     760        if (r0 >= r1) {
     761                fibril_mutex_unlock(&cons->mtx);
     762                return;
     763        }
     764
     765        /* Update front buffer from user buffer */
     766
     767        pointer_undraw();
     768
     769        for (row = r0; row < r1; row++) {
     770                for (col = c0; col < c1; col++) {
     771                        ch = chargrid_charfield_at(cons->frontbuf, col, row);
     772                        *ch = cons->ubuf[row * cons->ucols + col];
     773                }
     774        }
     775
     776        pointer_draw();
     777        fibril_mutex_unlock(&cons->mtx);
     778
     779        /* Update console */
     780        cons_update(cons);
    508781}
    509782
     
    649922
    650923                input_activate(input);
     924                active = true;
     925                cons_damage(active_console);
    651926        }
    652927
Note: See TracChangeset for help on using the changeset viewer.