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