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