]> Chaos Git - corbenik/ctrulib.git/commitdiff
add console
authorDave Murphy <davem@devkitpro.org>
Thu, 11 Dec 2014 23:05:29 +0000 (23:05 +0000)
committerDave Murphy <davem@devkitpro.org>
Fri, 12 Dec 2014 00:24:08 +0000 (00:24 +0000)
libctru/data/default_font.bin [new file with mode: 0644]
libctru/include/3ds.h
libctru/include/3ds/console.h [new file with mode: 0644]
libctru/source/console.c [new file with mode: 0644]

diff --git a/libctru/data/default_font.bin b/libctru/data/default_font.bin
new file mode 100644 (file)
index 0000000..73436fc
Binary files /dev/null and b/libctru/data/default_font.bin differ
index beec9142833db000a4469b663804709d0c3ffb2d..d128d25d62506cb51b8bf2b2750e72ec7fb4a539 100644 (file)
@@ -11,6 +11,7 @@ extern "C" {
 #include <3ds/linear.h>
 #include <3ds/os.h>
 #include <3ds/gfx.h>
+#include <3ds/console.h>
 
 #include <3ds/services/ac.h>
 #include <3ds/services/apt.h>
diff --git a/libctru/include/3ds/console.h b/libctru/include/3ds/console.h
new file mode 100644 (file)
index 0000000..fe694bf
--- /dev/null
@@ -0,0 +1,138 @@
+\r
+\r
+/*! \file console.h\r
+    \brief 3ds stdio support.\r
+\r
+<div class="fileHeader">\r
+Provides stdio integration for printing to the 3DS screen as well as debug print\r
+functionality provided by stderr.\r
+\r
+General usage is to initialize the console by:\r
+consoleDemoInit()\r
+or to customize the console usage by:\r
+consoleInit()\r
+\r
+*/\r
+\r
+#ifndef CONSOLE_H\r
+#define CONSOLE_H\r
+\r
+#include <3ds/types.h>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+typedef bool(* ConsolePrint)(void* con, char c);\r
+\r
+//! a font struct for the console.\r
+typedef struct ConsoleFont\r
+{\r
+       u8* gfx;                        //!< A pointer to the font graphics\r
+       u16 asciiOffset;        //!<  Offset to the first valid character in the font table\r
+       u16 numChars;           //!< Number of characters in the font graphics\r
+\r
+}ConsoleFont;\r
+\r
+/** \brief console structure used to store the state of a console render context.\r
+\r
+Default values from consoleGetDefault();\r
+<div class="fixedFont"><pre>\r
+PrintConsole defaultConsole =\r
+{\r
+       //Font:\r
+       {\r
+               (u8*)default_font_bin, //font gfx\r
+               0, //first ascii character in the set\r
+               128, //number of characters in the font set\r
+       },\r
+       0,0, //cursorX cursorY\r
+       0,0, //prevcursorX prevcursorY\r
+       40, //console width\r
+       30, //console height\r
+       0,  //window x\r
+       0,  //window y\r
+       32, //window width\r
+       24, //window height\r
+       3, //tab size\r
+       0, //font character offset\r
+       0,  //print callback\r
+       false //console initialized\r
+};\r
+</pre></div>\r
+*/\r
+typedef struct PrintConsole\r
+{\r
+       ConsoleFont font;       //!< font of the console.\r
+\r
+       u16 *frameBuffer;       //!< framebuffer address.\r
+\r
+       int cursorX;            /*!< Current X location of the cursor (as a tile offset by default) */\r
+       int cursorY;            /*!< Current Y location of the cursor (as a tile offset by default) */\r
+\r
+       int prevCursorX;        /*!< Internal state */\r
+       int prevCursorY;        /*!< Internal state */\r
+\r
+       int consoleWidth;       /*!< Width of the console hardware layer in characters */\r
+       int consoleHeight;      /*!< Height of the console hardware layer in characters  */\r
+\r
+       int windowX;            /*!< Window X location in characters (not implemented) */\r
+       int windowY;            /*!< Window Y location in characters (not implemented) */\r
+       int windowWidth;        /*!< Window width in characters (not implemented) */\r
+       int windowHeight;       /*!< Window height in characters (not implemented) */\r
+\r
+       int tabSize;            /*!< Size of a tab*/\r
+       int fg;                         /*!< foreground color*/\r
+       int bg;                         /*!< background color*/\r
+       int flags;                      /*!< reverse/bright flags*/\r
+\r
+       ConsolePrint PrintChar;                 /*!< callback for printing a character. Should return true if it has handled rendering the graphics\r
+                                                                       (else the print engine will attempt to render via tiles) */\r
+\r
+       bool consoleInitialised;        /*!< True if the console is initialized */\r
+}PrintConsole;\r
+\r
+#define CONSOLE_COLOR_BRIGHT   (1<<0)\r
+#define CONSOLE_COLOR_REVERSE  (1<<1)\r
+\r
+/*!    \brief Loads the font into the console\r
+       \param console pointer to the console to update, if NULL it will update the current console\r
+       \param font the font to load\r
+*/\r
+void consoleSetFont(PrintConsole* console, ConsoleFont* font);\r
+\r
+/*!    \brief Sets the print window\r
+       \param console console to set, if NULL it will set the current console window\r
+       \param x x location of the window\r
+       \param y y location of the window\r
+       \param width width of the window\r
+       \param height height of the window\r
+*/\r
+void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height);\r
+\r
+/*!    \brief Gets a pointer to the console with the default values\r
+       this should only be used when using a single console or without changing the console that is returned, other wise use consoleInit()\r
+       \return A pointer to the console with the default values\r
+*/\r
+PrintConsole* consoleGetDefault(void);\r
+\r
+/*!    \brief Make the specified console the render target\r
+       \param console A pointer to the console struct (must have been initialized with consoleInit(PrintConsole* console)\r
+       \return a pointer to the previous console\r
+*/\r
+PrintConsole *consoleSelect(PrintConsole* console);\r
+\r
+/*!    \brief Initialise the console.\r
+       \param console A pointer to the console data to initialze (if it's NULL, the default console will be used)\r
+       \return A pointer to the current console.\r
+*/\r
+PrintConsole* consoleInit(PrintConsole* console);\r
+\r
+//! Clears the screan by using iprintf("\x1b[2J");\r
+void consoleClear(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
diff --git a/libctru/source/console.c b/libctru/source/console.c
new file mode 100644 (file)
index 0000000..451fe0c
--- /dev/null
@@ -0,0 +1,552 @@
+#include <stdio.h>\r
+#include <string.h>\r
+#include <sys/iosupport.h>\r
+#include <3ds/gfx.h>\r
+#include <3ds/console.h>\r
+\r
+#include "default_font_bin.h"\r
+\r
+//set up the palette for color printing\r
+static u16 colorTable[] = {\r
+       RGB565( 0, 0, 0),       // normal black\r
+       RGB565(17, 0, 0),       // normal red\r
+       RGB565( 0,15, 0),       // normal green\r
+       RGB565(17,34, 0),       // normal yellow\r
+       RGB565( 0, 0,17),       // normal blue\r
+       RGB565(17, 0,17),       // normal magenta\r
+       RGB565( 0,34,17),       // normal cyan\r
+       RGB565(17,34,17),       // normal white\r
+       RGB565( 0, 0, 0),       // bright black\r
+       RGB565(25, 0, 0),       // bright red\r
+       RGB565( 0,52, 0),       // bright green\r
+       RGB565(25,52, 0),       // bright yellow\r
+       RGB565( 4,18,31),       // bright blue\r
+       RGB565(25, 0,25),       // bright magenta\r
+       RGB565( 0,52,25),       // bright cyan\r
+       RGB565(28,57,28)        // bright white\r
+};\r
+\r
+PrintConsole defaultConsole =\r
+{\r
+       //Font:\r
+       {\r
+               (u8*)default_font_bin, //font gfx\r
+               0, //first ascii character in the set\r
+               128 //number of characters in the font set\r
+       },\r
+       (u16*)NULL,\r
+       0,0,    //cursorX cursorY\r
+       0,0,     //prevcursorX prevcursorY\r
+       40,     //console width\r
+       30,     //console height\r
+       0,      //window x\r
+       0,      //window y\r
+       40,     //window width\r
+       30,     //window height\r
+       3,              //tab size\r
+       7,              // foreground color\r
+       0,              // background color\r
+       CONSOLE_COLOR_BRIGHT,   // flags\r
+       0,              //print callback\r
+       false   //console initialized\r
+};\r
+\r
+PrintConsole currentCopy;\r
+\r
+PrintConsole* currentConsole = &currentCopy;\r
+\r
+PrintConsole* consoleGetDefault(void){return &defaultConsole;}\r
+\r
+void consolePrintChar(char c);\r
+void consoleDrawChar(int c);\r
+\r
+//---------------------------------------------------------------------------------\r
+static void consoleCls(char mode) {\r
+//---------------------------------------------------------------------------------\r
+\r
+       int i = 0;\r
+       int colTemp,rowTemp;\r
+\r
+       switch (mode)\r
+       {\r
+       case '[':\r
+       case '0':\r
+               {\r
+                       colTemp = currentConsole->cursorX ;\r
+                       rowTemp = currentConsole->cursorY ;\r
+\r
+                       while(i++ < ((currentConsole->windowHeight * currentConsole->windowWidth) - (rowTemp * currentConsole->consoleWidth + colTemp)))\r
+                               consolePrintChar(' ');\r
+\r
+                       currentConsole->cursorX  = colTemp;\r
+                       currentConsole->cursorY  = rowTemp;\r
+                       break;\r
+               }\r
+       case '1':\r
+               {\r
+                       colTemp = currentConsole->cursorX ;\r
+                       rowTemp = currentConsole->cursorY ;\r
+\r
+                       currentConsole->cursorY  = 0;\r
+                       currentConsole->cursorX  = 0;\r
+\r
+                       while (i++ < (rowTemp * currentConsole->windowWidth + colTemp))\r
+                               consolePrintChar(' ');\r
+\r
+                       currentConsole->cursorX  = colTemp;\r
+                       currentConsole->cursorY  = rowTemp;\r
+                       break;\r
+               }\r
+       case '2':\r
+               {\r
+                       currentConsole->cursorY  = 0;\r
+                       currentConsole->cursorX  = 0;\r
+\r
+                       while(i++ < currentConsole->windowHeight * currentConsole->windowWidth)\r
+                               consolePrintChar(' ');\r
+\r
+                       currentConsole->cursorY  = 0;\r
+                       currentConsole->cursorX  = 0;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+//---------------------------------------------------------------------------------\r
+static void consoleClearLine(char mode) {\r
+//---------------------------------------------------------------------------------\r
+\r
+       int i = 0;\r
+       int colTemp;\r
+\r
+       switch (mode)\r
+       {\r
+       case '[':\r
+       case '0':\r
+               {\r
+                       colTemp = currentConsole->cursorX ;\r
+\r
+                       while(i++ < (currentConsole->windowWidth - colTemp)) {\r
+                               consolePrintChar(' ');\r
+                       }\r
+\r
+                       currentConsole->cursorX  = colTemp;\r
+\r
+                       break;\r
+               }\r
+       case '1':\r
+               {\r
+                       colTemp = currentConsole->cursorX ;\r
+\r
+                       currentConsole->cursorX  = 0;\r
+\r
+                       while(i++ < ((currentConsole->windowWidth - colTemp)-2)) {\r
+                               consolePrintChar(' ');\r
+                       }\r
+\r
+                       currentConsole->cursorX  = colTemp;\r
+\r
+                       break;\r
+               }\r
+       case '2':\r
+               {\r
+                       colTemp = currentConsole->cursorX ;\r
+\r
+                       currentConsole->cursorX  = 0;\r
+\r
+                       while(i++ < currentConsole->windowWidth) {\r
+                               consolePrintChar(' ');\r
+                       }\r
+\r
+                       currentConsole->cursorX  = colTemp;\r
+\r
+                       break;\r
+               }\r
+       default:\r
+               {\r
+                       colTemp = currentConsole->cursorX ;\r
+\r
+                       while(i++ < (currentConsole->windowWidth - colTemp)) {\r
+                               consolePrintChar(' ');\r
+                       }\r
+\r
+                       currentConsole->cursorX  = colTemp;\r
+\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+//---------------------------------------------------------------------------------\r
+ssize_t con_write(struct _reent *r,int fd,const char *ptr, size_t len) {\r
+//---------------------------------------------------------------------------------\r
+\r
+       char chr;\r
+\r
+       int i, count = 0;\r
+       char *tmp = (char*)ptr;\r
+\r
+       if(!tmp || len<=0) return -1;\r
+\r
+       i = 0;\r
+\r
+       while(i<len) {\r
+\r
+               chr = *(tmp++);\r
+               i++; count++;\r
+\r
+               if ( chr == 0x1b && *tmp == '[' ) {\r
+                       bool escaping = true;\r
+                       char *escapeseq = tmp;\r
+                       int escapelen = 0;\r
+\r
+                       do {\r
+                               chr = *(tmp++);\r
+                               i++; count++; escapelen++;\r
+                               int parameter, consumed, assigned;\r
+                               bool scanning;\r
+\r
+                               switch (chr) {\r
+                                       //---------------------------------------\r
+                                       // Cursor directional movement\r
+                                       //---------------------------------------\r
+                                       case 'A':\r
+                                               assigned = sscanf(escapeseq,"[%dA", &parameter);\r
+                                               if (assigned==0) parameter = 1;\r
+                                               currentConsole->cursorY  =  (currentConsole->cursorY  - parameter) < 0 ? 0 : currentConsole->cursorY  - parameter;\r
+                                               escaping = false;\r
+                                               break;\r
+                                       case 'B':\r
+                                               sscanf(escapeseq,"[%dB", &parameter);\r
+                                               currentConsole->cursorY  =  (currentConsole->cursorY  + parameter) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY  + parameter;\r
+                                               escaping = false;\r
+                                               break;\r
+                                       case 'C':\r
+                                               sscanf(escapeseq,"[%dC", &parameter);\r
+                                               currentConsole->cursorX  =  (currentConsole->cursorX  + parameter) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX  + parameter;\r
+                                               escaping = false;\r
+                                               break;\r
+                                       case 'D':\r
+                                               sscanf(escapeseq,"[%dD", &parameter);\r
+                                               currentConsole->cursorX  =  (currentConsole->cursorX  - parameter) < 0 ? 0 : currentConsole->cursorX  - parameter;\r
+                                               escaping = false;\r
+                                               break;\r
+                                       //---------------------------------------\r
+                                       // Cursor position movement\r
+                                       //---------------------------------------\r
+                                       case 'H':\r
+                                       case 'f':\r
+                                               sscanf(escapeseq,"[%d;%df", &currentConsole->cursorY , &currentConsole->cursorX );\r
+                                               escaping = false;\r
+                                               break;\r
+                                       //---------------------------------------\r
+                                       // Screen clear\r
+                                       //---------------------------------------\r
+                                       case 'J':\r
+                                               consoleCls(escapeseq[escapelen-2]);\r
+                                               escaping = false;\r
+                                               break;\r
+                                       //---------------------------------------\r
+                                       // Line clear\r
+                                       //---------------------------------------\r
+                                       case 'K':\r
+                                               consoleClearLine(escapeseq[escapelen-2]);\r
+                                               escaping = false;\r
+                                               break;\r
+                                       //---------------------------------------\r
+                                       // Save cursor position\r
+                                       //---------------------------------------\r
+                                       case 's':\r
+                                               currentConsole->prevCursorX  = currentConsole->cursorX ;\r
+                                               currentConsole->prevCursorY  = currentConsole->cursorY ;\r
+                                               escaping = false;\r
+                                               break;\r
+                                       //---------------------------------------\r
+                                       // Load cursor position\r
+                                       //---------------------------------------\r
+                                       case 'u':\r
+                                               currentConsole->cursorX  = currentConsole->prevCursorX ;\r
+                                               currentConsole->cursorY  = currentConsole->prevCursorY ;\r
+                                               escaping = false;\r
+                                               break;\r
+                                       //---------------------------------------\r
+                                       // Color scan codes\r
+                                       //---------------------------------------\r
+                                       case 'm':\r
+                                               escapeseq++;\r
+                                               scanning = true;\r
+\r
+// do while doesn't work at -O2\r
+//                                             do {\r
+                                                       sscanf(escapeseq,"%d;%n", &parameter, &consumed);\r
+                                                       escapeseq += consumed;\r
+\r
+                                                       if (parameter == 0 ) {\r
+                                                               currentConsole->flags |= CONSOLE_COLOR_BRIGHT;\r
+                                                               currentConsole->flags &= ~CONSOLE_COLOR_REVERSE;\r
+                                                               currentConsole->bg = 0;\r
+                                                               currentConsole->fg = 7;\r
+                                                       } else if (parameter == 7) { // reverse video\r
+                                                               currentConsole->flags |= CONSOLE_COLOR_REVERSE;\r
+                                                       } else if (parameter == 2) { // half bright\r
+                                                               currentConsole->flags &= ~CONSOLE_COLOR_BRIGHT;\r
+                                                       } else if (parameter >= 30 && parameter <= 37) { // writing color\r
+                                                               currentConsole->fg = parameter - 30;\r
+                                                       } else if (parameter >= 40 && parameter <= 47) { // screen color\r
+                                                               currentConsole->bg = parameter - 40;\r
+                                                       }\r
+                                                       if(escapeseq >= tmp) scanning = false;\r
+//                                             } while(scanning);\r
+\r
+                                               escaping = false;\r
+                                               break;\r
+                               }\r
+                       } while (escaping);\r
+                       continue;\r
+               }\r
+\r
+               consolePrintChar(chr);\r
+       }\r
+\r
+       return count;\r
+}\r
+\r
+static const devoptab_t dotab_stdout = {\r
+       "con",\r
+       0,\r
+       NULL,\r
+       NULL,\r
+       con_write,\r
+       NULL,\r
+       NULL,\r
+       NULL\r
+};\r
+\r
+static const devoptab_t dotab_null = {\r
+       "null",\r
+       0,\r
+       NULL,\r
+       NULL,\r
+       NULL,\r
+       NULL,\r
+       NULL,\r
+       NULL\r
+};\r
+\r
+//---------------------------------------------------------------------------------\r
+PrintConsole* consoleInit(PrintConsole* console) {\r
+//---------------------------------------------------------------------------------\r
+\r
+       static bool firstConsoleInit = true;\r
+\r
+       if(firstConsoleInit) {\r
+               devoptab_list[STD_OUT] = &dotab_stdout;\r
+               devoptab_list[STD_ERR] = &dotab_stdout;\r
+\r
+               setvbuf(stdout, NULL , _IONBF, 0);\r
+               setvbuf(stderr, NULL , _IONBF, 0);\r
+\r
+               firstConsoleInit = false;\r
+       }\r
+\r
+       if(console) {\r
+               currentConsole = console;\r
+       } else {\r
+               console = currentConsole;\r
+       }\r
+\r
+       *currentConsole = defaultConsole;\r
+\r
+       console->consoleInitialised = 1;\r
+\r
+       gfxSetScreenFormat(GFX_BOTTOM,GSP_RGB565_OES);\r
+       gfxSetDoubleBuffering(GFX_BOTTOM,false);\r
+       console->frameBuffer = (u16*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL);\r
+\r
+\r
+       consoleCls('2');\r
+\r
+       return currentConsole;\r
+\r
+}\r
+//---------------------------------------------------------------------------------\r
+PrintConsole *consoleSelect(PrintConsole* console){\r
+//---------------------------------------------------------------------------------\r
+       PrintConsole *tmp = currentConsole;\r
+       currentConsole = console;\r
+       return tmp;\r
+}\r
+\r
+//---------------------------------------------------------------------------------\r
+void consoleSetFont(PrintConsole* console, ConsoleFont* font){\r
+//---------------------------------------------------------------------------------\r
+\r
+       if(!console) console = currentConsole;\r
+\r
+       console->font = *font;\r
+\r
+}\r
+\r
+//---------------------------------------------------------------------------------\r
+static void newRow() {\r
+//---------------------------------------------------------------------------------\r
+\r
+\r
+       currentConsole->cursorY ++;\r
+\r
+       if(currentConsole->cursorY  >= currentConsole->windowHeight)  {\r
+               currentConsole->cursorY --;\r
+               u16 *dst = &currentConsole->frameBuffer[(currentConsole->windowX * 8 * 240) + (239 - (currentConsole->windowY * 8))];\r
+               u16 *src = dst - 8;\r
+\r
+               int i,j;\r
+\r
+               for (i=0; i<currentConsole->windowWidth*8; i++) {\r
+                       u32 *from=(u32*)src;\r
+                       u32 *to = (u32*)dst;\r
+                       for (j=0; j<((currentConsole->windowHeight*8)-8)/2;j++) *(to--) = *(from--);\r
+\r
+                       dst += 240;\r
+                       src += 240;\r
+               }\r
+\r
+               consoleClearLine('2');\r
+       }\r
+}\r
+//---------------------------------------------------------------------------------\r
+void consoleDrawChar(int c) {\r
+//---------------------------------------------------------------------------------\r
+       c -= currentConsole->font.asciiOffset;\r
+       if ( c < 0 || c > currentConsole->font.numChars ) return;\r
+\r
+       u8 *fontdata = currentConsole->font.gfx + (8 * c);\r
+\r
+       int writingColor = currentConsole->fg;\r
+       int screenColor = currentConsole->bg;\r
+\r
+       if (currentConsole->flags & CONSOLE_COLOR_BRIGHT) {\r
+               writingColor |= 8;\r
+               screenColor |=8;\r
+       }\r
+\r
+       if (currentConsole->flags & CONSOLE_COLOR_REVERSE) {\r
+               int tmp = writingColor;\r
+               writingColor = screenColor;\r
+               screenColor = tmp;\r
+       }\r
+\r
+       u16 bg = colorTable[screenColor];\r
+       u16 fg = colorTable[writingColor];\r
+\r
+       u8 b1 = *(fontdata++);\r
+       u8 b2 = *(fontdata++);\r
+       u8 b3 = *(fontdata++);\r
+       u8 b4 = *(fontdata++);\r
+       u8 b5 = *(fontdata++);\r
+       u8 b6 = *(fontdata++);\r
+       u8 b7 = *(fontdata++);\r
+       u8 b8 = *(fontdata++);\r
+\r
+       u8 mask = 0x80;\r
+\r
+\r
+       int i;\r
+\r
+       int x = (currentConsole->cursorX + currentConsole->windowX) * 8;\r
+       int y = ((currentConsole->cursorY + currentConsole->windowY) *8 );\r
+\r
+       u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 7))];\r
+\r
+       for (i=0;i<8;i++) {\r
+               if (b8 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b7 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b6 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b5 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b4 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b3 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b2 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               if (b1 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }\r
+               mask >>= 1;\r
+               screen += 240 - 8;\r
+       }\r
+\r
+}\r
+\r
+//---------------------------------------------------------------------------------\r
+void consolePrintChar(char c) {\r
+//---------------------------------------------------------------------------------\r
+       if (c==0) return;\r
+\r
+       if(currentConsole->PrintChar)\r
+               if(currentConsole->PrintChar(currentConsole, c))\r
+                       return;\r
+\r
+       if(currentConsole->cursorX  >= currentConsole->windowWidth) {\r
+               currentConsole->cursorX  = 0;\r
+\r
+               newRow();\r
+       }\r
+\r
+       switch(c) {\r
+               /*\r
+               The only special characters we will handle are tab (\t), carriage return (\r), line feed (\n)\r
+               and backspace (\b).\r
+               Carriage return & line feed will function the same: go to next line and put cursor at the beginning.\r
+               For everything else, use VT sequences.\r
+\r
+               Reason: VT sequences are more specific to the task of cursor placement.\r
+               The special escape sequences \b \f & \v are archaic and non-portable.\r
+               */\r
+               case 8:\r
+                       currentConsole->cursorX--;\r
+\r
+                       if(currentConsole->cursorX < 0) {\r
+                               if(currentConsole->cursorY > 0) {\r
+                                       currentConsole->cursorX = currentConsole->windowX - 1;\r
+                                       currentConsole->cursorY--;\r
+                               } else {\r
+                                       currentConsole->cursorX = 0;\r
+                               }\r
+                       }\r
+\r
+                       consoleDrawChar(' ');\r
+                       break;\r
+\r
+               case 9:\r
+                       currentConsole->cursorX  += currentConsole->tabSize - ((currentConsole->cursorX)%(currentConsole->tabSize));\r
+                       break;\r
+               case 10:\r
+                       newRow();\r
+               case 13:\r
+                       currentConsole->cursorX  = 0;\r
+                       break;\r
+               default:\r
+                       consoleDrawChar(c);\r
+                       ++currentConsole->cursorX ;\r
+                       break;\r
+       }\r
+}\r
+\r
+//---------------------------------------------------------------------------------\r
+void consoleClear(void) {\r
+//---------------------------------------------------------------------------------\r
+       iprintf("\x1b[2J");\r
+}\r
+\r
+//---------------------------------------------------------------------------------\r
+void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height){\r
+//---------------------------------------------------------------------------------\r
+\r
+       if(!console) console = currentConsole;\r
+\r
+       console->windowWidth = width;\r
+       console->windowHeight = height;\r
+       console->windowX = x;\r
+       console->windowY = y;\r
+\r
+       console->cursorX = 0;\r
+       console->cursorY = 0;\r
+\r
+}\r
+\r
+\r