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 18static bool sForceBW = false; // force black & white for Milan 19 20 21// TOS emulates a VT52 22 23class 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 43extern ConsoleNode* gConsoleNode; 44static Console sConsole; 45FILE *stdin, *stdout, *stderr; 46 47 48Console::Console() 49 : ConsoleNode(), fHandle(DEV_CONSOLE) 50{ 51} 52 53 54ssize_t 55Console::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 64ssize_t 65Console::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 85void 86Console::ClearScreen() 87{ 88 Write("\033E", 2); 89} 90 91 92int32 93Console::Width() 94{ 95 return 80; 96} 97 98 99int32 100Console::Height() 101{ 102 return 25; 103} 104 105 106void 107Console::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 118void 119Console::SetCursorVisible(bool visible) 120{ 121 // TODO 122} 123 124static int 125translate_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 157void 158Console::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 179constexpr bool kDumpColors = false; 180constexpr bool kDumpMilanModes = false; 181 182static void 183dump_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 198static int32 199dump_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 209status_t 210console_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 240int 241console_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