2009-10-09 2 views
4

Я работаю над созданием игры на основе ASCII, и везде, где я смотрю, люди говорят использовать Console.Write() из MSDN, который является dandy и все, если вы используете Windows, но я не знаю.Как я могу написать буфер экрана консоли ANSI C?

И, таким образом, я пытаюсь написать функцию или группу функций в C, которые могут чередоваться между двумя экранными буферами и записывать их на экран, похожие на то, что было бы на страницах man, а также pico , vim и emacs.

У меня работает буфер и найдена старая ASCII-игра для Linux, называемая 0verkill, которая использует C и putchar() для размещения каждого символа на экране, но все мои попытки воссоздать это, приводят к непрерывному поток текста, а не панель размера статического текста. Я действительно не хочу использовать какие-либо внешние библиотеки, такие как проклятия (потому что это снизит переносимость) и хотелось бы придерживаться стандартов ansi, если это вообще возможно.

Спасибо!

ответ

4

Я действительно не хочу использовать какие-либо внешние библиотеки, такие как проклятия (потому что уменьшил бы портативность)

Что? Библиотеки как проклятий и Ncurses разработаны, чтобы сделать этот вид вещи более портативны, потому что ...

и хотел бы придерживаться стандартов ANSI, если вообще возможно.

... не существует стандарта ANSI (по крайней мере для C) для того, что вы хотите. Каждая операционная система реализует такое поведение по-разному, поэтому, если вам нужен переносной способ сделать это, вам нужно использовать библиотеку. Честно говоря, мне не хотелось бы разрабатывать для системы, что не имеют ncurses, портированные на нее. Представьте себе все программы, которые вы не сможете использовать без него.

+0

Я согласен с тем, что вы сказали о Ncurses быть удивительно, но добро пожаловать в OSX (есть Ncurses порт), но как делать такие программы, как emacs (установленный по умолчанию) работает без него? –

+0

OS X (по крайней мере, моя OS X) имеет ncurses, установленные по умолчанию. –

+0

Ну, похоже, я мог бы также углубиться в документацию ncurses .... спасибо за вашу помощь! –

4

Я думаю, что вы ищете ANSI управляющий символ ESC[2J который очищает экран. Вы бы назвали это после любого изменения состояния, чтобы «обновить» экран консоли.

См. this page, чтобы узнать о других из них. Используя эти коды, вы можете определять цвета и форматирование (расстояние, выравнивание, отступы и т. Д.) На консоли.

+0

Спасибо, хотя, когда я пытаюсь это сделать, он продолжает прокручивать окно терминала дольше и дольше .... и не ставит старые putchars поверх новых, всегда esc [2j делает пустое пространство размером с мою консоль окно. –

+2

Да, я думаю, что это все, что вы можете сделать, оно прокручивает окно количество строк в качестве консоли, затем вы перерисовываете все, а затем прокручиваете снова. Это единственный способ, которым я знаю, что эти вещи работают, чтобы создать статическое окно, но я не думаю, что вы можете иметь фактический статический текст, как в элементе управления Windows (но даже это не очень статично, это просто постоянно перекрашивается): вы имеете дело с консолью - просто поток - в конце концов. –

+0

Неверный. Оба окна и x имеют концепцию очищенного окна консоли. Оба также позволяют записывать в произвольных местах в окне консоли –

3

Существует стандарт ANSI X3.64, также ISO/IEC 6429, который описывает терминал DEC VT100. В стандарте описываются определенные escape sequences для определения цвета и курсора, которые распознает совместимый эмулятор терминала, который будет в основном всех X-терминалов, но в Windows не обязательно (возможно, вам нужно, чтобы пользователь загружал ansi.sys). Именно эта последняя уродливая несогласованность иллюстрирует, почему вы должны использовать ncurses, который абстрагирует эту информацию.

+1

+1 для последнего предложения. Почему вы хотите написать ошибку, неполную и труднодоступную версию вековой, хорошо протестированной и широкопористой библиотеки? –

3

Пример заголовка и исходного файла, иллюстрирующий способ абстрактного проклятия из приложения. Собирать пыль; написал его более 15 лет назад. Пусть покупатель будет бдителен.

cursemu.h

/*************************************************************************** 
*                   
* DO NOT CHANGE ANYTHING BETWEEN THIS LINE AND THE NEXT LINE THAT HAS THE 
* WORDS "KLAATU BARRATA NIKTO" ON IT          
*                   
***************************************************************************/ 
#ifndef X__CURSEMU__H               
#define X__CURSEMU__H               

#include <stdio.h> 

#ifdef linux 
#define _POSIX_VERSION 
#endif     

#ifndef _POSIX_VERSION 
#include <sgtty.h>  
#define USE_OLD_TTY 
#include <sys/ioctl.h> 
#undef USE_OLD_TTY 

#ifndef CBREAK 
#define CBREAK RAW 
#endif    

#if !defined(sun) && !defined(sequent) && !defined(hpux) && \ 
    !defined(_AIX) && !defined(aix)       
#include <strings.h>           
#define strchr index           
#else               
#include <string.h>           
#endif              
#else               
#include <string.h>           
#include <termios.h>           
#endif              

#include <errno.h> 
#include <sys/types.h> 
#include <pwd.h>  
#include <sys/time.h> 
#include <sys/file.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h>  
#include <signal.h>  

/* Keep looking ... */ 

int _tty_ch; 

#ifdef _POSIX_VERSION 
struct termios _tty; 
tcflag_t _res_iflg, 
    _res_lflg;   

#define cbreak()(_tty.c_lflag&=~ICANON, \ 
    tcsetattr(_tty_ch, TCSANOW, &_tty)) 

#define noecho()(_tty.c_lflag &= ~(ECHO|ICRNL), \ 
    tcsetattr(_tty_ch, TCSADRAIN, &_tty))   

#define savetty()((void) tcgetattr(_tty_ch, &_tty), \ 
    _res_iflg = _tty.c_iflag, _res_lflg = _tty.c_lflag) 

#define resetty()(_tty.c_iflag = _res_iflg, _tty.c_lflag = _res_lflg,\ 
    (void) tcsetattr(_tty_ch, TCSADRAIN, &_tty))       

#define erasechar()(_tty.c_cc[VERASE]) 
#else         
struct sgttyb _tty;     
int _res_flg;       

#define cbreak()(_tty.sg_flags|=CBREAK, ioctl(_tty_ch, TIOCSETP, &_tty)) 

#define noecho()(_tty.sg_flags &= ~(ECHO|CRMOD), \ 
    ioctl(_tty_ch, TIOCSETP, &_tty))    

#define savetty()((void) ioctl(_tty_ch, TIOCGETP, &_tty), \ 
    _res_flg = _tty.sg_flags)        

#define resetty()(_tty.sg_flags = _res_flg, \ 
    (void) ioctl(_tty_ch, TIOCSETP, &_tty))  
#define erasechar()(_tty.sg_erase)   
#endif          

/* KLAATU BARRATA NIKTO */ 

#define TERMCAP_LENGTH 1024 

struct CtrlSeq 
{    
    char termcap[ TERMCAP_LENGTH ]; 

    int numRows, numCols; 

    /* These pointers are indexes into the termcap buffer, and represent the 
    * control sequences neccessary to send to the terminal window to perform 
    * their appropriately named feature. 
    */ 
    char *highlight, 
     *endMode,   /* End highlight mode, and other modes. */ 
     *clearScr, 
     *clearEol, 
     *scrollRegion, 
     *moveCursor, 
     *deleteRow, 
     *insertRow, 
     *saveCursor,   /* Save the current cursor position */ 
     *restoreCursor;  /* Restore the saved cursor position */ 

    int dumbTerm,    /* 1 if the terminal is a dumb terminal */ 
     flush;    /* 1 if the emulation should flush stdout */ 
}; 

struct CtrlSeq ctrlSeq; 

#define DEFAULT_COLS 80 
#define DEFAULT_ROWS 24 

void ce_flush(int toSet); 
void ce_puts(char *str); 
void ce_gotoRowCol(int row, int col); 

void ce_writeStrRowCol(char *theText, int row, int col); 
void ce_writeStr(char *theText); 
void ce_writeCharRowCol(char theChar, int row, int col); 
void ce_writeChar(char theChar); 

void ce_clearScreen(void); 
void ce_clearEol(void); 

void ce_highlight(int on); 
void ce_scrollRegion(int row1, int row2); 
void ce_deleteRow(int row); 
void ce_insertRow(int row); 
void ce_saveCursor(void); 
void ce_restoreCursor(void); 

int ce_getRows(void); 
int ce_getCols(void); 

#endif 

cursemu.с

#include "cursemu.h" 

int putchar_x(int c) 
{      
    return(putchar(c)); 
}       

/* Returns 0 on success, -1 on error 
*/         
int ce_startCurses(void)   
{          
    char *ptr,       
     tempBuff[ 1024 ];    
    int result = 0;     

    if((ptr = (char *)getenv("TERM")) != NULL) 
    result = tgetent(tempBuff, ptr);   
    else           
    result = tgetent(tempBuff, "vt100");  

    if(result < 1) 
    {    
    perror("FATAL Error: No termcap entry found (even tried vt100)!\n"); 
    return(-1);               
    }                  

    ptr = ctrlSeq.termcap; 

    if((ctrlSeq.numCols = tgetnum("co")) == -1) 
    ctrlSeq.numCols = DEFAULT_COLS;    
    if((ctrlSeq.numRows = tgetnum("li")) == -1) 
    ctrlSeq.numRows = DEFAULT_ROWS;    

    if((ctrlSeq.moveCursor = (char *)tgetstr("cm", &ptr)) == NULL) 
    ctrlSeq.moveCursor = (char *)tgetstr("cl", &ptr);    
    if((ctrlSeq.highlight = (char *)tgetstr("mr", &ptr)) == NULL) 
    ctrlSeq.highlight = (char *)tgetstr("md", &ptr);    

    ctrlSeq.endMode  = (char *)tgetstr("me", &ptr); 
    ctrlSeq.clearEol  = (char *)tgetstr("ce", &ptr); 
    ctrlSeq.clearScr  = (char *)tgetstr("cl", &ptr); 
    ctrlSeq.scrollRegion = (char *)tgetstr("cs", &ptr); 
    ctrlSeq.deleteRow  = (char *)tgetstr("dl", &ptr); 
    ctrlSeq.insertRow  = (char *)tgetstr("al", &ptr); 
    ctrlSeq.saveCursor = (char *)tgetstr("sc", &ptr); 
    ctrlSeq.restoreCursor = (char *)tgetstr("rc", &ptr); 

    ctrlSeq.dumbTerm = (ctrlSeq.moveCursor == NULL) || 
        (ctrlSeq.scrollRegion == NULL) || 
        (ctrlSeq.saveCursor == NULL) || 
        (ctrlSeq.restoreCursor == NULL) || 
        (ctrlSeq.clearEol == NULL);  

    ctrlSeq.flush = 1; 

    if(!ctrlSeq.dumbTerm) 
    {      
    if((_tty_ch = open("/dev/tty", O_RDWR, 0)) == -1) 
     _tty_ch = 0;           

    savetty(); 
    cbreak(); 
    noecho(); 
    return(0); 
    }    

    return(-1); 
}    

int ce_endCurses(void) 
{      
    ce_scrollRegion(-1, -1); 
    ce_gotoRowCol(ce_getRows() - 1, 0); 
    resetty();       
}          

void ce_flush(int toSet) 
{       
    ctrlSeq.flush = toSet; 

    if(toSet == 1) 
    fflush(stdout); 
}      

void ce_puts(char *str) 
{       
    tputs(str, 0, putchar_x); 

    if(ctrlSeq.flush) 
    fflush(stdout); 
}      

void ce_gotoRowCol(int row, int col) 
{          
    if(row > ctrlSeq.numRows)   
    row = ctrlSeq.numRows;    
    if(col > ctrlSeq.numCols)   
    col = ctrlSeq.numCols;    

    ce_puts((char *)tgoto(ctrlSeq.moveCursor, col, row)); 
}               

void ce_writeStrRowCol(char *theText, int row, int col) 
{               
    ce_flush(0);           
    ce_gotoRowCol(row, col);        
    ce_writeStr(theText);         
    ce_flush(1);           
}               

void ce_writeStr(char *theText) 
{         
    ce_flush(0);     
    printf("%s", theText);  
    ce_flush(1);     
}         

void ce_writeCharRowCol(char theChar, int row, int col) 
{               
    ce_flush(0);           
    ce_gotoRowCol(row, col);        
    ce_writeChar(theChar);        
    ce_flush(1);           
}               

void ce_writeChar(char theChar) 
{         
    ce_flush(0);     
    printf("%c", theChar);  
    ce_flush(1);     
}         

void ce_clearScreen(void) 
{       
    ce_puts(ctrlSeq.clearScr); 
} 

void ce_clearEol(void) 
{ 
    ce_puts(ctrlSeq.clearEol); 
} 

void ce_highlight(int on) 
{ 
    if(on == 0) 
    ce_puts(ctrlSeq.endMode); 
    else 
    ce_puts(ctrlSeq.highlight); 
} 

void ce_scrollRegion(int row1, int row2) 
{ 
    ce_puts((char *)tgoto(ctrlSeq.scrollRegion, row1, row2)); 
} 

void ce_deleteRow(int row) 
{ 
    ce_gotoRowCol(row, 0); 
    ce_puts(ctrlSeq.deleteRow); 
} 

void ce_insertRow(int row) 
{ 
    ce_gotoRowCol(row, 0); 
    ce_puts(ctrlSeq.insertRow); 
} 

void ce_saveCursor(void) 
{ 
    ce_puts(ctrlSeq.saveCursor); 
} 

void ce_restoreCursor(void) 
{ 
    ce_puts(ctrlSeq.restoreCursor); 
} 

int ce_getRows(void) 
{ 
    return(ctrlSeq.numRows); 
} 

int ce_getCols(void) 
{ 
    return(ctrlSeq.numCols); 
} 

Компиляция

Требуется:

gcc -o cursemu.o -lcurses -ltermcap 
+0

о, ничего себе, спасибо! –

Смежные вопросы