Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Η υλοποίηση της γνωστής εντολής clear του bash είναι απλή με ANSI EC:

/* void clear(void)
 * 
 * Clears the screen and moves the cursor in the top left corner.
 */
void clear(void){
	printf("\033[2J\033[1;1H");
}

  • 033 is the octal of ESC
  • 2J is for cleaning the entire screen
  • 1;1H moves the cursor to row 1 and column 1
 
 

Είναι όμως πλήρως cross platform; Πως αλλιώς θα μπορούσε να υλοποιηθεί ώστε να υποστηρίζεται ευρέως; Διάβασα πως οι περισσότερες γνωστές Consoles υποστηρίζουν ANSI Escape Codes. Μόνο και μόνο για εξάσκηση..

 

Πως δηλαδή θα ανιχνεύσω πόσες γραμμές υπάρχουν σε ένα παράθυρο terminal κάποια στιγμή;

Πως θα μετακινήσω τον cursor σε κάποιο συγκεκριμένο σημείο;

 

Ευχαριστώ.

Δημοσ.

Υπάρχει ένα μίνιμουμ συμβατό σετ από ANSI escape sequences. Ρίξε μια ματιά στη Wikipedia: http://en.wikipedia.org/wiki/ANSI_escape_code

Επίσης...

http://www.isthe.com/chongo/tech/comp/ansi_escapes.html

(VT100): http://www.termsys.demon.co.uk/vtansi.htm

 

Είχα ξεκινήσει μια μικρή cross-platform βιβλιοθήκη σε C++, αλλά την έχω παρατημένη.

 

Για gotoXY() βλέπω είχα γράψει το παρακάτω...

 

 

/* ------------------------------------------------------------
 * Cross-platform function to move arbitrarily the console cursor.
 *
 * It works both on the Windows console and on terminals that
 * support ANSI escape sequences (that is on most Unix/Linux
 * terminals).
 */
bool cui_gotoxy( int x, int y )
{
#if defined( CUI_OS_WINDOWS )
	COORD temp;
	temp.X = x;
	temp.Y = y;
	if ( !SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), temp) ) {
		return false;
	}

#elif defined( CUI_OS_UNIX ) || defined( CUI_OS_LINUX )
	std::cout << "\033[" << (y+1) << ";" << (x+1) << "H";
	std::cout.flush();

#endif

	return true;
}

 

Για ClearScreen ...

 

 

/* -----------------------------------------------------
 * Cross-platform function to clear the standard output.
 *
 * It works both on the Windows console and on terminals that
 * support ANSI escape sequences (that is on most Unix/Linux
 * terminals).
 */
bool cui_cls( void )
{
#if defined( CUI_OS_WINDOWS )
	// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx

	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coordScreen = {0, 0};	/* home for the cursor */
	DWORD cCharsWritten;
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	DWORD dwConSize;

	if ( INVALID_HANDLE_VALUE == hConsole) {
		return false;
	}

	// get the number of character cells in the current buffer
	if ( !GetConsoleScreenBufferInfo(hConsole, &csbi) ) {
		return false;
	}

	dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

	// fill the entire screen with blanks
	if ( !FillConsoleOutputCharacter(
		hConsole,		/* Handle to console screen buffer */
		(TCHAR) ' ',		/* Character to write to the buffer */
		dwConSize,		/* Number of cells to write */
		coordScreen,		/* Coordinates of first cell */
		&cCharsWritten )	/* Receive number of characters written */
	){
		return false;
	}

	// get the current text attribute
	if ( !GetConsoleScreenBufferInfo(hConsole, &csbi) ) {
		return false;
	}

	// set the buffer's attributes accordingly
	if ( !FillConsoleOutputAttribute(
		hConsole,		/* Handle to console screen buffer */
		csbi.wAttributes,	/* Character attributes to use */
		dwConSize,		/* Number of cells to set attribute */
		coordScreen,		/* Coordinates of first cell */
		&cCharsWritten )	/* Receive number of characters written */
	){
		return false;
	}

	// put the cursor at its home coordinates
	if ( !SetConsoleCursorPosition(hConsole, coordScreen) ) {
		return false;
	}

#elif defined( CUI_OS_UNIX ) || defined( CUI_OS_LINUX )
	std::cout << "\033[2J" << "\033[H";
	std::cout.flush();

#else	/* On Unsupported Platforms */
	for (int i=0; i < 24; i++)
		std::cout << std::endl;
#endif

	return true;
}

 

Για διάβασμα του κέρσορα...

 

 

/* ------------------------------------------------------------
 * Get cursor's current x & y coords.
 */
inline bool cui_getxy( int &x, int &y )
{
#if defined( CUI_OS_WINDOWS )
	CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
	HANDLE hConsole = GetStdHandle( STD_OUTPUT_HANDLE );

	if ( INVALID_HANDLE_VALUE == hConsole ) {
		return false;
	}
	if ( !GetConsoleScreenBufferInfo(hConsole, &csbiInfo) ) {
		return false;
	}

	x = csbiInfo.dwCursorPosition.X;
	y = csbiInfo.dwCursorPosition.Y;

#elif defined( CUI_OS_UNIX ) || defined( CUI_OS_LINUX )
	char keycodes[18+1] = {'\0'};
	int  tempX, tempY;

	cui_echo_onoff( false );
	cui_raw_onoff( true );

	// query cursor coords
	std::cout << "\033[6n";
	std::cout.flush();

	read( fileno(stdin), keycodes, 18 );

	keycodes[18] = '\0';
	if ( 2 != sscanf(keycodes, "\033[%d;%dR", &tempY, &tempX) ) {
		return false;
	}
	x = tempX-1;
	y = tempY-1;

	cui_raw_onoff( false );
	cui_echo_onoff( true );

#else	/* On UnSupported Platforms */

	return false;
#endif

	return true;
}
/* -----------------------------------------------------
 *
 */
static inline bool cui_raw_on( void )
{
#if defined( CUI_OS_WINDOWS )
	HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode = 0;

	if ( INVALID_HANDLE_VALUE == hConsole) {
		return false;
	}
	if ( !GetConsoleMode(hConsole, &mode) ) {
		return false;
	}
	if ( !SetConsoleMode(hConsole, mode & ~(ENABLE_LINE_INPUT)) ) {
		return false;
	}

#elif defined( CUI_OS_UNIX ) || defined( CUI_OS_LINUX )
	struct termios term;

	if ( 0 != tcgetattr(fileno(stdout), &term) ) {
		return false;
	}

	term.c_lflag &= ~(IXOFF);
	term.c_lflag &= ~(ICANON);

//	if ( 0 != tcsetattr(fileno(stdout), TCSAFLUSH, &term) ) {
	if ( 0 != tcsetattr(fileno(stdout), TCSANOW, &term) ) {
		return false;
	}

#else	/* on Unsupported Platforms */
	return false;
#endif

	return true;
}

/* -----------------------------------------------------
 *
 */
static inline bool cui_raw_off( void )
{
#if defined( CUI_OS_WINDOWS )
	HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode = 0;

	if ( INVALID_HANDLE_VALUE == hConsole) {
		return false;
	}
	if ( !GetConsoleMode(hConsole, &mode) ) {
		return false;
	}
	if ( !SetConsoleMode(hConsole, mode | ENABLE_LINE_INPUT) ) {
		return false;
	}

#elif defined( CUI_OS_UNIX ) || defined( CUI_OS_LINUX )
	struct termios term;

	if ( 0 != tcgetattr(fileno(stdout), &term) ) {
		return false;
	}

	term.c_lflag |= IXOFF;
	term.c_lflag |= ICANON;

//	if ( 0 != tcsetattr(fileno(stdout), TCSAFLUSH, &term) ) {
	if ( 0 != tcsetattr(fileno(stdout), TCSANOW, &term) ) {
		return false;
	}

#else	/* on Unsupported Platforms */
	return false;
#endif

	return true;
}

 

κλπ, κλπ.

 

Όρεξη να 'χεις και χρόνο... αν δεν τα θέλεις cross-platform είναι ακόμα πιο εύκολο.

Δημοσ.

Ευχαριστώ. :)

Όντως θέλει λίγο χρόνο.

Όταν αποκτήσω λίγο θα τους ρίξω μία ματιά.

 

Βγάζοντας απ' έξω την native υποστήριξη για Windows, ουσιαστικά πρόκειται κατά κανόνα για απλά output ακολουθιών χαρακτήρων (ενίοτε με χρήση μιας-δυο μεταβλητών). Η δυσκολία προκύπτει όταν θες  να κάνεις πιο advanced πράγματα, αλλά τότε είναι καλύτερα να χρησιμοποιήσεις απευθείας κάποια έτοιμη βιβλιοθήκη, όπως π.χ τις ncurses (posix), pdcurses (windows/X).

 

Πάντως ακόμα και η κονσόλα των Windows μπορεί να γίνει ANSI codes aware, με τη βοήθεια π.χ. του ansicon. Το συγκεκριμένο το έχω δοκιμάσει με επιτυχία. Υπάρχουν και διάφορα console replacements για Windows που καταλαβαίνουν και ANSI Codes, με ναυαρχίδα υποθέτω το ConEmu (είναι πράγματι jaw dropper αυτό το πρόγραμμα).

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...