HOME

Adding double buffer for conio.h

TODO release resources and linux implementation

#include "conio.h"

void edit(int x, int y, int w, char* buffer)
{
    c_textcolor(WHITE);
    c_textbackground(BLUE);

    c_gotoxy(x, y);
    for (int i = 0; i < w; i++)
    {
        if (*buffer)
        {
            c_printf("%c", *buffer);
            buffer++;
        }
        else
            c_printf(" ");
        
    }

    
}

void screen()
{
    edit(2, 1, 10, "teste");
    edit(2, 3, 10, "teste2");
    

}

int main(void)
{
    c_init();
    
    int i = 0;
    int j = 1;
    while (1) {
        
        c_begin();


        c_textcolor(WHITE);
        c_textbackground(GREEN);
        c_clrscr();
        
        screen();

        //for (int i = 1 ; i < j; i++)
//        c_printf("A");
        
        c_end();

        j++;
        Sleep(30);
        if (j == 50)
            j = 1;
    }

    c_destroy();

    return 0;
}
#pragma once

extern HANDLE hConsole;//; GetStdHandle(STD_OUTPUT_HANDLE);

enum COLORS
{
  BLACK = 0,
  BLUE = 1,
  GREEN = 2,
  CYAN = 3,
  RED = 4,
  MAGENTA = 5,
  BROWN = 6,
  LIGHTGRAY = 7,
  DARKGRAY = 8,
  LIGHTBLUE = 9,
  LIGHTGREEN = 10,
  LIGHTCYAN = 11,
  LIGHTRED = 12,
  LIGHTMAGENTA = 13,
  YELLOW = 14,
  WHITE = 15,
  BLINK = 128
};

enum CURSORTYPE
{
  _NOCURSOR,//     turns off the cursor
  _SOLIDCURSOR,//  solid block cursor
  _NORMALCURSOR // normal underscore cursor
};

struct text_info
{
  unsigned char attribute;      /* text attribute */
  unsigned char normattr;       /* normal attribute */
  int screenheight;   /* text screen's height */
  int screenwidth;    /* text screen's width */
  int curx;           /* x-coordinate in current window */
  int cury;           /* y-coordinate in current window */
};



int   c_getch(void);
int   c_getche(void);
int   c_kbhit(void);

void  c_clrscr();
void  c_gotoxy(int x, int y);
void  c_setcursortype(int cur_t);
void  c_textbackground(int newcolor);
void  c_textcolor(int newcolor);
int   c_wherex(void);
int   c_wherey(void);
void  c_gettextinfo(struct text_info *r);
void  c_textattr(int newattr);

void c_init();
void c_destroy();
void c_begin();
void c_end();
void c_printf(const char* format, ...);


#ifdef _WIN32



#include <windows.h>
#include <conio.h>
#include "conio.h"
#include <limits.h>
#include <stdio.h>

HANDLE hNewScreenBuffer = 0;
HANDLE hNewScreenBuffer2 = 0;


void c_init()
{
    struct text_info ti;
    c_gettextinfo(&ti);

    hNewScreenBuffer = CreateConsoleScreenBuffer(
        GENERIC_WRITE | GENERIC_READ,
        0,
        NULL,                    // default security attributes 
        CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE 
        NULL);                   // reserved; must be NULL 


    hNewScreenBuffer2 = CreateConsoleScreenBuffer(
        GENERIC_WRITE | GENERIC_READ,
        0,
        NULL,                    // default security attributes 
        CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE 
        NULL);                   // reserved; must be NULL 


    COORD coordBufSize = { ti.screenwidth, ti.screenheight };
    SetConsoleScreenBufferSize(hNewScreenBuffer, coordBufSize);


    SMALL_RECT srctWriteRect = { 0 };
    srctWriteRect.Right = ti.screenwidth - 1;
    srctWriteRect.Bottom = ti.screenheight - 1;

    SetConsoleWindowInfo(hNewScreenBuffer, TRUE, &srctWriteRect);

    SetConsoleScreenBufferSize(hNewScreenBuffer2, coordBufSize);
    SetConsoleWindowInfo(hNewScreenBuffer2, TRUE, &srctWriteRect);

    
}

void c_begin()
{
    
}

void c_destroy()
{
}

void c_printf(const char* format, ...)
{
    char buffer[1000];

    va_list args;
    va_start(args, format);
    int n = vsnprintf(buffer, 1000, format, args);
    va_end(args);

    int numberOfCharsWritten;
    WriteConsoleA(
        hConsole,
        buffer,
        n,
        &numberOfCharsWritten,
        0);
}

void c_end()
{

    SetConsoleActiveScreenBuffer(hConsole);


    if (hConsole == hNewScreenBuffer2)
    {
        hConsole = hNewScreenBuffer;
    }
    else
    {
        hConsole = hNewScreenBuffer2;
    }
}


HANDLE hConsole = 0;//GetStdHandle(STD_OUTPUT_HANDLE);

static void clearbits(unsigned char * v,
  int bit_index,
  int nbits)
{
  unsigned mask = ~((unsigned char)(0)) << (sizeof(v) * CHAR_BIT - (unsigned char)(nbits));
  mask = mask >> (sizeof(v) * CHAR_BIT - (unsigned char)(bit_index)-(unsigned char)(nbits));
  *v &= ~mask;
}


static void setbits(unsigned char *v,
  int bit_index,
  int nbits,
  unsigned char number)
{
  clearbits(&number, nbits, sizeof(number) * CHAR_BIT - nbits);

  unsigned char big = number;
  big = (big << bit_index);

  clearbits(v, bit_index, nbits);
  *v |= big;
}


static unsigned char getbits(unsigned char v, int bit_index, int nbits)
{
  unsigned char r = v >> bit_index;
  clearbits(&r, nbits, sizeof(unsigned char) * CHAR_BIT - nbits);
  return r;
}


void c_gettextinfo(struct text_info *r)
{
  if (hConsole == NULL)
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

  if (r == 0)
    return;

  CONSOLE_SCREEN_BUFFER_INFO csbi;
  if (GetConsoleScreenBufferInfo(hConsole, &csbi))
  {

      r->attribute = (unsigned char)csbi.wAttributes;
      r->curx = (unsigned char)csbi.dwCursorPosition.X;
      r->cury = (unsigned char)csbi.dwCursorPosition.Y;
      r->screenwidth = (unsigned char)csbi.dwMaximumWindowSize.X;
      r->screenheight = (unsigned char)csbi.dwMaximumWindowSize.Y;
      r->normattr = 0;
  }
  else
  {
      int e = GetLastError();
      e = 0;
  }
}

int c_kbhit(void)
{
  return _kbhit();
}
int c_getch(void)
{
  return _getch();
}

int c_getche(void)
{
  return _getche();
}

void c_setcursortype(int cur_t)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

  CONSOLE_CURSOR_INFO ci;

  switch (cur_t)
  {
  case _NOCURSOR://     (turns off the cursor)
    ci.bVisible = FALSE;
    ci.dwSize = 1;
    break;

  case _SOLIDCURSOR://  (solid block cursor)
    ci.bVisible = TRUE;
    ci.dwSize = 100;
    break;

  default:
  case _NORMALCURSOR: // (normal underscore cursor)
    ci.bVisible = TRUE;
    ci.dwSize = 50;
    break;
  }

  SetConsoleCursorInfo(hConsole, &ci);
}

void c_textattr(int newattr)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

  SetConsoleTextAttribute(hConsole, newattr);
}

void c_textbackground(int newcolor)
{
    
  struct text_info ti;
  c_gettextinfo(&ti);
  unsigned char wColor = ti.attribute;
  unsigned char old = getbits(wColor, 4, 4);
  setbits(&wColor, 4, 4, newcolor);
  c_textattr(wColor);
}

void c_textcolor(int newcolor)
{
  struct text_info ti;
  c_gettextinfo(&ti);
  unsigned char wColor = ti.attribute;
  int old = getbits(wColor, 0, 4);
  setbits(&wColor, 0, 4, newcolor);
  c_textattr(wColor);
}


int c_wherex()
{
  CONSOLE_SCREEN_BUFFER_INFO cbsi;
  if (GetConsoleScreenBufferInfo(hConsole, &cbsi))
  {
    return cbsi.dwCursorPosition.X + 1;
  }
  return -1;
}

int c_wherey()
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

  CONSOLE_SCREEN_BUFFER_INFO cbsi;
  if (GetConsoleScreenBufferInfo(hConsole, &cbsi))
  {
    return cbsi.dwCursorPosition.Y;
  }
  return -1;
}

void c_gotoxy(int x, int y)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

  COORD point;
  point.X = x - (short)1;
  point.Y = y;
  SetConsoleCursorPosition(hConsole, point);
}

void c_clrscr()
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

  COORD coordScreen = { 0, 0 };
  unsigned long cCharsWritten;
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  unsigned long dwConSize;
  //HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  GetConsoleScreenBufferInfo(hConsole, &csbi);
  dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
  FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
  GetConsoleScreenBufferInfo(hConsole, &csbi);
  FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
  SetConsoleCursorPosition(hConsole, coordScreen);
}



#elif __linux__


#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "conio.h"

int c_kbhit(void)
{
  struct termios oldt, newt;
  int ch;
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch = getchar();

  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

  if (ch != EOF)
  {
    ungetc(ch, stdin);
    return 1;
  }

  return 0;
}


static int getCursorPosition2(int *x, int *y)
{
  *x = -1;
  *y = -1;

  char buf[32];
  unsigned int i = 0;
  int ch;

  printf("\x1B[6n");

  while (i < sizeof(buf) - 1)
  {
    ch = c_getch();
    if (ch == EOF || ch == 'R') break;
    buf[i++] = ch;
  }
  buf[i] = '\0';

  if (buf[0] != '\x1b' || buf[1] != '[') return -1;

  if (sscanf(&buf[2], "%d;%d", y, x) != 2) return -1;

  return 0;
}

int c_wherex(void)
{
  int x, y;
  getCursorPosition2(&x, &y);
  return x;
}

int c_wherey(void)
{
  int x, y;
  getCursorPosition2(&x, &y);
  return y;
}


void c_gotoxy(int x, int y)
{
  printf("\x1b[%d;%dH", y, x);
  fflush(stdout);
}

void c_clrscr()
{
  puts("\x1b[2J\x1b[1;1H");
  fflush(stdout);
}

void c_textcolor(int newcolor)
{
  //https://en.wikipedia.org/wiki/ANSI_escape_code

  const char * s = "\x1b[30m";

  switch (newcolor)
  {
  case BLACK:
    s = "\x1b[30m";
    break;

  case BLUE:
    s = "\x1b[34m";
    break;

  case GREEN:
    s = "\x1b[32m";
    break;

  case CYAN:
    s = "\x1b[36m";
    break;

  case RED:
    s = "\x1b[31;1m";
    break;

  case MAGENTA:
    s = "\x1b[35m";
    break;

  case BROWN:
    s = "\x1b[31m";
    break;

  case LIGHTGRAY:
    s = "\x1b[30;1m";
    break;

  case DARKGRAY:
    s = "\x1b[30m";
    break;

  case LIGHTBLUE:
    s = "\x1b[34;1m";
    break;

  case LIGHTGREEN:
    s = "\x1b[32,1m";;
    break;

  case LIGHTCYAN:
    s = "\x1b[36;1m";
    break;

  case LIGHTRED:
    s = "\x1b[31;1m";
    break;

  case LIGHTMAGENTA:
    s = "\x1b[35;1m";
    break;

  case YELLOW:
    s = "\x1b[33;1m";
    break;

  case WHITE:
    s = "\x1b[37;1m";
    break;

  case BLINK:
    s = "\x1b[30m";
    break;
  };

  printf("%s", s);
}

void c_textbackground(int newcolor)
{
  //https://en.wikipedia.org/wiki/ANSI_escape_code

  const char * s = "\x1b[40m";

  switch (newcolor)
  {
  case BLACK:
    s = "\x1b[40m";
    break;

  case BLUE:
    s = "\x1b[44m";
    break;

  case GREEN:
    s = "\x1b[42m";
    break;

  case CYAN:
    s = "\x1b[46m";
    break;

  case RED:
    s = "\x1b[41;1m";
    break;

  case MAGENTA:
    s = "\x1b[45m";
    break;

  case BROWN:
    s = "\x1b[41m";
    break;

  case LIGHTGRAY:
    s = "\x1b[40;1m";
    break;

  case DARKGRAY:
    s = "\x1b[40m";
    break;

  case LIGHTBLUE:
    s = "\x1b[44;1m";
    break;

  case LIGHTGREEN:
    s = "\x1b[42,1m";;
    break;

  case LIGHTCYAN:
    s = "\x1b[46;1m";
    break;

  case LIGHTRED:
    s = "\x1b[41;1m";
    break;

  case LIGHTMAGENTA:
    s = "\x1b[45;1m";
    break;

  case YELLOW:
    s = "\x1b[43;1m";
    break;

  case WHITE:
    s = "\x1b[47;1m";
    break;

  case BLINK:
    s = "\x1b[40m";
    break;
  };

  puts(s);
}


/* Read 1 character - echo defines echo mode */
/*
static char getch_(int echo)
{
  struct termios old, new;
  int ch;

  tcgetattr(0, &old);

  new = old;
  new.c_lflag &= ~ICANON;
  if (!echo)
  {
    new.c_lflag &= ~ECHO;
  }
  tcsetattr(0, TCSANOW, &new);

  ch = getchar();

  tcsetattr(0, TCSANOW, &old);

  return ch;
}
*/

/* Read 1 character without echo */
int c_getch(void)
{
  struct termios old, new;
  int ch;

  tcgetattr(0, &old);

  new = old;
  new.c_lflag &= ~ICANON;
  new.c_lflag &= ~ECHO;
  tcsetattr(0, TCSANOW, &new);

  ch = getchar();

  tcsetattr(0, TCSANOW, &old);

  return ch;
}

/* Read 1 character with echo */
int c_getche(void)
{
  struct termios old, new;
  int ch;

  tcgetattr(0, &old);

  new = old;
  new.c_lflag &= ~ICANON;
  //new.c_lflag &= ~ECHO;
  tcsetattr(0, TCSANOW, &new);

  ch = getchar();

  tcsetattr(0, TCSANOW, &old);
  return ch;
}


void c_setcursortype(int cur_t)
{
  switch (cur_t)
  {
  case _NOCURSOR:
    printf("\x1b[?25l");
    break;

  case _NORMALCURSOR:
    printf("\x1b[?25h");
    break;

  case _SOLIDCURSOR://TODO
    printf("\x1b[?25h");
    break;
  }
}

void c_gettextinfo(struct text_info *r)
{

  struct winsize w;
  ioctl(0, TIOCGWINSZ, &w);

  r->screenheight = w.ws_row;
  r->screenwidth = w.ws_col;

  int x, y;
  getCursorPosition2(&x, &y);


  r->curx = x;
  r->cury = y;

}

void c_textattr(int newattr)
{
  //tODO
}

#endif //linux