Ignore:
File:
1 edited

Legend:

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

    r28a5ebd r1a96db9  
    11/*
     2 * Copyright (c) 2025 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Decky
    34 * All rights reserved.
     
    3637#include <stdio.h>
    3738#include <adt/prodcons.h>
     39#include <io/console.h>
    3840#include <io/input.h>
    3941#include <ipc/vfs.h>
     
    6264typedef struct {
    6365        atomic_flag refcnt;      /**< Connection reference count */
    64         prodcons_t input_pc;  /**< Incoming keyboard events */
     66        prodcons_t input_pc;  /**< Incoming console events */
    6567
    6668        /**
     
    7981        console_caps_t ccaps;  /**< Console capabilities */
    8082
     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
    8187        chargrid_t *frontbuf;    /**< Front buffer */
    8288        frontbuf_handle_t fbid;  /**< Front buffer handle */
     
    8490} console_t;
    8591
     92static loc_srv_t *console_srv;
     93
    8694/** Input server proxy */
    8795static input_t *input;
     
    95103static sysarg_t rows;
    96104
     105/** Mouse pointer X coordinate */
     106static int pointer_x;
     107/** Mouse pointer Y coordinate */
     108static int pointer_y;
     109/** Character under mouse cursor */
     110static charfield_t pointer_bg;
     111
     112static int mouse_scale_x = 4;
     113static int mouse_scale_y = 8;
     114
    97115/** Array of data for virtual consoles */
    98116static console_t consoles[CONSOLE_COUNT];
     
    105123static errno_t input_ev_active(input_t *);
    106124static errno_t input_ev_deactive(input_t *);
    107 static errno_t input_ev_key(input_t *, kbd_event_type_t, keycode_t, keymod_t, char32_t);
    108 static errno_t input_ev_move(input_t *, int, int);
    109 static errno_t input_ev_abs_move(input_t *, unsigned, unsigned, unsigned, unsigned);
    110 static errno_t input_ev_button(input_t *, int, int);
     125static errno_t input_ev_key(input_t *, unsigned, kbd_event_type_t, keycode_t,
     126    keymod_t, char32_t);
     127static errno_t input_ev_move(input_t *, unsigned, int, int);
     128static errno_t input_ev_abs_move(input_t *, unsigned, unsigned, unsigned,
     129    unsigned, unsigned);
     130static errno_t input_ev_button(input_t *, unsigned, int, int);
     131static errno_t input_ev_dclick(input_t *, unsigned, int);
    111132
    112133static input_ev_ops_t input_ev_ops = {
     
    116137        .move = input_ev_move,
    117138        .abs_move = input_ev_abs_move,
    118         .button = input_ev_button
     139        .button = input_ev_button,
     140        .dclick = input_ev_dclick
    119141};
    120142
     
    134156static void cons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
    135157static void cons_set_cursor_visibility(con_srv_t *, bool);
     158static errno_t cons_set_caption(con_srv_t *, const char *);
    136159static errno_t cons_get_event(con_srv_t *, cons_event_t *);
     160static errno_t cons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
     161static void cons_unmap(con_srv_t *);
     162static void cons_buf_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
     163    sysarg_t);
    137164
    138165static con_ops_t con_ops = {
     
    151178        .set_rgb_color = cons_set_rgb_color,
    152179        .set_cursor_visibility = cons_set_cursor_visibility,
    153         .get_event = cons_get_event
     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
    154185};
     186
     187static void pointer_draw(void);
     188static void pointer_undraw(void);
    155189
    156190static console_t *srv_to_console(con_srv_t *srv)
     
    219253
    220254        fibril_mutex_lock(&switch_mtx);
     255        pointer_undraw();
    221256
    222257        if (cons == active_console) {
     
    227262        active_console = cons;
    228263
     264        pointer_draw();
    229265        fibril_mutex_unlock(&switch_mtx);
    230266
    231267        cons_damage(cons);
     268}
     269
     270/** Draw mouse pointer. */
     271static 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. */
     313static 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 */
     333static 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);
    232345}
    233346
     
    249362}
    250363
    251 static errno_t input_ev_key(input_t *input, kbd_event_type_t type, keycode_t key,
    252     keymod_t mods, char32_t c)
    253 {
     364static 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 */
    254375        if ((key >= KC_F1) && (key <= KC_F1 + CONSOLE_COUNT) &&
    255             ((mods & KM_CTRL) == 0)) {
     376            (alt || shift)) {
    256377                cons_switch(key - KC_F1);
    257378        } else {
    258379                /* 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;
    276 }
    277 
    278 static errno_t input_ev_move(input_t *input, int dx, int dy)
    279 {
    280         return EOK;
    281 }
    282 
    283 static 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 
    289 static errno_t input_ev_button(input_t *input, int bnum, int bpress)
    290 {
     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 */
     399static 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
     431static 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
     438static 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
     446static 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
     463static 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);
    291476        return EOK;
    292477}
     
    298483
    299484        fibril_mutex_lock(&cons->mtx);
     485        pointer_undraw();
    300486
    301487        switch (ch) {
     
    304490                break;
    305491        case '\r':
     492                updated = chargrid_cr(cons->frontbuf);
    306493                break;
    307494        case '\t':
     
    315502        }
    316503
     504        pointer_draw();
    317505        fibril_mutex_unlock(&cons->mtx);
    318506
     
    324512{
    325513        fibril_mutex_lock(&cons->mtx);
     514        pointer_undraw();
    326515        chargrid_set_cursor_visibility(cons->frontbuf, visible);
     516        pointer_draw();
    327517        fibril_mutex_unlock(&cons->mtx);
    328518
     
    367557                if (pos < size) {
    368558                        link_t *link = prodcons_consume(&cons->input_pc);
    369                         kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
     559                        cons_qevent_t *qevent = list_get_instance(link,
     560                            cons_qevent_t, link);
     561                        cons_event_t *event = &qevent->ev;
    370562
    371563                        /* Accept key presses of printable chars only. */
    372                         if ((event->type == KEY_PRESS) && (event->c != 0)) {
    373                                 char32_t tmp[2] = { event->c, 0 };
     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 };
    374567                                wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
    375568                                cons->char_remains_len = str_size(cons->char_remains);
    376569                        }
    377570
    378                         free(event);
     571                        free(qevent);
    379572                }
    380573        }
     
    408601
    409602        fibril_mutex_lock(&cons->mtx);
     603        pointer_undraw();
    410604        chargrid_clear(cons->frontbuf);
     605        pointer_draw();
    411606        fibril_mutex_unlock(&cons->mtx);
    412607
     
    419614
    420615        fibril_mutex_lock(&cons->mtx);
     616        pointer_undraw();
    421617        chargrid_set_cursor(cons->frontbuf, col, row);
     618        pointer_draw();
    422619        fibril_mutex_unlock(&cons->mtx);
    423620
     
    495692}
    496693
     694static 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
    497703static errno_t cons_get_event(con_srv_t *srv, cons_event_t *event)
    498704{
    499705        console_t *cons = srv_to_console(srv);
    500706        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;
     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 */
     723static 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 */
     756static 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 */
     780static 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);
    508829}
    509830
     
    592913        /* Register server */
    593914        async_set_fallback_port_handler(client_connection, NULL);
    594         rc = loc_server_register(NAME);
     915        rc = loc_server_register(NAME, &console_srv);
    595916        if (rc != EOK) {
    596917                printf("%s: Unable to register server (%s)\n", NAME,
     
    642963                        snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    643964
    644                         if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
     965                        if (loc_service_register(console_srv, vc,
     966                            fallback_port_id, &consoles[i].dsid) != EOK) {
    645967                                printf("%s: Unable to register device %s\n", NAME, vc);
    646968                                return false;
     
    649971
    650972                input_activate(input);
     973                active = true;
     974                cons_damage(active_console);
    651975        }
    652976
Note: See TracChangeset for help on using the changeset viewer.