1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
#include <ciso646>
#include <cstdio>
#include "console.hpp"
bool _is_initialized = false;
#define Q(b) if (_is_initialized == b) return; _is_initialized = b
// All Windows-specifc code begins with the following incantation:
#ifdef _WIN32
#include <windows.h>
#define hstdin GetStdHandle( STD_INPUT_HANDLE )
#define hstdout GetStdHandle( STD_OUTPUT_HANDLE )
static DWORD input_mode, output_mode;
static UINT input_codepage, output_codepage;
#define CSBI \
CONSOLE_SCREEN_BUFFER_INFO csbi; \
GetConsoleScreenBufferInfo( hstdout, &csbi );
width_height get_terminal_size()
{
CSBI return {
csbi.srWindow.Right - csbi.srWindow.Left + 1,
csbi.srWindow.Bottom - csbi.srWindow.Top + 1 };
}
bool is_key_pressed( int timeout_ms )
{
return WaitForSingleObject( hstdin, (DWORD)timeout_ms ) == WAIT_OBJECT_0;
}
void flush_input() { FlushConsoleInputBuffer( hstdin ); }
// On Windows, the only One True Way™ to print Unicode output is using WriteConsoleW().
// This works for ANY code page on both Windows Console and Windows Terminal.
void _write( const std::string & s )
{
DWORD n;
std::wstring w( s.size(), 0 ); // Convert to UTF-16
w.resize( MultiByteToWideChar( CP_UTF8, 0, (char *)s.c_str(), (int)s.size(), (wchar_t *)w.c_str(), (int)w.size() ) );
WriteConsoleW( hstdout, (wchar_t *)w.c_str(), (DWORD)w.size(), &n, NULL );
}
void _finalize()
{
Q(false);
_write( "\033[?1049l" "\033[?25h" );
SetConsoleCP( input_codepage );
SetConsoleOutputCP( output_codepage );
SetConsoleMode( hstdin, input_mode );
SetConsoleMode( hstdout, output_mode );
}
void _initialize()
{
Q(true);
GetConsoleMode( hstdin, &input_mode );
GetConsoleMode( hstdout, &output_mode );
SetConsoleMode( hstdin, ENABLE_VIRTUAL_TERMINAL_INPUT | ENABLE_EXTENDED_FLAGS );
SetConsoleMode( hstdout, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT );
input_codepage = GetConsoleCP();
output_codepage = GetConsoleOutputCP();
SetConsoleCP( 65001 );
SetConsoleOutputCP( 65001 );
setlocale( LC_ALL, ".UTF-8" );
_write( "\033[?1049h" "\033[?25l" );
atexit( &_finalize );
}
// If it ain’t Windows, it must be Linux / OS X / etc
#else
#include <sys/types.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <termios.h>
#include <unistd.h>
static int _esc_delay = 100;
static struct termios _initial_settings;
width_height get_terminal_size()
{
struct winsize ws;
ioctl( 0, TIOCGWINSZ, &ws );
return { ws.ws_col, ws.ws_row };
}
bool is_key_pressed( int timeout_ms )
{
struct pollfd pls[ 1 ];
pls[ 0 ].fd = STDIN_FILENO;
pls[ 0 ].events = POLLIN | POLLPRI;
return poll( pls, 1, timeout_ms ) > 0;
}
void flush_input() { while (is_key_pressed( 0 )) getchar(); }
// The Linux console has been UTF-8 capable for ages now.
// Alas, we must still convert individual code point values to UTF-8 before output.
void _write( const std::string & s ) { printf( "%s", s.c_str() ); fflush( stdout ); }
void _finalize()
{
Q(false);
_write( "\033[?1049l" "\033[?25h" );
tcsetattr( STDIN_FILENO, TCSANOW, &_initial_settings );
}
void _initialize()
{
Q(true);
const char * eds = getenv( "ESCDELAY" );
if (eds) _esc_delay = atoi( eds );
_esc_delay = (_esc_delay < 50) ? 50 : _esc_delay;
auto e = error( "Could not initialize terminal" );
if (tcgetattr( STDIN_FILENO, &_initial_settings ) < 0) throw e;
auto settings = _initial_settings;
settings.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | ICRNL | ISTRIP | INLCR | IXON );
settings.c_oflag &= ~(OPOST);
settings.c_cflag |= (CS8);
settings.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN | TOSTOP);
settings.c_cc[VMIN] = 0;
settings.c_cc[VTIME] = 0;
if (tcsetattr( STDIN_FILENO, TCSANOW, &settings ) < 0) throw e;
setlocale( LC_ALL, ".UTF-8" );
_write( "\033[?1049h" "\033[?25l" );
atexit( &_finalize );
}
#endif
void _output( const std::string & s ) { _initialize(); _write( s ); }
template <typename...Args> void OSC( Args...args ) { output( "\033]", args..., "\033\\" ); }
template <typename...Args> void CSI( Args...args ) { output( "\033[", args... ); }
void title( const std::string & s ) { OSC( "0;", s ); }
void clear_screen() { CSI( "2J" ); }
void gotoxy( int x, int y ) { CSI( y+1, ";", x+1, "H" ); } // Home --> 0,0
void cursor( bool visible ) { CSI( visible ? "\?25h" : "\?25l" ); }
void colors( const rgb & fg, const rgb & bg )
#define C(F,c,L) F "8;2;", (int)c.red, ";", (int)c.green, ";", (int)c.blue, L
{
CSI(C( "3", fg, ";" ), C( "4", bg, "m" ));
}
void fcolor( const rgb & c ) { CSI(C( "3", c, "m" )); }
void bcolor( const rgb & c ) { CSI(C( "4", c, "m" )); }
|