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