1 /* 2 * Copyright 2007-2023, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * François Revol, revol@free.fr. 7 */ 8 9 #include <SupportDefs.h> 10 #include <string.h> 11 #include "toscalls.h" 12 #include <util/kernel_cpp.h> 13 14 #include "console.h" 15 #include "keyboard.h" 16 17 18 static bool sForceBW = false; // force black & white for Milan 19 20 21 // TOS emulates a VT52 22 23 class Console : public ConsoleNode { 24 public: 25 Console(); 26 27 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 28 size_t bufferSize); 29 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 30 size_t bufferSize); 31 32 void ClearScreen(); 33 int32 Width(); 34 int32 Height(); 35 void SetCursor(int32 x, int32 y); 36 void SetCursorVisible(bool visible); 37 void SetColors(int32 foreground, int32 background); 38 private: 39 int16 fHandle; 40 }; 41 42 43 extern ConsoleNode* gConsoleNode; 44 static Console sConsole; 45 FILE *stdin, *stdout, *stderr; 46 47 48 Console::Console() 49 : ConsoleNode(), fHandle(DEV_CONSOLE) 50 { 51 } 52 53 54 ssize_t 55 Console::ReadAt(void */*cookie*/, off_t /*pos*/, void *buffer, 56 size_t bufferSize) 57 { 58 // don't seek in character devices 59 // not implemented (and not yet? needed) 60 return B_ERROR; 61 } 62 63 64 ssize_t 65 Console::WriteAt(void */*cookie*/, off_t /*pos*/, const void *buffer, 66 size_t bufferSize) 67 { 68 const char *string = (const char *)buffer; 69 size_t i; 70 71 // be nice to our audience and replace single "\n" with "\r\n" 72 73 for (i = 0; i < bufferSize; i++) { 74 if (string[i] == '\0') 75 break; 76 if (string[i] == '\n') 77 Bconout(fHandle, '\r'); 78 Bconout(fHandle, string[i]); 79 } 80 81 return bufferSize; 82 } 83 84 85 void 86 Console::ClearScreen() 87 { 88 Write("\033E", 2); 89 } 90 91 92 int32 93 Console::Width() 94 { 95 return 80; 96 } 97 98 99 int32 100 Console::Height() 101 { 102 return 25; 103 } 104 105 106 void 107 Console::SetCursor(int32 x, int32 y) 108 { 109 char buff[] = "\033Y "; 110 x = MIN(79,MAX(0,x)); 111 y = MIN(24,MAX(0,y)); 112 buff[3] += (char)x; 113 buff[2] += (char)y; 114 Write(buff, 4); 115 } 116 117 118 void 119 Console::SetCursorVisible(bool visible) 120 { 121 // TODO 122 } 123 124 static int 125 translate_color(int32 color) 126 { 127 /* 128 r g b 129 0: 0 0 0 // black 130 1: 0 0 aa // dark blue 131 2: 0 aa 0 // dark green 132 3: 0 aa aa // cyan 133 4: aa 0 0 // dark red 134 5: aa 0 aa // purple 135 6: aa 55 0 // brown 136 7: aa aa aa // light gray 137 8: 55 55 55 // dark gray 138 9: 55 55 ff // light blue 139 a: 55 ff 55 // light green 140 b: 55 ff ff // light cyan 141 c: ff 55 55 // light red 142 d: ff 55 ff // magenta 143 e: ff ff 55 // yellow 144 f: ff ff ff // white 145 */ 146 // cf. http://www.fortunecity.com/skyscraper/apple/308/html/chap4.htm 147 static const char cmap[] = { 148 15, 4, 2, 6, 1, 5, 3, 7, 149 8, 12, 10, 14, 9, 13, 11, 0 }; 150 151 if (color < 0 || color >= 16) 152 return 0; 153 return cmap[color]; 154 } 155 156 157 void 158 Console::SetColors(int32 foreground, int32 background) 159 { 160 char buff[] = "\033b \033c "; 161 if (sForceBW) { 162 if (background == 0) 163 foreground = 15; 164 else { 165 background = 15; 166 foreground = 0; 167 } 168 169 } 170 buff[2] += (char)translate_color(foreground); 171 buff[5] += (char)translate_color(background); 172 Write(buff, 6); 173 } 174 175 176 // #pragma mark - 177 178 179 constexpr bool kDumpColors = false; 180 constexpr bool kDumpMilanModes = false; 181 182 static void 183 dump_colors() 184 { 185 int bg, fg; 186 dprintf("colors:\n"); 187 for (bg = 0; bg < 16; bg++) { 188 for (fg = 0; fg < 16; fg++) { 189 console_set_color(fg, bg); 190 dprintf("#"); 191 } 192 console_set_color(0, 15); 193 dprintf("\n"); 194 } 195 } 196 197 198 static int32 199 dump_milan_modes(SCREENINFO *info, uint32 flags) 200 { 201 dprintf("mode: %d '%s':\n flags %08" B_PRIx32 " @%08" B_PRIx32 " %dx%d (%dx%d)\n%d planes %d colors fmt %08" B_PRIx32 "\n", 202 info->devID, info->name, info->scrFlags, info->frameadr, 203 info->scrWidth, info->scrHeight, 204 info->virtWidth, info->virtHeight, 205 info->scrPlanes, info->scrColors, info->scrFormat); 206 return ENUMMODE_CONT; 207 } 208 209 status_t 210 console_init(void) 211 { 212 gConsoleNode = &sConsole; 213 214 console_clear_screen(); 215 216 // enable stdio functionality 217 stdin = (FILE *)&sConsole; 218 stdout = stderr = (FILE *)&sConsole; 219 220 if (tos_find_cookie('_MIL')) { 221 dprintf("Milan detected... forcing black & white\n"); 222 if (kDumpMilanModes) { 223 dprintf("Getrez() = %d\n", Getrez()); 224 Setscreen(-1, &dump_milan_modes, MI_MAGIC, CMD_ENUMMODES); 225 Setscreen((void*)-1, (void*)-1, 0, 0); 226 } 227 sForceBW = true; 228 } 229 230 if (kDumpColors) 231 dump_colors(); 232 233 return B_OK; 234 } 235 236 237 // #pragma mark - 238 239 240 int 241 console_wait_for_key(void) 242 { 243 #if 0 244 // XXX: do this way and remove keyboard.cpp ? 245 // wait for a key 246 char buffer[3]; 247 ssize_t bytesRead; 248 do { 249 bytesRead = sInput.ReadAt(NULL, 0, buffer, 3); 250 if (bytesRead < 0) 251 return 0; 252 } while (bytesRead == 0); 253 #endif 254 union key key = wait_for_key(); 255 256 if (key.code.ascii == 0) { 257 switch (key.code.bios) { 258 case BIOS_KEY_UP: 259 return TEXT_CONSOLE_KEY_UP; 260 case BIOS_KEY_DOWN: 261 return TEXT_CONSOLE_KEY_DOWN; 262 case BIOS_KEY_PAGE_UP: 263 return TEXT_CONSOLE_KEY_PAGE_UP; 264 case BIOS_KEY_PAGE_DOWN: 265 return TEXT_CONSOLE_KEY_PAGE_DOWN; 266 case BIOS_KEY_HOME: 267 return TEXT_CONSOLE_KEY_HOME; 268 case BIOS_KEY_END: 269 return TEXT_CONSOLE_KEY_END; 270 default: 271 return 0; 272 } 273 } else 274 return key.code.ascii; 275 } 276 277