Landfall

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

273:8f6ff113d000
8 months ago Paul Boddie Removed debugging output. cpm-library-improvements
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/util/util.h>
paul@153 53
paul@3 54
#include <l4/re/c/util/video/goos_fb.h>
paul@3 55
#include <l4/re/c/video/view.h>
paul@10 56
paul@3 57
#include <l4/mag-gfx/canvas>
paul@3 58
#include <l4/mag-gfx/font>
paul@3 59
#include <l4/mag-gfx/geometry>
paul@3 60
#include <l4/mag-gfx/gfx_colors>
paul@3 61
#include <l4/mag-gfx/mem_factory>
paul@3 62
paul@156 63
#include <ipc/irq.h>
paul@153 64
paul@3 65
#include <stdint.h>
paul@3 66
#include <string.h>
paul@3 67
paul@153 68
#include "event_client.h"
paul@153 69
#include "icu_client.h"
paul@153 70
paul@153 71
paul@153 72
paul@3 73
/* Video abstractions. */
paul@3 74
paul@3 75
static l4re_util_video_goos_fb_t gfb;
paul@3 76
static l4re_video_view_info_t view_info;
paul@3 77
static void *fb = 0;
paul@3 78
paul@3 79
/* Bundled font data. */
paul@3 80
paul@3 81
extern char const _binary_unifont_tff_start[];
paul@3 82
paul@3 83
/* Screen abstractions. */
paul@3 84
paul@3 85
using namespace Mag_gfx;
paul@3 86
paul@3 87
static Font *_font = 0;
paul@3 88
static Canvas *_screen = 0;
paul@3 89
paul@3 90
paul@3 91
paul@3 92
/* Factories for certain pixel formats. */
paul@3 93
paul@3 94
static Mem::Factory<Rgb16> _rgb16;
paul@3 95
static Mem::Factory<Rgb32> _rgb32;
paul@3 96
paul@3 97
paul@3 98
paul@3 99
/* Key to character conversion function. */
paul@3 100
paul@3 101
static const char *keys_to_strings[] = {
paul@3 102
paul@3 103
  0, "Escape", "1", "2", "3", "4", "5", "6", "7", "8",
paul@3 104
paul@3 105
  "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", "R",
paul@3 106
paul@3 107
  "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Left Ctrl",
paul@3 108
paul@3 109
  "A", "S", "D", "F", "G", "H", "J", "K", "L", ";",
paul@3 110
paul@3 111
  "'", "`", "Left Shift", "\\", "Z", "X", "C", "V", "B", "N",
paul@3 112
paul@3 113
  "M", ",", ".", "/", "Right Shift", "Keypad *", "Left Alt", "Space",
paul@3 114
    "Caps Lock", "F1",
paul@3 115
paul@3 116
  "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Num Lock",
paul@3 117
paul@3 118
  "Scroll Lock", "Keypad 7", "Keypad 8", "Keypad 9", "Keypad -", "Keypad 4",
paul@3 119
    "Keypad 5", "Keypad 6", "Keypad +", "Keypad 1",
paul@3 120
paul@3 121
  "Keypad 2", "Keypad 3", "Keypad 0", "Keypad .", 0, 0, "#102", "F11", "F12", 0,
paul@3 122
paul@3 123
  0, 0, 0, 0, 0, 0, "Keypad Enter", "Right Ctrl", "Keypad /", "SysRq",
paul@3 124
paul@3 125
  "Right Alt", "Line Feed", "Home", "Up", "Page Up", "Left", "Right", "End",
paul@3 126
    "Down", "Page Down",
paul@3 127
paul@3 128
  "Insert", "Delete", "Macro", "Mute", "Volume Down", "Volume Up", "Power",
paul@3 129
    "Keypad =", "Keypad +-", "Pause",
paul@3 130
};
paul@3 131
paul@3 132
static const char null_string[] = "Unknown";
paul@3 133
paul@3 134
const int keys_to_strings_length = 120;
paul@3 135
paul@3 136
static const char *key_to_string(int key)
paul@3 137
{
paul@3 138
  return key < keys_to_strings_length ? keys_to_strings[key] : 0;
paul@3 139
}
paul@3 140
paul@3 141
paul@3 142
paul@3 143
/* Show the keypad event status on the display. */
paul@3 144
paul@3 145
static uint8_t row = 0;
paul@3 146
static uint32_t text_x = 0, text_y = 0, next_y = 0;
paul@3 147
paul@10 148
static void show_key_code(L4Re::Event_buffer::Event &event)
paul@3 149
{
paul@3 150
  uint32_t colsize = view_info.width / 10,
paul@3 151
           rowsize = view_info.height / 20;
paul@3 152
  uint8_t column;
paul@3 153
  uint16_t mask;
paul@3 154
paul@3 155
  /* Convert the key code into a bit pattern. */
paul@3 156
paul@10 157
  for (column = 0, mask = (1 << 9); column < 10; column++, mask >>= 1)
paul@10 158
    _screen->draw_box(Rect(Point(column * colsize, row * rowsize),
paul@10 159
                           Area(colsize, rowsize)),
paul@10 160
                      event.payload.code & mask ? (
paul@10 161
                        event.payload.value ? Rgb32::Color(0, 255, 0)
paul@10 162
                                            : Rgb32::Color(255, 0, 0))
paul@10 163
                        : Rgb32::Color(0, 0, 0));
paul@10 164
paul@10 165
  /* Advance to the next row, wrapping around. */
paul@3 166
paul@10 167
  row = (row + 1) % 20;
paul@3 168
paul@10 169
  /* Refresh the display. */
paul@3 170
paul@10 171
  l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height);
paul@10 172
}
paul@3 173
paul@10 174
static void show_key_label(L4Re::Event_buffer::Event &event)
paul@10 175
{
paul@10 176
  if (event.payload.value)
paul@3 177
  {
paul@10 178
    const char *s = key_to_string(event.payload.code);
paul@3 179
    Rgba32::Color col;
paul@3 180
paul@3 181
    if (!s)
paul@3 182
    {
paul@3 183
      s = null_string;
paul@3 184
      col = Rgba32::Color(255, 0, 0, Rgba32::Color::Amax);
paul@3 185
    }
paul@3 186
    else
paul@3 187
      col = Rgba32::Color(255, 255, 255, Rgba32::Color::Amax);
paul@3 188
paul@3 189
    Area box = _font->str_sz(s, strlen(s));
paul@3 190
paul@3 191
    /* Test for enough space horizontally. */
paul@3 192
paul@3 193
    if (text_x + box.w() > view_info.width)
paul@3 194
    {
paul@3 195
      text_x = 0;
paul@3 196
      text_y = next_y;
paul@3 197
      next_y = text_y + box.h();
paul@3 198
    }
paul@3 199
paul@3 200
    /* Expand the line height, if appropriate. */
paul@3 201
paul@3 202
    else if (text_y + box.h() > next_y)
paul@3 203
      next_y += box.h();
paul@3 204
paul@3 205
    /* Test for enough space vertically. */
paul@3 206
paul@3 207
    if (next_y > view_info.height)
paul@3 208
    {
paul@3 209
      text_x = 0;
paul@3 210
      text_y = 0;
paul@3 211
      next_y = box.h();
paul@8 212
paul@8 213
      /* Clear the screen. */
paul@8 214
paul@8 215
      _screen->draw_box(Rect(Point(0, 0), Area(view_info.width, view_info.height)), Rgb32::Color(0, 0, 0));
paul@3 216
    }
paul@3 217
paul@3 218
    Point p(text_x, text_y);
paul@3 219
paul@3 220
    _screen->draw_box(Rect(p, box), Rgb32::Color(0, 0, 0));
paul@3 221
    _screen->draw_string(p, _font, col, s, strlen(s));
paul@3 222
paul@3 223
    /* Move to the next position. */
paul@3 224
paul@3 225
    text_x += box.w();
paul@3 226
  }
paul@3 227
paul@3 228
  /* Refresh the display. */
paul@3 229
paul@3 230
  l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height);
paul@3 231
}
paul@3 232
paul@3 233
paul@3 234
paul@3 235
/* Arguments: [ chars ] */
paul@3 236
paul@3 237
int main(int argc, char *argv[])
paul@3 238
{
paul@3 239
  if (l4re_util_video_goos_fb_setup_name(&gfb, "fb"))
paul@3 240
    return 1;
paul@3 241
paul@3 242
  if (l4re_util_video_goos_fb_view_info(&gfb, &view_info))
paul@3 243
    return 1;
paul@3 244
paul@3 245
  if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb)))
paul@3 246
    return 1;
paul@3 247
paul@3 248
  /* Obtain a canvas for the framebuffer. */
paul@3 249
paul@3 250
  Factory *factory;
paul@3 251
paul@3 252
  if (view_info.pixel_info.bytes_per_pixel == 2)
paul@3 253
    factory = &_rgb16;
paul@3 254
  else
paul@3 255
    factory = &_rgb32;
paul@3 256
paul@3 257
  Canvas *screen = factory->create_canvas((void *) ((unsigned long) fb + view_info.buffer_offset),
paul@3 258
      Area(view_info.width, view_info.height),
paul@3 259
      view_info.bytes_per_line);
paul@3 260
paul@3 261
  Font font(&_binary_unifont_tff_start[0]);
paul@3 262
paul@3 263
  _screen = screen;
paul@3 264
  _font = &font;
paul@3 265
paul@17 266
  /* Obtain a reference to the event source. It should also be possible to use
paul@17 267
     the Input_event_interface for the core operations. */
paul@3 268
paul@153 269
  l4_cap_idx_t event_cap = l4re_env_get_cap("ev");
paul@153 270
paul@153 271
  if (l4_is_invalid_cap(event_cap))
paul@153 272
    return 1;
paul@3 273
paul@156 274
  /* Obtain the event buffer. */
paul@153 275
paul@153 276
  client_Event event_obj(event_cap);
paul@153 277
  client_ICU icu_obj(event_cap);
paul@156 278
  l4re_ds_t mem;
paul@153 279
paul@153 280
  if (event_obj.get_buffer(&mem))
paul@153 281
    return 1;
paul@3 282
paul@3 283
  /* Attach the event buffer to this task. */
paul@3 284
paul@10 285
  void *evmem = 0;
paul@10 286
paul@153 287
  if (l4re_rm_attach(&evmem, l4re_ds_size(mem),
paul@153 288
                     L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW,
paul@153 289
                     mem, 0,
paul@153 290
                     L4_PAGESHIFT))
paul@3 291
    return 1;
paul@3 292
paul@153 293
  L4Re::Event_buffer event_buffer(evmem, l4re_ds_size(mem));
paul@3 294
paul@17 295
  /* Create an interrupt object. */
paul@17 296
paul@156 297
  l4_cap_idx_t irq;
paul@156 298
paul@156 299
  if (ipc_create_irq(&irq))
paul@153 300
    return 1;
paul@17 301
paul@3 302
  /* Bind the interrupt to the event capability. */
paul@3 303
paul@153 304
  if (icu_obj.bind(0, irq))
paul@153 305
    return 1;
paul@3 306
paul@10 307
  /* Create an event handler. */
paul@3 308
paul@10 309
  Input_event_loop loop(event_buffer, irq);
paul@10 310
paul@10 311
  /* Attach the handler function. */
paul@3 312
paul@3 313
  if ((argc > 1) && (!strcmp(argv[1], "chars")))
paul@10 314
    loop.attach(show_key_label);
paul@10 315
  else
paul@10 316
    loop.attach(show_key_code);
paul@3 317
paul@10 318
  /* Wait for events. */
paul@3 319
paul@3 320
  loop.start();
paul@3 321
  l4_sleep_forever();
paul@3 322
paul@3 323
  return 0;
paul@3 324
}