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 }