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