1 /* 2 * Copyright 2007, 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 "Handle.h" 15 #include "console.h" 16 #include "keyboard.h" 17 18 19 // TOS emulates a VT52 20 21 class ConsoleHandle : public CharHandle { 22 public: 23 ConsoleHandle(); 24 25 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 26 size_t bufferSize); 27 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 28 size_t bufferSize); 29 }; 30 31 class InputConsoleHandle : public ConsoleHandle { 32 public: 33 InputConsoleHandle(); 34 35 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 36 size_t bufferSize); 37 38 void PutChar(char c); 39 void PutChars(const char *buffer, int count); 40 char GetChar(); 41 42 private: 43 enum { BUFFER_SIZE = 32 }; 44 45 char fBuffer[BUFFER_SIZE]; 46 int fStart; 47 int fCount; 48 }; 49 50 51 static InputConsoleHandle sInput; 52 static ConsoleHandle sOutput; 53 FILE *stdin, *stdout, *stderr; 54 55 56 ConsoleHandle::ConsoleHandle() 57 : CharHandle() 58 { 59 } 60 61 62 ssize_t 63 ConsoleHandle::ReadAt(void */*cookie*/, off_t /*pos*/, void *buffer, 64 size_t bufferSize) 65 { 66 // don't seek in character devices 67 // not implemented (and not yet? needed) 68 return B_ERROR; 69 } 70 71 72 ssize_t 73 ConsoleHandle::WriteAt(void */*cookie*/, off_t /*pos*/, const void *buffer, 74 size_t bufferSize) 75 { 76 const char *string = (const char *)buffer; 77 size_t i; 78 79 // be nice to our audience and replace single "\n" with "\r\n" 80 81 for (i = 0; i < bufferSize; i++) { 82 if (string[i] == '\0') 83 break; 84 if (string[i] == '\n') 85 Bconout(fHandle, '\r'); 86 Bconout(fHandle, string[i]); 87 } 88 89 return bufferSize; 90 } 91 92 93 // #pragma mark - 94 95 96 InputConsoleHandle::InputConsoleHandle() 97 : ConsoleHandle() 98 , fStart(0) 99 , fCount(0) 100 { 101 } 102 103 104 ssize_t 105 InputConsoleHandle::ReadAt(void */*cookie*/, off_t /*pos*/, void *_buffer, 106 size_t bufferSize) 107 { 108 char *buffer = (char*)_buffer; 109 110 // copy buffered bytes first 111 int bytesTotal = 0; 112 while (bufferSize > 0 && fCount > 0) { 113 *buffer++ = GetChar(); 114 bytesTotal++; 115 bufferSize--; 116 } 117 118 // read from console 119 if (bufferSize > 0) { 120 ssize_t bytesRead = ConsoleHandle::ReadAt(NULL, 0, buffer, bufferSize); 121 if (bytesRead < 0) 122 return bytesRead; 123 bytesTotal += bytesRead; 124 } 125 126 return bytesTotal; 127 } 128 129 130 void 131 InputConsoleHandle::PutChar(char c) 132 { 133 if (fCount >= BUFFER_SIZE) 134 return; 135 136 int pos = (fStart + fCount) % BUFFER_SIZE; 137 fBuffer[pos] = c; 138 fCount++; 139 } 140 141 142 void 143 InputConsoleHandle::PutChars(const char *buffer, int count) 144 { 145 for (int i = 0; i < count; i++) 146 PutChar(buffer[i]); 147 } 148 149 150 char 151 InputConsoleHandle::GetChar() 152 { 153 if (fCount == 0) 154 return 0; 155 156 fCount--; 157 char c = fBuffer[fStart]; 158 fStart = (fStart + 1) % BUFFER_SIZE; 159 return c; 160 } 161 162 163 // #pragma mark - 164 165 166 status_t 167 console_init(void) 168 { 169 sInput.SetHandle(DEV_CONSOLE); 170 sOutput.SetHandle(DEV_CONSOLE); 171 172 // now that we're initialized, enable stdio functionality 173 stdin = (FILE *)&sInput; 174 stdout = stderr = (FILE *)&sOutput; 175 176 return B_OK; 177 } 178 179 180 // #pragma mark - 181 182 183 void 184 console_clear_screen(void) 185 { 186 sInput.WriteAt(NULL, 0LL, "\033E", 2); 187 } 188 189 190 int32 191 console_width(void) 192 { 193 int columnCount = 80; //XXX: check video mode 194 return columnCount; 195 } 196 197 198 int32 199 console_height(void) 200 { 201 int lineCount = 25; //XXX: check video mode 202 return lineCount; 203 } 204 205 206 void 207 console_set_cursor(int32 x, int32 y) 208 { 209 char buff[] = "\033Y "; 210 x = MIN(79,MAX(0,x)); 211 y = MIN(24,MAX(0,y)); 212 buff[3] += (char)x; 213 buff[2] += (char)y; 214 sInput.WriteAt(NULL, 0LL, buff, 4); 215 } 216 217 218 static int 219 translate_color(int32 color) 220 { 221 /* 222 r g b 223 0: 0 0 0 // black 224 1: 0 0 aa // dark blue 225 2: 0 aa 0 // dark green 226 3: 0 aa aa // cyan 227 4: aa 0 0 // dark red 228 5: aa 0 aa // purple 229 6: aa 55 0 // brown 230 7: aa aa aa // light gray 231 8: 55 55 55 // dark gray 232 9: 55 55 ff // light blue 233 a: 55 ff 55 // light green 234 b: 55 ff ff // light cyan 235 c: ff 55 55 // light red 236 d: ff 55 ff // magenta 237 e: ff ff 55 // yellow 238 f: ff ff ff // white 239 */ 240 // cf. http://www.fortunecity.com/skyscraper/apple/308/html/chap4.htm 241 static const char cmap[] = { 242 15, 4, 2, 6, 1, 5, 3, 7, 243 8, 12, 10, 14, 9, 13, 11, 0 }; 244 245 if (color < 0 && color >= 16) 246 return 0; 247 return cmap[color]; 248 //return color; 249 } 250 251 252 void 253 console_set_color(int32 foreground, int32 background) 254 { 255 char buff[] = "\033b \033c "; 256 buff[2] += (char)translate_color(foreground); 257 buff[5] += (char)translate_color(background); 258 sInput.WriteAt(NULL, 0LL, buff, 6); 259 } 260 261 262 int 263 console_wait_for_key(void) 264 { 265 #if 0 266 // XXX: do this way and remove keyboard.cpp ? 267 // wait for a key 268 char buffer[3]; 269 ssize_t bytesRead; 270 do { 271 bytesRead = sInput.ReadAt(NULL, 0, buffer, 3); 272 if (bytesRead < 0) 273 return 0; 274 } while (bytesRead == 0); 275 #endif 276 union key key = wait_for_key(); 277 278 if (key.code.ascii == 0) { 279 switch (key.code.bios) { 280 case BIOS_KEY_UP: 281 return TEXT_CONSOLE_KEY_UP; 282 case BIOS_KEY_DOWN: 283 return TEXT_CONSOLE_KEY_DOWN; 284 case BIOS_KEY_PAGE_UP: 285 return TEXT_CONSOLE_KEY_PAGE_UP; 286 case BIOS_KEY_PAGE_DOWN: 287 return TEXT_CONSOLE_KEY_PAGE_DOWN; 288 case BIOS_KEY_HOME: 289 return TEXT_CONSOLE_KEY_HOME; 290 case BIOS_KEY_END: 291 return TEXT_CONSOLE_KEY_END; 292 default: 293 return 0; 294 } 295 } else 296 return key.code.ascii; 297 } 298 299