Windows conio.h源码,实现gotoxy, textcolor,movetext等函数

258 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

经过自己的修改,成功从Dev-C++移植到VC,不用多说,直接上代码,支持Visual Studio and VC++, Windows only

/* A conio implementation for Mingw/Dev-C++.
 *
 * Written by:
 * Hongli Lai <hongli@telekabel.nl>
 * tkorrovi <tkorrovi@altavista.net> on 2002/02/26. 
 * Andrew Westcott <ajwestco@users.sourceforge.net>
 * Michal Molhanec <michal@molhanec.net>
 *
 * Offered for use in the public domain without any warranty.
 *
 * Modified by Tody Guo on 2020/04/29
 * Only support for VC and VS Studio
 * Tody Guo <tody_guo@163.com>
 * https://www.csdn.net/tody_guo
 *
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#include "conio2.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
static int __BACKGROUND = BLACK;
static int __FOREGROUND = LIGHTGRAY;
static struct text_info __text_info = {
    1, 1,
    LIGHTGRAY + (BLACK << 4),
    LIGHTGRAY + (BLACK << 4),
    80, 25
};
static int __CONIO_TOP = 0;
static int __CONIO_LEFT = 0;
 
static void __fill_text_info (void)
{
    CONSOLE_SCREEN_BUFFER_INFO info;
 
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
    __CONIO_LEFT = info.srWindow.Left;
    __CONIO_TOP = info.srWindow.Top;
    __text_info.curx = info.dwCursorPosition.X - __CONIO_LEFT + 1;
    __text_info.cury = info.dwCursorPosition.Y - __CONIO_TOP  + 1;
    __text_info.attribute = info.wAttributes;
    __text_info.screenwidth  = info.srWindow.Right - info.srWindow.Left + 1;
    __text_info.screenheight = info.srWindow.Bottom - info.srWindow.Top + 1;
}
 
void
gettextinfo (struct text_info * info)
{
    __fill_text_info();
    *info = __text_info;
}
 
void inittextinfo (void)
{
    CONSOLE_SCREEN_BUFFER_INFO info;
 
    GetConsoleScreenBufferInfo (GetStdHandle(STD_OUTPUT_HANDLE), &info);
    __text_info.normattr = info.wAttributes;
}
 
void clrscr (void)
{
    DWORD written;
    int i;
    COORD coord = { (short)__CONIO_LEFT, 0};
 
    __fill_text_info();
    for (i = __CONIO_TOP; i < __CONIO_TOP + __text_info.screenheight; i++) {
      coord.Y = i;
      FillConsoleOutputAttribute (GetStdHandle (STD_OUTPUT_HANDLE), __FOREGROUND + (__BACKGROUND << 4), 
        __text_info.screenwidth, coord, &written);
      FillConsoleOutputCharacter (GetStdHandle(STD_OUTPUT_HANDLE), ' ',
        __text_info.screenwidth, coord, &written);
    }
 
    gotoxy (1, 1);
}
 
 
void clreol (void)
{
    COORD coord;
    DWORD written;
 
    __fill_text_info();
    coord.X = __CONIO_LEFT + __text_info.curx - 1;
    coord.Y = __CONIO_TOP  + __text_info.cury - 1;
 
    FillConsoleOutputAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
      __FOREGROUND + (__BACKGROUND << 4),
      __text_info.screenwidth - __text_info.curx + 1, coord, &written);
    FillConsoleOutputCharacter (GetStdHandle (STD_OUTPUT_HANDLE),
      ' ', __text_info.screenwidth - __text_info.curx + 1, coord, &written);
    gotoxy (__text_info.curx, __text_info.cury);
}
 
 
void delline (void)
{
    COORD coord;
    SMALL_RECT rect;
    CHAR_INFO fillchar;
 
    __fill_text_info();
    coord.X = __CONIO_LEFT;
    coord.Y = __CONIO_TOP + __text_info.cury - 1;
    rect.Left = __CONIO_LEFT;
    rect.Top = __CONIO_TOP + __text_info.cury;
    rect.Right = __CONIO_LEFT + __text_info.screenwidth - 1;
    rect.Bottom = __CONIO_TOP + __text_info.screenheight - 1;
    fillchar.Attributes = __FOREGROUND + (__BACKGROUND << 4);
#ifdef UNICODE
    fillchar.Char.UnicodeChar = L' ';
    ScrollConsoleScreenBufferW(GetStdHandle(STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
#else
    fillchar.Char.AsciiChar = ' ';
    ScrollConsoleScreenBufferA(GetStdHandle(STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
#endif
    gotoxy (__text_info.curx, __text_info.cury);
}
 
void insline (void)
{
    COORD coord;
    SMALL_RECT rect;
    CHAR_INFO fillchar;
 
    __fill_text_info();
    coord.X = __CONIO_LEFT;
    coord.Y = __CONIO_TOP + __text_info.cury;
    rect.Left = __CONIO_LEFT;
    rect.Top = __CONIO_TOP + __text_info.cury - 1;
    rect.Right = __CONIO_LEFT + __text_info.screenwidth - 1;
    rect.Bottom = __CONIO_TOP + __text_info.screenheight - 2;
    fillchar.Attributes = __FOREGROUND + (__BACKGROUND << 4);
 
#ifdef UNICODE
    fillchar.Char.UnicodeChar = L' ';
    ScrollConsoleScreenBufferW(GetStdHandle(STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
#else
    fillchar.Char.AsciiChar = ' ';
    ScrollConsoleScreenBufferA(GetStdHandle(STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
#endif
 
    gotoxy (__text_info.curx, __text_info.cury);
}
 
void movetext (int left, int top, int right, int bottom, int destleft, int desttop)
{
    struct char_info * buffer;
 
    buffer = (char_info*)malloc ((right - left + 1) * (bottom - top + 1) * sizeof(struct char_info));  // -----
    gettext (left, top, right, bottom, buffer);
    puttext (destleft, desttop, destleft + right - left, desttop + bottom - top, buffer);
    free(buffer);
}
 
void _conio_gettext (int left, int top, int right, int bottom,
  struct char_info * buf)
{
    int i;
    SMALL_RECT r= { (short)(__CONIO_LEFT + left - 1), (short)(__CONIO_TOP + top - 1), (short)(__CONIO_LEFT + right - 1), (short)(__CONIO_TOP + bottom - 1) };
    CHAR_INFO* buffer;
    COORD size;
    COORD coord = {0,0};
    
    __fill_text_info();
    size.X = right - left + 1;
    size.Y = bottom - top + 1;
    buffer = (CHAR_INFO*)malloc (size.X * size.Y * sizeof(CHAR_INFO));
 
    ReadConsoleOutput (GetStdHandle (STD_OUTPUT_HANDLE),
      (PCHAR_INFO) buffer, size, coord, &r);
 
    for (i = 0; i < size.X * size.Y; i++)
    {
#ifdef UNICODE
        buf[i].letter = buffer[i].Char.UnicodeChar;
#else
        buf[i].letter = buffer[i].Char.AsciiChar;
#endif
        buf[i].attr = buffer[i].Attributes;
    }
    free (buffer);
}
 
void puttext (int left, int top, int right, int bottom, struct char_info * buf)
{ 
    int i;
    SMALL_RECT r= { (short)(__CONIO_LEFT + left - 1), (short)(__CONIO_TOP + top - 1), (short)(__CONIO_LEFT + right - 1), (short)(__CONIO_TOP + bottom - 1) };
    CHAR_INFO* buffer;
    COORD size;
    COORD coord = { 0,0 };
 
    __fill_text_info();
    size.X = right - left + 1;
    size.Y = bottom - top + 1;
    buffer = (CHAR_INFO*)malloc (size.X * size.Y * sizeof(CHAR_INFO));
 
    for (i = 0; i < size.X * size.Y; i++)
    {
#ifdef UNICODE
        buffer[i].Char.UnicodeChar = buf[i].letter;
#else
        buffer[i].Char.AsciiChar = buf[i].letter;
#endif
        buffer[i].Attributes = buf[i].attr;
    }
 
    WriteConsoleOutput (GetStdHandle (STD_OUTPUT_HANDLE), buffer, size, coord, &r);
    free (buffer);
}
 
void gotoxy(int x, int y)
{
  COORD c;
 
  c.X = __CONIO_LEFT + x - 1;
  c.Y = __CONIO_TOP  + y - 1;
  SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c);
}
 
void cputsxy (int x, int y, char * str)
{
    gotoxy (x, y);
    cputs (str);
}
 
void putchxy (int x, int y, char ch)
{
    gotoxy (x, y);
    _putch (ch);
}
 
void _setcursortype (int type)
{
    CONSOLE_CURSOR_INFO Info;
 
    if (type == 0) {
        Info.bVisible = FALSE;
    } else {
      Info.dwSize = type;
      Info.bVisible = TRUE;
    }
    SetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE),
      &Info);
}
 
 
void textattr (int _attr)
{
    __FOREGROUND = _attr & 0xF;
    __BACKGROUND = _attr >> 4;
    SetConsoleTextAttribute (GetStdHandle(STD_OUTPUT_HANDLE), _attr);
}
 
void normvideo (void)
{
    textattr (__text_info.normattr);
}
 
void textbackground (int color)
{
    __BACKGROUND = color;
    SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
      __FOREGROUND + (color << 4));
}
 
void textcolor (int color)
{
    __FOREGROUND = color;
    SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
      color + (__BACKGROUND << 4));
}
 
int wherex (void)
{
    __fill_text_info();
    return __text_info.curx;
}
 
 
int wherey (void)
{
    __fill_text_info();
    return __text_info.cury;
}
 
char *getpass (const char * prompt, char * str)
{
    int maxlength = str[0];
    int length = 0;
    int ch = 0;
    int x, y;
 
    cputs(prompt);
    __fill_text_info();
    x = __text_info.curx;
    y = __text_info.cury;
 
    while (ch != '\r') {
        ch = _getch();
        switch (ch) {
            case '\r' : /* enter */
                break;
            case '\b' : /* backspace */
                if (length > 0) putchxy (x + --length, y, ' ');
                gotoxy (x + length, y);
                break;
            default:
                if (length < maxlength) {
                    putchxy (x + length, y, '*');
                    str[2 + length++] = ch;
                }
        }
    }
    
    str[1] = length;
    str[2 + length] = '\0';
    return &str[2];
}
 
void highvideo (void)
{
    if (__FOREGROUND < DARKGRAY) textcolor(__FOREGROUND + 8);
}
 
void lowvideo (void)
{
    if (__FOREGROUND > LIGHTGRAY) textcolor(__FOREGROUND - 8);
}
 
void delay (int ms)
{
    Sleep(ms);
}
 
void switchbackground (int color)
{
    struct char_info* buffer;
    int i;
 
    buffer = (char_info*)malloc(__text_info.screenwidth * __text_info.screenheight *
      sizeof(struct char_info));
    _conio_gettext(1, 1, __text_info.screenwidth, __text_info.screenheight,
      buffer);
    for (i = 0; i < __text_info.screenwidth * __text_info.screenheight; i++) {
        unsigned short attr = buffer[i].attr & 0xF;
        buffer[i].attr = (color << 4) | attr;
    }
    puttext(1, 1, __text_info.screenwidth, __text_info.screenheight, buffer);
    free(buffer);
}
 
void flashbackground (int color, int ms)
{
    struct char_info* buffer;
 
    buffer = (char_info*)malloc(__text_info.screenwidth * __text_info.screenheight *
      sizeof(struct char_info));
    _conio_gettext(1, 1, __text_info.screenwidth, __text_info.screenheight,
      buffer);
    switchbackground(color);
    delay(ms);
    puttext(1, 1, __text_info.screenwidth, __text_info.screenheight, buffer);
    free(buffer);
}
 
void clearkeybuf (void)
{
    while (_kbhit()) {
        _getch();
    }
}
 
#ifdef __cplusplus
}
#endif