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), Area(colsize, rowsize)), 157 event.payload.code & mask ? event.payload.value ? Rgb32::Color(0, 255, 0) : Rgb32::Color(255, 0, 0) 158 : Rgb32::Color(0, 0, 0)); 159 160 /* Advance to the next row, wrapping around. */ 161 162 row = (row + 1) % 20; 163 } 164 165 /* Or produce a string. */ 166 167 else if (event.payload.value) 168 { 169 const char *s = ((const char *(*)(int)) priv)(event.payload.code); 170 Rgba32::Color col; 171 172 if (!s) 173 { 174 s = null_string; 175 col = Rgba32::Color(255, 0, 0, Rgba32::Color::Amax); 176 } 177 else 178 col = Rgba32::Color(255, 255, 255, Rgba32::Color::Amax); 179 180 Area box = _font->str_sz(s, strlen(s)); 181 182 /* Test for enough space horizontally. */ 183 184 if (text_x + box.w() > view_info.width) 185 { 186 text_x = 0; 187 text_y = next_y; 188 next_y = text_y + box.h(); 189 } 190 191 /* Expand the line height, if appropriate. */ 192 193 else if (text_y + box.h() > next_y) 194 next_y += box.h(); 195 196 /* Test for enough space vertically. */ 197 198 if (next_y > view_info.height) 199 { 200 text_x = 0; 201 text_y = 0; 202 next_y = box.h(); 203 } 204 205 Point p(text_x, text_y); 206 207 _screen->draw_box(Rect(p, box), Rgb32::Color(0, 0, 0)); 208 _screen->draw_string(p, _font, col, s, strlen(s)); 209 210 /* Move to the next position. */ 211 212 text_x += box.w(); 213 } 214 215 /* Refresh the display. */ 216 217 l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height); 218 } 219 220 221 222 /* Event buffer memory. */ 223 224 static void *evmem = 0; 225 226 227 228 /* Arguments: [ chars ] */ 229 230 int main(int argc, char *argv[]) 231 { 232 if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) 233 return 1; 234 235 if (l4re_util_video_goos_fb_view_info(&gfb, &view_info)) 236 return 1; 237 238 if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) 239 return 1; 240 241 /* Obtain a canvas for the framebuffer. */ 242 243 Factory *factory; 244 245 if (view_info.pixel_info.bytes_per_pixel == 2) 246 factory = &_rgb16; 247 else 248 factory = &_rgb32; 249 250 Canvas *screen = factory->create_canvas((void *) ((unsigned long) fb + view_info.buffer_offset), 251 Area(view_info.width, view_info.height), 252 view_info.bytes_per_line); 253 254 Font font(&_binary_unifont_tff_start[0]); 255 256 _screen = screen; 257 _font = &font; 258 259 /* Obtain a reference to the event source. */ 260 261 L4::Cap<Input_event_interface> event_server = L4Re::Env::env()->get_cap<Input_event_interface>("ev"); 262 if (!event_server.is_valid()) return 1; 263 264 /* Obtain a capability for the event buffer. */ 265 266 L4::Cap<L4Re::Dataspace> mem = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>(); 267 if (!mem.is_valid()) return 1; 268 269 if (event_server->get_buffer(mem)) return 1; 270 271 /* Attach the event buffer to this task. */ 272 273 if (L4Re::Env::env()->rm()->attach(&evmem, mem->size(), L4Re::Rm::Search_addr, 274 L4::Ipc::make_cap_rw(mem))) 275 return 1; 276 277 L4Re::Event_buffer event_buffer = L4Re::Event_buffer(evmem, mem->size()); 278 279 /* Obtain an interrupt capability. */ 280 281 L4::Cap<L4::Irq> irq = L4Re::Util::cap_alloc.alloc<L4::Irq>(); 282 if (!irq.is_valid()) return 1; 283 284 /* Bind the interrupt to the event capability. */ 285 286 if (event_server->bind(0, irq)) return 1; 287 288 /* Private data for the handler function. */ 289 290 void *priv = 0; 291 292 if ((argc > 1) && (!strcmp(argv[1], "chars"))) 293 priv = (void *) key_to_string; 294 295 /* Create an event handler and wait for events. */ 296 297 Input_event_loop loop(irq, handler, priv, event_buffer); 298 299 loop.start(); 300 l4_sleep_forever(); 301 302 return 0; 303 }