2009-10-09 422 views
4

我正在製作一個基於ASCII的遊戲,而且在我看來人們都在說要使用來自MSDN的Console.Write(),這是花花公子,如果你使用Windows,但是我不是。如何編寫ANSI C控制檯屏幕緩衝區?

因此,我試圖編寫一個函數或C函數組,可以在兩個屏幕緩衝區之間切換,並將它們寫入屏幕,類似於man頁面,以及pico ,vim和emacs。

我有緩衝區的工作,並發現一個名爲0verkill的Linux舊的ASCII遊戲,它使用C和putchar()將每個字符放在屏幕上,但我所有的嘗試重新創建,導致連續文本流,而不是靜態文本的窗口大小的面板。我真的不想使用任何外部庫,比如curses(因爲這會降低可移植性),並且希望儘可能遵守ANSI標準。

謝謝!

回答

4

我真的不希望使用任何外部庫就像詛咒(因爲這會降低可移植性)

什麼?像詛咒和Ncurses庫,旨在使這種事情便攜,因爲......

,並希望保持ANSI標準,如果在所有可能的。

...沒有ANSI標準(對於C至少)爲你想要的。每個操作系統都以不同的方式實現這種行爲,所以如果你想要一種可移植的方式來做到這一點,你需要使用一個庫。老實說,我討厭開發一個系統,沒有 ncurses移植到它。想象一下如果沒有它,你將無法使用所有的程序。

+0

我同意你說的關於ncurses的是驚人的,但歡迎OSX,(還有一個ncurses的端口),但如何做到像計劃emacs(默認安裝)運行沒有它? – 2009-10-09 04:44:32

+0

OS X(至少,我的OS X)默認安裝了ncurses。 – 2009-10-09 04:47:04

+0

好吧,我似乎也深入研究了ncurses的文檔....感謝您的幫助! – 2009-10-09 05:08:24

4

我覺得你要找的是ANSI控制字符ESC[2J清除屏幕。你可以在任何狀態改變後調用它來「刷新」控制檯屏幕。請致電this page瞭解其餘的人。使用這些代碼,您可以在控制檯上定義顏色和格式(間距,對齊,縮進等)。

+0

謝謝,雖然當我嘗試,它始終滾動終端窗口越來越長......並沒有把舊的putchars放在新的頂端,曾經esc [2j使我的控制檯的大小的空白空間窗口。 – 2009-10-09 04:58:33

+2

是的,我想這就是你所能做的,它將窗口的行數作爲控制檯滾動,然後重繪所有內容,然後再次滾動。這是我意識到這些東西只是爲了給出一個靜態窗口的外觀,但我不認爲你可以在Windows控件中擁有實際的靜態文本(但即使這不是靜態的,它是隻是不斷被重新繪製):畢竟,你正在處理一個控制檯 - 只是一個流。 – 2009-10-09 05:16:29

+0

不正確。窗口和x都有一個清除控制檯窗口的概念。兩者都允許在最後一句話的控制檯窗口 – 2013-12-18 20:24:02

3

有一個ANSI標準X3.64,也是ISO/IEC 6429,它描述了DEC VT100終端。該標準描述了某些escape sequences用於顏色和光標定位,一個兼容的終端仿真器將識別,這基本上將所有的X終端,但在Windows上不一定(可能需要用戶加載 ansi.sys)。這是最後一個醜陋的不一致,說明了爲什麼你應該使用ncurses來抽象出這些細節。

+1

+1內的任意位置寫入。你爲什麼要寫一個古老的,經過充分測試和廣泛移植的圖書館的錯誤,不完整,難以移植的版本? – 2009-10-09 04:52:17

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

哦哇,謝謝! – 2009-10-09 05:28:57