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