Ignore:
File:
1 edited

Legend:

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

    r1a96db9 r28a5ebd  
    11/*
    2  * Copyright (c) 2025 Jiri Svoboda
    32 * Copyright (c) 2011 Martin Decky
    43 * All rights reserved.
     
    3736#include <stdio.h>
    3837#include <adt/prodcons.h>
    39 #include <io/console.h>
    4038#include <io/input.h>
    4139#include <ipc/vfs.h>
     
    6462typedef struct {
    6563        atomic_flag refcnt;      /**< Connection reference count */
    66         prodcons_t input_pc;  /**< Incoming console events */
     64        prodcons_t input_pc;  /**< Incoming keyboard events */
    6765
    6866        /**
     
    8179        console_caps_t ccaps;  /**< Console capabilities */
    8280
    83         sysarg_t ucols;         /**< Number of columns in user buffer */
    84         sysarg_t urows;         /**< Number of rows in user buffer */
    85         charfield_t *ubuf;      /**< User buffer */
    86 
    8781        chargrid_t *frontbuf;    /**< Front buffer */
    8882        frontbuf_handle_t fbid;  /**< Front buffer handle */
     
    9084} console_t;
    9185
    92 static loc_srv_t *console_srv;
    93 
    9486/** Input server proxy */
    9587static input_t *input;
     
    10395static sysarg_t rows;
    10496
    105 /** Mouse pointer X coordinate */
    106 static int pointer_x;
    107 /** Mouse pointer Y coordinate */
    108 static int pointer_y;
    109 /** Character under mouse cursor */
    110 static charfield_t pointer_bg;
    111 
    112 static int mouse_scale_x = 4;
    113 static int mouse_scale_y = 8;
    114 
    11597/** Array of data for virtual consoles */
    11698static console_t consoles[CONSOLE_COUNT];
     
    123105static errno_t input_ev_active(input_t *);
    124106static errno_t input_ev_deactive(input_t *);
    125 static errno_t input_ev_key(input_t *, unsigned, kbd_event_type_t, keycode_t,
    126     keymod_t, char32_t);
    127 static errno_t input_ev_move(input_t *, unsigned, int, int);
    128 static errno_t input_ev_abs_move(input_t *, unsigned, unsigned, unsigned,
    129     unsigned, unsigned);
    130 static errno_t input_ev_button(input_t *, unsigned, int, int);
    131 static errno_t input_ev_dclick(input_t *, unsigned, int);
     107static errno_t input_ev_key(input_t *, kbd_event_type_t, keycode_t, keymod_t, char32_t);
     108static errno_t input_ev_move(input_t *, int, int);
     109static errno_t input_ev_abs_move(input_t *, unsigned, unsigned, unsigned, unsigned);
     110static errno_t input_ev_button(input_t *, int, int);
    132111
    133112static input_ev_ops_t input_ev_ops = {
     
    137116        .move = input_ev_move,
    138117        .abs_move = input_ev_abs_move,
    139         .button = input_ev_button,
    140         .dclick = input_ev_dclick
     118        .button = input_ev_button
    141119};
    142120
     
    156134static void cons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
    157135static void cons_set_cursor_visibility(con_srv_t *, bool);
    158 static errno_t cons_set_caption(con_srv_t *, const char *);
    159136static errno_t cons_get_event(con_srv_t *, cons_event_t *);
    160 static errno_t cons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
    161 static void cons_unmap(con_srv_t *);
    162 static void cons_buf_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
    163     sysarg_t);
    164137
    165138static con_ops_t con_ops = {
     
    178151        .set_rgb_color = cons_set_rgb_color,
    179152        .set_cursor_visibility = cons_set_cursor_visibility,
    180         .set_caption = cons_set_caption,
    181         .get_event = cons_get_event,
    182         .map = cons_map,
    183         .unmap = cons_unmap,
    184         .update = cons_buf_update
     153        .get_event = cons_get_event
    185154};
    186 
    187 static void pointer_draw(void);
    188 static void pointer_undraw(void);
    189155
    190156static console_t *srv_to_console(con_srv_t *srv)
     
    253219
    254220        fibril_mutex_lock(&switch_mtx);
    255         pointer_undraw();
    256221
    257222        if (cons == active_console) {
     
    262227        active_console = cons;
    263228
    264         pointer_draw();
    265229        fibril_mutex_unlock(&switch_mtx);
    266230
    267231        cons_damage(cons);
    268 }
    269 
    270 /** Draw mouse pointer. */
    271 static void pointer_draw(void)
    272 {
    273         charfield_t *ch;
    274         int col, row;
    275 
    276         /* Downscale coordinates to text resolution */
    277         col = pointer_x / mouse_scale_x;
    278         row = pointer_y / mouse_scale_y;
    279 
    280         /* Make sure they are in range */
    281         if (col < 0 || row < 0 || col >= (int)cols || row >= (int)rows)
    282                 return;
    283 
    284         ch = chargrid_charfield_at(active_console->frontbuf, col, row);
    285 
    286         /*
    287          * Store background attributes for undrawing the pointer.
    288          * This is necessary as styles cannot be inverted with
    289          * round trip (unlike RGB or INDEX)
    290          */
    291         pointer_bg = *ch;
    292 
    293         /* In general the color should be a one's complement of the background */
    294         if (ch->attrs.type == CHAR_ATTR_INDEX) {
    295                 ch->attrs.val.index.bgcolor ^= 0xf;
    296                 ch->attrs.val.index.fgcolor ^= 0xf;
    297         } else if (ch->attrs.type == CHAR_ATTR_RGB) {
    298                 ch->attrs.val.rgb.fgcolor ^= 0xffffff;
    299                 ch->attrs.val.rgb.bgcolor ^= 0xffffff;
    300         } else if (ch->attrs.type == CHAR_ATTR_STYLE) {
    301                 /* Don't have a proper inverse for each style */
    302                 if (ch->attrs.val.style == STYLE_INVERTED)
    303                         ch->attrs.val.style = STYLE_NORMAL;
    304                 else
    305                         ch->attrs.val.style = STYLE_INVERTED;
    306         }
    307 
    308         /* Make sure the cell gets updated */
    309         ch->flags |= CHAR_FLAG_DIRTY;
    310 }
    311 
    312 /** Undraw mouse pointer. */
    313 static void pointer_undraw(void)
    314 {
    315         charfield_t *ch;
    316         int col, row;
    317 
    318         col = pointer_x / mouse_scale_x;
    319         row = pointer_y / mouse_scale_y;
    320         if (col < 0 || row < 0 || col >= (int)cols || row >= (int)rows)
    321                 return;
    322 
    323         ch = chargrid_charfield_at(active_console->frontbuf, col, row);
    324         *ch = pointer_bg;
    325         ch->flags |= CHAR_FLAG_DIRTY;
    326 }
    327 
    328 /** Queue console event.
    329  *
    330  * @param cons Console
    331  * @param ev Console event
    332  */
    333 static void console_queue_cons_event(console_t *cons, cons_event_t *ev)
    334 {
    335         /* Got key press/release event */
    336         cons_qevent_t *event =
    337             (cons_qevent_t *) malloc(sizeof(cons_qevent_t));
    338         if (event == NULL)
    339                 return;
    340 
    341         event->ev = *ev;
    342         link_initialize(&event->link);
    343 
    344         prodcons_produce(&cons->input_pc, &event->link);
    345232}
    346233
     
    362249}
    363250
    364 static errno_t input_ev_key(input_t *input, unsigned kbd_id,
    365     kbd_event_type_t type, keycode_t key, keymod_t mods, char32_t c)
    366 {
    367         cons_event_t event;
    368         bool alt;
    369         bool shift;
    370 
    371         alt = (mods & KM_ALT) != 0 && (mods & (KM_CTRL | KM_SHIFT)) == 0;
    372         shift = (mods & KM_SHIFT) != 0 && (mods & (KM_CTRL | KM_ALT)) == 0;
    373 
    374         /* Switch console on Alt+Fn or Shift+Fn */
     251static errno_t input_ev_key(input_t *input, kbd_event_type_t type, keycode_t key,
     252    keymod_t mods, char32_t c)
     253{
    375254        if ((key >= KC_F1) && (key <= KC_F1 + CONSOLE_COUNT) &&
    376             (alt || shift)) {
     255            ((mods & KM_CTRL) == 0)) {
    377256                cons_switch(key - KC_F1);
    378257        } else {
    379258                /* Got key press/release event */
    380                 event.type = CEV_KEY;
    381 
    382                 (void)kbd_id;
    383                 event.ev.key.type = type;
    384                 event.ev.key.key = key;
    385                 event.ev.key.mods = mods;
    386                 event.ev.key.c = c;
    387 
    388                 console_queue_cons_event(active_console, &event);
    389         }
    390 
    391         return EOK;
    392 }
    393 
    394 /** Update pointer position.
    395  *
    396  * @param new_x New X coordinate (in pixels)
    397  * @param new_y New Y coordinate (in pixels)
    398  */
    399 static void pointer_update(int new_x, int new_y)
    400 {
    401         bool upd_pointer;
    402 
    403         /* Make sure coordinates are in range */
    404 
    405         if (new_x < 0)
    406                 new_x = 0;
    407         if (new_x >= (int)cols * mouse_scale_x)
    408                 new_x = cols * mouse_scale_x - 1;
    409         if (new_y < 0)
    410                 new_y = 0;
    411         if (new_y >= (int)rows * mouse_scale_y)
    412                 new_y = rows * mouse_scale_y - 1;
    413 
    414         /* Determine if pointer moved to a different character cell */
    415         upd_pointer = (new_x / mouse_scale_x != pointer_x / mouse_scale_x) ||
    416             (new_y / mouse_scale_y != pointer_y / mouse_scale_y);
    417 
    418         if (upd_pointer)
    419                 pointer_undraw();
    420 
    421         /* Store new pointer position */
    422         pointer_x = new_x;
    423         pointer_y = new_y;
    424 
    425         if (upd_pointer) {
    426                 pointer_draw();
    427                 cons_update(active_console);
    428         }
    429 }
    430 
    431 static errno_t input_ev_move(input_t *input, unsigned pos_id, int dx, int dy)
    432 {
    433         (void) pos_id;
    434         pointer_update(pointer_x + dx, pointer_y + dy);
    435         return EOK;
    436 }
    437 
    438 static errno_t input_ev_abs_move(input_t *input, unsigned pos_id, unsigned x,
    439     unsigned y, unsigned max_x, unsigned max_y)
    440 {
    441         (void)pos_id;
    442         pointer_update(mouse_scale_x * cols * x / max_x, mouse_scale_y * rows * y / max_y);
    443         return EOK;
    444 }
    445 
    446 static errno_t input_ev_button(input_t *input, unsigned pos_id, int bnum,
    447     int bpress)
    448 {
    449         cons_event_t event;
    450 
    451         (void)pos_id;
    452 
    453         event.type = CEV_POS;
    454         event.ev.pos.type = bpress ? POS_PRESS : POS_RELEASE;
    455         event.ev.pos.btn_num = bnum;
    456         event.ev.pos.hpos = pointer_x / mouse_scale_x;
    457         event.ev.pos.vpos = pointer_y / mouse_scale_y;
    458 
    459         console_queue_cons_event(active_console, &event);
    460         return EOK;
    461 }
    462 
    463 static errno_t input_ev_dclick(input_t *input, unsigned pos_id, int bnum)
    464 {
    465         cons_event_t event;
    466 
    467         (void)pos_id;
    468 
    469         event.type = CEV_POS;
    470         event.ev.pos.type = POS_DCLICK;
    471         event.ev.pos.btn_num = bnum;
    472         event.ev.pos.hpos = pointer_x / mouse_scale_x;
    473         event.ev.pos.vpos = pointer_y / mouse_scale_y;
    474 
    475         console_queue_cons_event(active_console, &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;
     276}
     277
     278static errno_t input_ev_move(input_t *input, int dx, int dy)
     279{
     280        return EOK;
     281}
     282
     283static errno_t input_ev_abs_move(input_t *input, unsigned x, unsigned y,
     284    unsigned max_x, unsigned max_y)
     285{
     286        return EOK;
     287}
     288
     289static errno_t input_ev_button(input_t *input, int bnum, int bpress)
     290{
    476291        return EOK;
    477292}
     
    483298
    484299        fibril_mutex_lock(&cons->mtx);
    485         pointer_undraw();
    486300
    487301        switch (ch) {
     
    490304                break;
    491305        case '\r':
    492                 updated = chargrid_cr(cons->frontbuf);
    493306                break;
    494307        case '\t':
     
    502315        }
    503316
    504         pointer_draw();
    505317        fibril_mutex_unlock(&cons->mtx);
    506318
     
    512324{
    513325        fibril_mutex_lock(&cons->mtx);
    514         pointer_undraw();
    515326        chargrid_set_cursor_visibility(cons->frontbuf, visible);
    516         pointer_draw();
    517327        fibril_mutex_unlock(&cons->mtx);
    518328
     
    557367                if (pos < size) {
    558368                        link_t *link = prodcons_consume(&cons->input_pc);
    559                         cons_qevent_t *qevent = list_get_instance(link,
    560                             cons_qevent_t, link);
    561                         cons_event_t *event = &qevent->ev;
     369                        kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
    562370
    563371                        /* Accept key presses of printable chars only. */
    564                         if (event->type == CEV_KEY && event->ev.key.type == KEY_PRESS &&
    565                             (event->ev.key.c != 0)) {
    566                                 char32_t tmp[2] = { event->ev.key.c, 0 };
     372                        if ((event->type == KEY_PRESS) && (event->c != 0)) {
     373                                char32_t tmp[2] = { event->c, 0 };
    567374                                wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
    568375                                cons->char_remains_len = str_size(cons->char_remains);
    569376                        }
    570377
    571                         free(qevent);
     378                        free(event);
    572379                }
    573380        }
     
    601408
    602409        fibril_mutex_lock(&cons->mtx);
    603         pointer_undraw();
    604410        chargrid_clear(cons->frontbuf);
    605         pointer_draw();
    606411        fibril_mutex_unlock(&cons->mtx);
    607412
     
    614419
    615420        fibril_mutex_lock(&cons->mtx);
    616         pointer_undraw();
    617421        chargrid_set_cursor(cons->frontbuf, col, row);
    618         pointer_draw();
    619422        fibril_mutex_unlock(&cons->mtx);
    620423
     
    692495}
    693496
    694 static errno_t cons_set_caption(con_srv_t *srv, const char *caption)
    695 {
    696         console_t *cons = srv_to_console(srv);
    697 
    698         (void) cons;
    699         (void) caption;
    700         return EOK;
    701 }
    702 
    703497static errno_t cons_get_event(con_srv_t *srv, cons_event_t *event)
    704498{
    705499        console_t *cons = srv_to_console(srv);
    706500        link_t *link = prodcons_consume(&cons->input_pc);
    707         cons_qevent_t *qevent = list_get_instance(link, cons_qevent_t, link);
    708 
    709         *event = qevent->ev;
    710         free(qevent);
    711         return EOK;
    712 }
    713 
    714 /** Create shared buffer for efficient rendering.
    715  *
    716  * @param srv Console server
    717  * @param cols Number of columns in buffer
    718  * @param rows Number of rows in buffer
    719  * @param rbuf Place to store pointer to new sharable buffer
    720  *
    721  * @return EOK on sucess or an error code
    722  */
    723 static errno_t cons_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
    724     charfield_t **rbuf)
    725 {
    726         console_t *cons = srv_to_console(srv);
    727         void *buf;
    728 
    729         fibril_mutex_lock(&cons->mtx);
    730 
    731         if (cons->ubuf != NULL) {
    732                 fibril_mutex_unlock(&cons->mtx);
    733                 return EBUSY;
    734         }
    735 
    736         buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
    737             AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
    738         if (buf == AS_MAP_FAILED) {
    739                 fibril_mutex_unlock(&cons->mtx);
    740                 return ENOMEM;
    741         }
    742 
    743         cons->ucols = cols;
    744         cons->urows = rows;
    745         cons->ubuf = buf;
    746         fibril_mutex_unlock(&cons->mtx);
    747 
    748         *rbuf = buf;
    749         return EOK;
    750 }
    751 
    752 /** Delete shared buffer.
    753  *
    754  * @param srv Console server
    755  */
    756 static void cons_unmap(con_srv_t *srv)
    757 {
    758         console_t *cons = srv_to_console(srv);
    759         void *buf;
    760 
    761         fibril_mutex_lock(&cons->mtx);
    762 
    763         buf = cons->ubuf;
    764         cons->ubuf = NULL;
    765 
    766         if (buf != NULL)
    767                 as_area_destroy(buf);
    768 
    769         fibril_mutex_unlock(&cons->mtx);
    770 }
    771 
    772 /** Update area of console from shared buffer.
    773  *
    774  * @param srv Console server
    775  * @param c0 Column coordinate of top-left corner (inclusive)
    776  * @param r0 Row coordinate of top-left corner (inclusive)
    777  * @param c1 Column coordinate of bottom-right corner (exclusive)
    778  * @param r1 Row coordinate of bottom-right corner (exclusive)
    779  */
    780 static void cons_buf_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
    781     sysarg_t c1, sysarg_t r1)
    782 {
    783         console_t *cons = srv_to_console(srv);
    784         charfield_t *ch;
    785         sysarg_t col, row;
    786 
    787         fibril_mutex_lock(&cons->mtx);
    788 
    789         if (cons->ubuf == NULL) {
    790                 fibril_mutex_unlock(&cons->mtx);
    791                 return;
    792         }
    793 
    794         /* Make sure we have meaningful coordinates, within bounds */
    795 
    796         if (c1 > cons->ucols)
    797                 c1 = cons->ucols;
    798         if (c1 > cons->cols)
    799                 c1 = cons->cols;
    800         if (c0 >= c1) {
    801                 fibril_mutex_unlock(&cons->mtx);
    802                 return;
    803         }
    804         if (r1 > cons->urows)
    805                 r1 = cons->urows;
    806         if (r1 > cons->rows)
    807                 r1 = cons->rows;
    808         if (r0 >= r1) {
    809                 fibril_mutex_unlock(&cons->mtx);
    810                 return;
    811         }
    812 
    813         /* Update front buffer from user buffer */
    814 
    815         pointer_undraw();
    816 
    817         for (row = r0; row < r1; row++) {
    818                 for (col = c0; col < c1; col++) {
    819                         ch = chargrid_charfield_at(cons->frontbuf, col, row);
    820                         *ch = cons->ubuf[row * cons->ucols + col];
    821                 }
    822         }
    823 
    824         pointer_draw();
    825         fibril_mutex_unlock(&cons->mtx);
    826 
    827         /* Update console */
    828         cons_update(cons);
     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;
    829508}
    830509
     
    913592        /* Register server */
    914593        async_set_fallback_port_handler(client_connection, NULL);
    915         rc = loc_server_register(NAME, &console_srv);
     594        rc = loc_server_register(NAME);
    916595        if (rc != EOK) {
    917596                printf("%s: Unable to register server (%s)\n", NAME,
     
    963642                        snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    964643
    965                         if (loc_service_register(console_srv, vc,
    966                             fallback_port_id, &consoles[i].dsid) != EOK) {
     644                        if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
    967645                                printf("%s: Unable to register device %s\n", NAME, vc);
    968646                                return false;
     
    971649
    972650                input_activate(input);
    973                 active = true;
    974                 cons_damage(active_console);
    975651        }
    976652
Note: See TracChangeset for help on using the changeset viewer.