Landfall

pkg/landfall-examples/input_event_client/input_event_client.cc

181:04e69fba99d8
13 months ago Paul Boddie Removed superfluous clock methods. cpm-library-improvements
     1 /*     2  * Access an input device via a capability.     3  *     4  * Copyright (C) 2018, 2023 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  *    21  *    22  * Font definitions and licence (see unifont.tff for bitmap data derived from    23  * GNU Unifont's unifont.hex file):    24  *    25  * Copyright (C) 1998-2003 Roman Czyborra (http://czyborra.com/)    26  *    27  *   All glyphs are released under the GNU General Public License    28  *   (GPL) version 2 or (at your option) a later version, with the    29  *   GNU font embedding exception:    30  *    31  *        ** GPL v2.0 license with font embedding exception:    32  *    33  *        As a special exception, if you create a document which    34  *        uses this font, and embed this font or unaltered portions    35  *        of this font into the document, this font does not by    36  *        itself cause the resulting document to be covered by    37  *        the GNU General Public License. This exception does not    38  *        however invalidate any other reasons why the document    39  *        might be covered by the GNU General Public License.    40  *        If you modify this font, you may extend this exception    41  *        to your version of the font, but you are not obligated    42  *        to do so. If you do not wish to do so, delete this    43  *        exception statement from your version.    44  */    45     46 #include <l4/devices/input-event-loop.h>    47     48 #include <l4/re/c/rm.h>    49 #include <l4/re/env.h>    50 #include <l4/re/event>    51 #include <l4/re/event_enums.h>    52 #include <l4/util/util.h>    53     54 #include <l4/re/c/util/video/goos_fb.h>    55 #include <l4/re/c/video/view.h>    56     57 #include <l4/mag-gfx/canvas>    58 #include <l4/mag-gfx/font>    59 #include <l4/mag-gfx/geometry>    60 #include <l4/mag-gfx/gfx_colors>    61 #include <l4/mag-gfx/mem_factory>    62     63 #include <ipc/irq.h>    64     65 #include <stdint.h>    66 #include <string.h>    67     68 #include "event_client.h"    69 #include "icu_client.h"    70     71     72     73 /* Video abstractions. */    74     75 static l4re_util_video_goos_fb_t gfb;    76 static l4re_video_view_info_t view_info;    77 static void *fb = 0;    78     79 /* Bundled font data. */    80     81 extern char const _binary_unifont_tff_start[];    82     83 /* Screen abstractions. */    84     85 using namespace Mag_gfx;    86     87 static Font *_font = 0;    88 static Canvas *_screen = 0;    89     90     91     92 /* Factories for certain pixel formats. */    93     94 static Mem::Factory<Rgb16> _rgb16;    95 static Mem::Factory<Rgb32> _rgb32;    96     97     98     99 /* Key to character conversion function. */   100    101 static const char *keys_to_strings[] = {   102    103   0, "Escape", "1", "2", "3", "4", "5", "6", "7", "8",   104    105   "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", "R",   106    107   "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Left Ctrl",   108    109   "A", "S", "D", "F", "G", "H", "J", "K", "L", ";",   110    111   "'", "`", "Left Shift", "\\", "Z", "X", "C", "V", "B", "N",   112    113   "M", ",", ".", "/", "Right Shift", "Keypad *", "Left Alt", "Space",   114     "Caps Lock", "F1",   115    116   "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Num Lock",   117    118   "Scroll Lock", "Keypad 7", "Keypad 8", "Keypad 9", "Keypad -", "Keypad 4",   119     "Keypad 5", "Keypad 6", "Keypad +", "Keypad 1",   120    121   "Keypad 2", "Keypad 3", "Keypad 0", "Keypad .", 0, 0, "#102", "F11", "F12", 0,   122    123   0, 0, 0, 0, 0, 0, "Keypad Enter", "Right Ctrl", "Keypad /", "SysRq",   124    125   "Right Alt", "Line Feed", "Home", "Up", "Page Up", "Left", "Right", "End",   126     "Down", "Page Down",   127    128   "Insert", "Delete", "Macro", "Mute", "Volume Down", "Volume Up", "Power",   129     "Keypad =", "Keypad +-", "Pause",   130 };   131    132 static const char null_string[] = "Unknown";   133    134 const int keys_to_strings_length = 120;   135    136 static const char *key_to_string(int key)   137 {   138   return key < keys_to_strings_length ? keys_to_strings[key] : 0;   139 }   140    141    142    143 /* Show the keypad event status on the display. */   144    145 static uint8_t row = 0;   146 static uint32_t text_x = 0, text_y = 0, next_y = 0;   147    148 static void show_key_code(L4Re::Event_buffer::Event &event)   149 {   150   uint32_t colsize = view_info.width / 10,   151            rowsize = view_info.height / 20;   152   uint8_t column;   153   uint16_t mask;   154    155   /* Convert the key code into a bit pattern. */   156    157   for (column = 0, mask = (1 << 9); column < 10; column++, mask >>= 1)   158     _screen->draw_box(Rect(Point(column * colsize, row * rowsize),   159                            Area(colsize, rowsize)),   160                       event.payload.code & mask ? (   161                         event.payload.value ? Rgb32::Color(0, 255, 0)   162                                             : Rgb32::Color(255, 0, 0))   163                         : Rgb32::Color(0, 0, 0));   164    165   /* Advance to the next row, wrapping around. */   166    167   row = (row + 1) % 20;   168    169   /* Refresh the display. */   170    171   l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height);   172 }   173    174 static void show_key_label(L4Re::Event_buffer::Event &event)   175 {   176   if (event.payload.value)   177   {   178     const char *s = key_to_string(event.payload.code);   179     Rgba32::Color col;   180    181     if (!s)   182     {   183       s = null_string;   184       col = Rgba32::Color(255, 0, 0, Rgba32::Color::Amax);   185     }   186     else   187       col = Rgba32::Color(255, 255, 255, Rgba32::Color::Amax);   188    189     Area box = _font->str_sz(s, strlen(s));   190    191     /* Test for enough space horizontally. */   192    193     if (text_x + box.w() > view_info.width)   194     {   195       text_x = 0;   196       text_y = next_y;   197       next_y = text_y + box.h();   198     }   199    200     /* Expand the line height, if appropriate. */   201    202     else if (text_y + box.h() > next_y)   203       next_y += box.h();   204    205     /* Test for enough space vertically. */   206    207     if (next_y > view_info.height)   208     {   209       text_x = 0;   210       text_y = 0;   211       next_y = box.h();   212    213       /* Clear the screen. */   214    215       _screen->draw_box(Rect(Point(0, 0), Area(view_info.width, view_info.height)), Rgb32::Color(0, 0, 0));   216     }   217    218     Point p(text_x, text_y);   219    220     _screen->draw_box(Rect(p, box), Rgb32::Color(0, 0, 0));   221     _screen->draw_string(p, _font, col, s, strlen(s));   222    223     /* Move to the next position. */   224    225     text_x += box.w();   226   }   227    228   /* Refresh the display. */   229    230   l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height);   231 }   232    233    234    235 /* Arguments: [ chars ] */   236    237 int main(int argc, char *argv[])   238 {   239   if (l4re_util_video_goos_fb_setup_name(&gfb, "fb"))   240     return 1;   241    242   if (l4re_util_video_goos_fb_view_info(&gfb, &view_info))   243     return 1;   244    245   if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb)))   246     return 1;   247    248   /* Obtain a canvas for the framebuffer. */   249    250   Factory *factory;   251    252   if (view_info.pixel_info.bytes_per_pixel == 2)   253     factory = &_rgb16;   254   else   255     factory = &_rgb32;   256    257   Canvas *screen = factory->create_canvas((void *) ((unsigned long) fb + view_info.buffer_offset),   258       Area(view_info.width, view_info.height),   259       view_info.bytes_per_line);   260    261   Font font(&_binary_unifont_tff_start[0]);   262    263   _screen = screen;   264   _font = &font;   265    266   /* Obtain a reference to the event source. It should also be possible to use   267      the Input_event_interface for the core operations. */   268    269   l4_cap_idx_t event_cap = l4re_env_get_cap("ev");   270    271   if (l4_is_invalid_cap(event_cap))   272     return 1;   273    274   /* Obtain the event buffer. */   275    276   client_Event event_obj(event_cap);   277   client_ICU icu_obj(event_cap);   278   l4re_ds_t mem;   279    280   if (event_obj.get_buffer(&mem))   281     return 1;   282    283   /* Attach the event buffer to this task. */   284    285   void *evmem = 0;   286    287   if (l4re_rm_attach(&evmem, l4re_ds_size(mem),   288                      L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW,   289                      mem, 0,   290                      L4_PAGESHIFT))   291     return 1;   292    293   L4Re::Event_buffer event_buffer(evmem, l4re_ds_size(mem));   294    295   /* Create an interrupt object. */   296    297   l4_cap_idx_t irq;   298    299   if (ipc_create_irq(&irq))   300     return 1;   301    302   /* Bind the interrupt to the event capability. */   303    304   if (icu_obj.bind(0, irq))   305     return 1;   306    307   /* Create an event handler. */   308    309   Input_event_loop loop(event_buffer, irq);   310    311   /* Attach the handler function. */   312    313   if ((argc > 1) && (!strcmp(argv[1], "chars")))   314     loop.attach(show_key_label);   315   else   316     loop.attach(show_key_code);   317    318   /* Wait for events. */   319    320   loop.start();   321   l4_sleep_forever();   322    323   return 0;   324 }