1 /* 2 * Access an input device via a capability. 3 * 4 * (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-client.h> 47 #include <l4/devices/input-event-loop.h> 48 49 #include <pthread.h> 50 #include <pthread-l4.h> 51 52 #include <l4/re/c/util/video/goos_fb.h> 53 #include <l4/re/c/video/view.h> 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/util/util.h> 59 60 #include <l4/mag-gfx/canvas> 61 #include <l4/mag-gfx/font> 62 #include <l4/mag-gfx/geometry> 63 #include <l4/mag-gfx/gfx_colors> 64 #include <l4/mag-gfx/mem_factory> 65 66 #include <stdint.h> 67 #include <string.h> 68 69 /* Video abstractions. */ 70 71 static l4re_util_video_goos_fb_t gfb; 72 static l4re_video_view_info_t view_info; 73 static void *fb = 0; 74 75 /* Bundled font data. */ 76 77 extern char const _binary_unifont_tff_start[]; 78 79 /* Screen abstractions. */ 80 81 using namespace Mag_gfx; 82 83 static Font *_font = 0; 84 static Canvas *_screen = 0; 85 86 87 88 /* Factories for certain pixel formats. */ 89 90 static Mem::Factory<Rgb16> _rgb16; 91 static Mem::Factory<Rgb32> _rgb32; 92 93 94 95 /* Key to character conversion function. */ 96 97 static const char *keys_to_strings[] = { 98 99 0, "Escape", "1", "2", "3", "4", "5", "6", "7", "8", 100 101 "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", "R", 102 103 "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Left Ctrl", 104 105 "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", 106 107 "'", "`", "Left Shift", "\\", "Z", "X", "C", "V", "B", "N", 108 109 "M", ",", ".", "/", "Right Shift", "Keypad *", "Left Alt", "Space", 110 "Caps Lock", "F1", 111 112 "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Num Lock", 113 114 "Scroll Lock", "Keypad 7", "Keypad 8", "Keypad 9", "Keypad -", "Keypad 4", 115 "Keypad 5", "Keypad 6", "Keypad +", "Keypad 1", 116 117 "Keypad 2", "Keypad 3", "Keypad 0", "Keypad .", 0, 0, "#102", "F11", "F12", 0, 118 119 0, 0, 0, 0, 0, 0, "Keypad Enter", "Right Ctrl", "Keypad /", "SysRq", 120 121 "Right Alt", "Line Feed", "Home", "Up", "Page Up", "Left", "Right", "End", 122 "Down", "Page Down", 123 124 "Insert", "Delete", "Macro", "Mute", "Volume Down", "Volume Up", "Power", 125 "Keypad =", "Keypad +-", "Pause", 126 }; 127 128 static const char null_string[] = "Unknown"; 129 130 const int keys_to_strings_length = 120; 131 132 static const char *key_to_string(int key) 133 { 134 return key < keys_to_strings_length ? keys_to_strings[key] : 0; 135 } 136 137 138 139 /* Show the keypad event status on the display. */ 140 141 static uint8_t row = 0; 142 static uint32_t text_x = 0, text_y = 0, next_y = 0; 143 144 static void handler(L4Re::Event_buffer::Event &event, void *priv) 145 { 146 uint32_t colsize = view_info.width / 10, 147 rowsize = view_info.height / 20; 148 uint8_t column; 149 uint16_t mask; 150 151 /* Convert the key code into a bit pattern. */ 152 153 if (!priv) 154 { 155 for (column = 0, mask = (1 << 9); column < 10; column++, mask >>= 1) 156 _screen->draw_box(Rect(Point(column * colsize, row * rowsize), 157 Area(colsize, rowsize)), 158 event.payload.code & mask ? ( 159 event.payload.value ? Rgb32::Color(0, 255, 0) 160 : Rgb32::Color(255, 0, 0)) 161 : Rgb32::Color(0, 0, 0)); 162 163 /* Advance to the next row, wrapping around. */ 164 165 row = (row + 1) % 20; 166 } 167 168 /* Or produce a string. */ 169 170 else if (event.payload.value) 171 { 172 const char *s = ((const char *(*)(int)) priv)(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 /* Event buffer memory. */ 230 231 static void *evmem = 0; 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. */ 267 268 L4::Cap<Input_event_interface> event_server = L4Re::Env::env()->get_cap<Input_event_interface>("ev"); 269 if (!event_server.is_valid()) return 1; 270 271 /* Obtain a capability for the event buffer. */ 272 273 L4::Cap<L4Re::Dataspace> mem = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>(); 274 if (!mem.is_valid()) return 1; 275 276 if (event_server->get_buffer(mem)) return 1; 277 278 /* Attach the event buffer to this task. */ 279 280 if (L4Re::Env::env()->rm()->attach(&evmem, mem->size(), L4Re::Rm::Search_addr, 281 L4::Ipc::make_cap_rw(mem))) 282 return 1; 283 284 L4Re::Event_buffer event_buffer = L4Re::Event_buffer(evmem, mem->size()); 285 286 /* Obtain an interrupt capability. */ 287 288 L4::Cap<L4::Irq> irq = L4Re::Util::cap_alloc.alloc<L4::Irq>(); 289 if (!irq.is_valid()) return 1; 290 291 /* Bind the interrupt to the event capability. */ 292 293 if (event_server->bind(0, irq)) return 1; 294 295 /* Private data for the handler function. */ 296 297 void *priv = 0; 298 299 if ((argc > 1) && (!strcmp(argv[1], "chars"))) 300 priv = (void *) key_to_string; 301 302 /* Create an event handler and wait for events. */ 303 304 Input_event_loop loop(handler, priv, event_buffer, irq); 305 306 loop.start(); 307 l4_sleep_forever(); 308 309 return 0; 310 }