我正在制作一个基于ASCII的游戏,而且我认为人们都会说使用来自MSDN的Console.Write(),如果你使用的是Windows,但是我不是。 / p>
因此,我正在尝试在C中编写一个函数或一组函数,它们可以在两个屏幕缓冲区之间交替,并将它们写入屏幕,类似于手册页,以及pico, vim和emacs。
我有缓冲区正在工作,并发现了一个名为0verkill的旧的ASCII游戏,使用C和putchar()将每个角色放在屏幕上,但我尝试重新创建它,导致连续流文本,而不是窗口大小的静态文本。我真的不想使用像curses这样的任何外部库(因为这会降低可移植性),并且如果可能的话,我希望保持ansi标准。
谢谢!
答案 0 :(得分:5)
我真的不想使用像curses这样的任何外部库(因为这会降低可移植性)
什么?像curses和ncurses这样的库旨在使更多这类东西变得便携,因为......
并且如果可能的话,我希望遵守ansi标准。
...没有ANSI标准(至少对C来说)你想要的东西。每个操作系统都以不同的方式实现这种行为,因此如果您希望以可移植的方式执行此操作,则需要使用库。老实说,我讨厌必须开发一个没有将ncurses移植到它的系统。想象一下没有它就无法使用的所有程序。
答案 1 :(得分:4)
我认为你要找的是 ANSI控制字符ESC[2J
,它会清除屏幕。在状态发生任何变化后,您可以调用它来“刷新”控制台屏幕。
请参阅this page了解其余部分。使用这些代码,您可以在控制台上定义颜色和格式(间距,对齐,缩进等)。
答案 2 :(得分:3)
有ANSI标准X3.64,ISO / IEC 6429也描述了DEC VT100终端。该标准描述了兼容终端模拟器将识别的颜色和光标定位的某些escape sequences,它基本上都是所有X终端,但在Windows上不一定(可能需要用户加载 ansi.sys 的)。这是最后一个丑陋的不一致,说明了为什么你应该使用ncurses来抽象出这些细节。
答案 3 :(得分:3)
示例标题和源文件,说明从应用程序中抽象curses的方法。收集灰尘; 15年前写的。注意事项。
/***************************************************************************
*
* 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
#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