Landfall

Annotated pkg/landfall-examples/input_event_client/input_event_client.cc

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