/* cs.c: Change (temporarily) or display properties of the console. Jason Hood, 27, 30 & 31 August, 2004. v1.01, 27 December, 2005: - fix window resizing at the bottom of the buffer. v2.00, 20 to 26 October, 2014: ! swapped the meaning of "m"; - fix sizing both buffer and window; * sizing buffer will size window, if necessary; * use stdout for the reduced window warnings; + use ",FACE" to select font face (Vista onwards); + option "o" to set text attribute; * always return existing values; * recognise COLS as being two WORDs, split into COLSxROWS; * allow "," (i.e. by itself) and ",-1" to set next/previous font; + return and restore existing position; * dynamically word wrap the help screen; + add "e[0|1]" and "i[0|1]" to set/query quick edit & insert modes; * rename to "Console Settings"; + option "v" to display all properties; + option "u" to set/query cursor; + option "d" to use console defaults; + option "l" to restore local values (undoes "m" & "d"); - fixed multiple display options; * use new font for the maximum window; * choose a font closer to the existing size (prefer 8x8, not 16x8); * slightly change the position of the maximum window; - use the work area for positioning (todo: multiple monitors); + additional "p" options to center horizontally OR vertically. */ #define PVERS "2.00" #define PDATE "26 October, 2014" #define _CRT_SECURE_NO_WARNINGS #define _WIN32_WINNT 0x400 // stop MinGW from defining GetConsoleWindow #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #ifdef _MSC_VER __declspec(noreturn) #elif __GNUC__ __attribute__((noreturn)) #endif void help( BOOL ); void wrap_text( int, const char* ); BOOL redir; HANDLE con, conin; CONSOLE_SCREEN_BUFFER_INFO csbi; COORD cur_win, max_win; void buf_size( SHORT, SHORT ); void win_size( SHORT, SHORT ); void font_size( void ); void win_pos( void ); int pos_mask( char ); #ifndef ENABLE_EXTENDED_FLAGS #define ENABLE_EXTENDED_FLAGS 0x80 #define ENABLE_QUICK_EDIT_MODE 0x40 #define ENABLE_INSERT_MODE 0x20 #endif // Version-dependent console functions. // Console font structure (CONSOLE_FONT_INFO). typedef struct _CONSOLE_FONT { DWORD nFont; COORD dwFontSize; } CONSOLE_FONT, *PCONSOLE_FONT; // Extended console font structure (CONSOLE_FONT_INFOEX). typedef struct _CONSOLE_FONTEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; } CONSOLE_FONTEX, *PCONSOLE_FONTEX; typedef BOOL (WINAPI *GetConsoleFontInfoT)( HANDLE,BOOL,DWORD,PCONSOLE_FONT ); typedef COORD (WINAPI *GetConsoleFontSizeT)( HANDLE, DWORD ); typedef HWND (WINAPI *GetConsoleOriginalTitleWT)( LPWSTR, DWORD ); typedef HWND (WINAPI *GetConsoleWindowT)( void ); typedef BOOL (WINAPI *GetCurrentConsoleFontT)( HANDLE, BOOL, PCONSOLE_FONT ); typedef BOOL (WINAPI *GetCurrentConsoleFontExT)( HANDLE, BOOL, PCONSOLE_FONTEX ); typedef DWORD (WINAPI *GetNumberOfConsoleFontsT)( VOID ); typedef BOOL (WINAPI *SetConsoleFontT)( HANDLE, DWORD ); typedef BOOL (WINAPI *SetCurrentConsoleFontExT)( HANDLE, BOOL, PCONSOLE_FONTEX ); GetConsoleFontInfoT GetConsoleFontInfo; GetConsoleFontSizeT GetConsoleFontSize; GetConsoleOriginalTitleWT GetConsoleOriginalTitleW; GetConsoleWindowT GetConsoleWindow; GetCurrentConsoleFontT GetCurrentConsoleFont; GetCurrentConsoleFontExT GetCurrentConsoleFontEx; GetNumberOfConsoleFontsT GetNumberOfConsoleFonts; SetConsoleFontT SetConsoleFont; SetCurrentConsoleFontExT SetCurrentConsoleFontEx; // End console functions. #define MAX_FONTS 100 CONSOLE_FONTEX cur_font = { sizeof(cur_font) }; BOOL InitConsoleFont( VOID ); BOOL find_font( VOID ); void GetConsoleDefaults( VOID ); struct { COORD buf; // buffer size COORD win; // window size COORD font; // font size BOOL quiet; // prevent display BOOL a; // set both buffer & window sizes BOOL b; // set buffer size BOOL w; // set window size int f; // set font size int fi; // relative font index int p; // set position char face[LF_FACESIZE]; // font face name int facelen; // length of above } option; struct { COORD buf; COORD win; COORD font; char face[LF_FACESIZE]; int weight; DWORD attr; BOOL quickedit; BOOL insmode; DWORD cursor; COORD pos; } defcon = { { 80, 25 }, { 80, 25 }, { 8, 12 }, { '\0' }, 400, 7, FALSE, FALSE, 25, { -1, -1 } }; // Bitmasks of values to display. #define BUF_COLS 0x00000001 #define BUF_ROWS 0x00000002 #define WIN_COLS 0x00000004 #define WIN_ROWS 0x00000008 #define MAX_COLS 0x00000010 #define MAX_ROWS 0x00000020 #define FONT_WID 0x00000040 #define FONT_HYT 0x00000080 #define DEF_BUF_COLS 0x00000100 #define DEF_BUF_ROWS 0x00000200 #define DEF_WIN_COLS 0x00000400 #define DEF_WIN_ROWS 0x00000800 #define DEF_FONT_WID 0x00001000 #define DEF_FONT_HYT 0x00002000 #define BUF 0x00004000 #define WIN 0x00008000 #define MAX_WIN 0x00010000 #define FONT 0x00020000 #define ATTR 0x00040000 #define QUICKEDIT 0x00080000 #define INSMODE 0x00100000 #define CURSOR 0x00200000 #define DEF_BUF 0x00400000 #define DEF_WIN 0x00800000 #define DEF_FONT 0x01000000 #define DEF_ATTR 0x02000000 #define DEF_QUICKEDIT 0x04000000 #define DEF_INSMODE 0x08000000 #define DEF_CURSOR 0x10000000 #define MAX 1 // display maximum window values #define DEFAULT 2 // display default values // Type of the value. enum { NUM_NONE, NUM_NUM, NUM_MAX, NUM_DEF }; // Position masks. #define POS_LEFT 0x01 #define POS_HMID 0x02 #define POS_RIGHT 0x04 #define POS_TOP 0x08 #define POS_VMID 0x10 #define POS_BOTTOM 0x20 // Map position numbers to their masks. const int pos_map[] = { POS_HMID | POS_VMID, // 0 - center POS_LEFT | POS_TOP, // 1 - top-left POS_RIGHT | POS_TOP, // 2 - top-right POS_LEFT | POS_BOTTOM, // 3 - bottom-left POS_RIGHT | POS_BOTTOM, // 4 - bottom-right POS_HMID | POS_TOP, // 5 - top-center POS_HMID | POS_BOTTOM, // 6 - bottom-center POS_LEFT | POS_VMID, // 7 - center-left POS_RIGHT | POS_VMID, // 8 - center-right }; // Return codes. #define E_OK 0 // no problem #define E_OPTION -1 // problem with option, unknown option #define E_CONSOLE -2 // invalid parameters to console function #define E_SYSTEM -3 // problem accessing console functions // Cast a COORD to int, avoiding gcc's strict aliasing warning. #ifdef __GNUC__ union ICOORD { COORD c; int i; }; static inline int c2i( COORD c ) { union ICOORD ic; ic.c = c; return ic.i; } #else #define c2i( c ) *(int*)&(c) #endif int main( int argc, char* argv[] ) { char opt, nopt = '\0'; COORD* size = &option.win; COORD* defsize = &defcon.win; CONSOLE_CURSOR_INFO cci; int num_type; SHORT num, nnum; char* end; BOOL setting = FALSE; int display = 0, display_mode = 0; DWORD mode = 0; int j, k; int rc; // Set the code page so the face name (which is wide) displays correctly. char cp[8]; sprintf( cp, ".%u", GetConsoleOutputCP() ); setlocale( LC_CTYPE, cp ); redir = !_isatty( 1 ); con = CreateFile( "CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); rc = GetConsoleScreenBufferInfo( con, &csbi ); if (!rc) csbi.dwSize.X = 80; if (!InitConsoleFont()) option.f = -1; if (argc == 1 || strcmp( argv[1], "--help" ) == 0) help( argc == 1 ); if (strcmp( argv[1], "--version" ) == 0) { wrap_text( 0, "Console Settings version " PVERS " (" PDATE ").\n" ); return E_OK; } if (!rc) { fputs( "Unable to retrieve console information.\n", stderr ); return E_SYSTEM; } max_win = GetLargestConsoleWindowSize( con ); cur_win.X = csbi.srWindow.Right - csbi.srWindow.Left + 1; cur_win.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; rc = c2i( cur_win ); conin = CreateFile( "CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); GetConsoleMode( conin, &mode ); mode |= ENABLE_EXTENDED_FLAGS; GetConsoleCursorInfo( con, &cci ); GetConsoleDefaults(); for (j = 1; j < argc; ++j) { for (k = 0; argv[j][k] || nopt; ) { num = 0; num_type = NUM_NONE; if (nopt) { opt = nopt; num = nnum; num_type = NUM_NUM; nopt = '\0'; } else { opt = argv[j][k++]; if ((opt == '/' || opt == '-') && argv[j][k] != '\0') opt = argv[j][k++]; if (opt == '?') help( FALSE ); if (isdigit( opt )) { opt = 'c'; --k; } else { opt = tolower( opt ); if (opt == 'x') opt = 'r'; } } if (strchr( ",ceiopru", opt )) { if (argv[j][k] == '\0' && argv[j+1] != NULL && opt != ',') ++j, k = 0; if (isdigit( argv[j][k] ) || (argv[j][k] == '-' && isdigit( argv[j][k+1] ))) { long lnum = strtol( argv[j] + k, &end, 0 ); num = (SHORT)lnum; if (num < 0 && opt != ',') num = -num; num_type = NUM_NUM; if (lnum > 65535) { if (opt == 'c') { nopt = 'r'; nnum = (SHORT)(lnum >> 16); } else if (opt == 'p') { option.p = lnum; num_type = NUM_NONE; } } k = end - argv[j]; setting = TRUE; } else if (argv[j][k] == '#') { num = (SHORT)strtoul( argv[j] + k + 1, &end, 16 ); num_type = NUM_NUM; k = end - argv[j]; setting = TRUE; } else if (opt == ',' || opt == 'p') { setting = TRUE; if (opt == 'p' && argv[j][k] == 'd') { num_type = NUM_DEF; ++k; setting = TRUE; } } else if (argv[j][k] == 'm' && (opt == 'c' || opt == 'r')) { num_type = NUM_MAX; ++k; setting = TRUE; } else if (argv[j][k] == 'd') { num_type = NUM_DEF; ++k; setting = TRUE; } } else if (strchr( "abfw", opt )) { if (argv[j][k] == 'm' && opt != 'f') { num_type = NUM_MAX; ++k; setting = TRUE; } else if (argv[j][k] == 'd') { num_type = NUM_DEF; ++k; setting = TRUE; } } switch (opt) { case 'a': case 'b': if (num_type == NUM_MAX) { option.buf.X = option.buf.Y = -1; } else if (num_type == NUM_DEF) { option.buf.X = defcon.buf.X; option.buf.Y = defcon.buf.Y; if (opt == 'a') { option.win.X = defcon.win.X; option.win.Y = defcon.win.Y; } } size = &option.buf; defsize = &defcon.buf; if (display_mode == DEFAULT) { display |= DEF_BUF; rc = c2i( defcon.buf ); } else if (display_mode == MAX) { display |= BUF; rc = c2i( max_win ); } else { display |= BUF; rc = c2i( csbi.dwSize ); } if (opt == 'a') { display |= (display_mode == MAX) ? MAX_WIN : (display_mode == DEFAULT) ? DEF_WIN : WIN; option.a = TRUE; } else option.b = TRUE; break; case 'w': if (num_type == NUM_MAX) { option.win.X = option.win.Y = -1; } else if (num_type == NUM_DEF) { option.win.X = defcon.win.X; option.win.Y = defcon.win.Y; } size = &option.win; defsize = &defcon.win; if (display_mode == MAX) { display |= MAX_WIN; rc = c2i( max_win ); } else if (display_mode == DEFAULT) { display |= DEF_WIN; rc = c2i( defcon.win ); } else { display |= WIN; rc = c2i( cur_win ); } option.w = TRUE; break; case 'm': display_mode = MAX; display |= MAX_WIN; rc = c2i( max_win ); break; case 'd': display_mode = DEFAULT; break; case 'l': display_mode = 0; break; case 'f': case ',': if (option.f < 0) { fputs( "Console font functions not available.\n", stderr ); return E_SYSTEM; } size = &option.font; defsize = &defcon.font; rc = (display_mode == DEFAULT) ? c2i( defcon.font ) : c2i( cur_font.dwFontSize ); option.f = TRUE; if (opt == 'f') { if (num_type == NUM_DEF) { option.font.X = defcon.font.X; option.font.Y = defcon.font.Y; if (*defcon.face) { option.facelen = mbstowcs( cur_font.FaceName, defcon.face, LF_FACESIZE ); cur_font.FontWeight = defcon.weight; } } display |= (display_mode == DEFAULT) ? DEF_FONT : FONT; break; } rc = cur_font.nFont; if (num_type == NUM_NONE && argv[j][k] != ',' && argv[j][k] != '\0') { if (!SetCurrentConsoleFontEx) { fputs( "Font face selection not available.\n", stderr ); return E_SYSTEM; } option.facelen = 0; cur_font.FontWeight = 400; while (argv[j][k] != '/' && argv[j][k] != '\0') { option.face[option.facelen++] = argv[j][k++]; if (option.facelen == LF_FACESIZE) break; } if (option.face[option.facelen-1] == '+') { cur_font.FontWeight = 700; --option.facelen; } else if (option.face[option.facelen-1] == '-') { --option.facelen; } if (option.facelen == 0) { // Just changing the weight of the current font. if (cur_font.FontFamily & 4) option.facelen = 1; } else if (!find_font()) { fputs( "Font face not found or prefix not unique.\n", stderr ); return E_OPTION; } if (!option.font.Y) option.font.Y = cur_font.dwFontSize.Y; } else if (num_type == NUM_NONE) ++option.fi; else option.fi = num; break; case 'c': if (num_type == NUM_NUM) { if (option.a || option.b || option.w || option.f) size->X = num; else option.buf.X = option.win.X = num; } else if (num_type == NUM_MAX) { size->X = -1; } else if (num_type == NUM_DEF) { size->X = defsize->X; } if (size == &option.buf) { if (display_mode == DEFAULT) { display |= DEF_BUF_COLS; rc = defcon.buf.X; } else { display |= BUF_COLS; rc = csbi.dwSize.X; } } else if (size == &option.win) { if (display_mode == MAX) { display |= MAX_COLS; rc = max_win.X; } else if (display_mode == DEFAULT) { display |= DEF_WIN_COLS; rc = defcon.win.X; } else { display |= WIN_COLS; rc = cur_win.X; } } else // (size == &option.font) { if (display_mode == DEFAULT) { display |= DEF_FONT_WID; rc = defcon.font.X; } else { display |= FONT_WID; rc = cur_font.dwFontSize.X; } } break; case 'r': if (num_type == NUM_NUM) { size->Y = num; } else if (num_type == NUM_MAX) { size->Y = -1; } else if (num_type == NUM_DEF) { size->Y = defsize->Y; } if (size == &option.buf) { if (display_mode == DEFAULT) { display |= DEF_BUF_ROWS; rc = defcon.buf.Y; } else { display |= BUF_ROWS; rc = csbi.dwSize.Y; } } else if (size == &option.win) { if (display_mode == MAX) { display |= MAX_ROWS; rc = max_win.Y; } else if (display_mode == DEFAULT) { display |= DEF_WIN_ROWS; rc = defcon.win.Y; } else { display |= WIN_ROWS; rc = cur_win.Y; } } else // (size == &option.font) { if (display_mode == DEFAULT) { display |= DEF_FONT_HYT; rc = defcon.font.Y; } else { display |= FONT_HYT; rc = cur_font.dwFontSize.Y; } } break; case 'o': if (num_type == NUM_DEF) num = (SHORT)defcon.attr; if (num_type != NUM_NONE) SetConsoleTextAttribute( con, num ); if (display_mode == DEFAULT) { display |= DEF_ATTR; rc = defcon.attr; } else { display |= ATTR; rc = csbi.wAttributes; } break; case 'e': if (num_type == NUM_DEF) num = defcon.quickedit; if (num_type != NUM_NONE) { if (num) mode |= ENABLE_QUICK_EDIT_MODE; else mode &= ~ENABLE_QUICK_EDIT_MODE; SetConsoleMode( conin, mode ); } if (display_mode == DEFAULT) { display |= DEF_QUICKEDIT; rc = defcon.quickedit; } else { display |= QUICKEDIT; rc = (mode & ENABLE_QUICK_EDIT_MODE) ? 1 : 0; } break; case 'i': if (num_type == NUM_DEF) num = defcon.insmode; if (num_type != NUM_NONE) { if (num) mode |= ENABLE_INSERT_MODE; else mode &= ~ENABLE_INSERT_MODE; SetConsoleMode( conin, mode ); } if (display_mode == DEFAULT) { display |= DEF_INSMODE; rc = defcon.insmode; } else { display |= INSMODE; rc = (mode & ENABLE_INSERT_MODE) ? 1 : 0; } break; case 'u': if (num_type == NUM_DEF) num = (SHORT)defcon.cursor; if (num_type != NUM_NONE) { CONSOLE_CURSOR_INFO ci; ci.dwSize = cci.dwSize; if (num <= 0) { ci.bVisible = FALSE; } else { ci.bVisible = TRUE; if (num != 1) ci.dwSize = min( num, 100 ); } SetConsoleCursorInfo( con, &ci ); } if (display_mode == DEFAULT) { display |= DEF_CURSOR; rc = defcon.cursor; } else { display |= CURSOR; rc = (!cci.bVisible) ? 0 : (cci.dwSize == 1) ? 2 : cci.dwSize; } break; case 'p': { RECT window; HWND win = GetConsoleWindow(); GetWindowRect( win, &window ); // Add 1 to the line to distinguish from the placements. rc = ((SHORT)(window.top + 1) << 16) | (SHORT)window.left; if (option.p) { SetWindowPos( win, 0, (SHORT)option.p, (option.p >> 16) - 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); option.p = 0; } else if (num_type == NUM_DEF) { if (defcon.pos.X != -1) SetWindowPos( win, 0, defcon.pos.X, defcon.pos.Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); } else if (num_type == NUM_NUM) { if (num > 8) { fprintf( stderr, "Position must be between 0 and 8: %d.\n", num ); return E_OPTION; } option.p = pos_map[num]; } else // (num_type == NUM_NONE) { option.p = pos_mask( argv[j][k] ); if (option.p) { int mask = pos_mask( argv[j][++k] ); if (mask) { option.p |= mask; ++k; } } else { option.p = pos_map[0]; } } } break; case 'q': option.quiet = TRUE; break; case 'v': // v - display current // dv - display default // vd - display both if (argv[j][k] == 'd') { ++k; display = -1; } else if (display_mode == DEFAULT) { display = DEF_BUF | DEF_WIN | DEF_FONT | DEF_ATTR | DEF_QUICKEDIT | DEF_INSMODE | DEF_CURSOR; } else { display = BUF | WIN | MAX_WIN | FONT | ATTR | QUICKEDIT | INSMODE | CURSOR; } break; default: fprintf( stderr, "Unknown option: %c.\n", opt ); return E_OPTION; } } } // If 'd' is used by itself, set everything. if (display_mode == DEFAULT && display == 0) { option.buf.X = defcon.buf.X; option.buf.Y = defcon.buf.Y; option.win.X = defcon.win.X; option.win.Y = defcon.win.Y; option.font.X = defcon.font.X; option.font.Y = defcon.font.Y; if (*defcon.face) { option.facelen = mbstowcs( cur_font.FaceName, defcon.face, LF_FACESIZE ); cur_font.FontWeight = defcon.weight; } option.f = TRUE; setting = TRUE; SetConsoleTextAttribute( con, (WORD)defcon.attr ); mode &= ~(ENABLE_QUICK_EDIT_MODE | ENABLE_INSERT_MODE); if (defcon.quickedit) mode |= ENABLE_QUICK_EDIT_MODE; if (defcon.insmode) mode |= ENABLE_INSERT_MODE; SetConsoleMode( conin, mode ); cci.bVisible = TRUE; cci.dwSize = defcon.cursor; SetConsoleCursorInfo( con, &cci ); if (defcon.pos.X != -1) { SetWindowPos( GetConsoleWindow(), 0, defcon.pos.X, defcon.pos.Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); } } if (!setting) { if (!option.quiet) { if (display == -1) { char face[LF_FACESIZE]; wcstombs( face, cur_font.FaceName, LF_FACESIZE ); printf( "Buffer: %d x %d (default", csbi.dwSize.X, csbi.dwSize.Y ); if (csbi.dwSize.X != defcon.buf.X || csbi.dwSize.Y != defcon.buf.Y) printf( ": %d x %d", defcon.buf.X, defcon.buf.Y ); printf( ")\nWindow: %d x %d (default", cur_win.X, cur_win.Y ); if (cur_win.X != defcon.win.X || cur_win.Y != defcon.win.Y) printf( ": %d x %d", defcon.win.X, defcon.win.Y ); if (defcon.pos.X != -1) { RECT window; GetWindowRect( GetConsoleWindow(), &window ); if (defcon.pos.X != window.left || defcon.pos.Y != window.top) printf( " @ %d,%d", defcon.pos.X, defcon.pos.Y ); } printf( ")\nFont: %d x %d", cur_font.dwFontSize.X, cur_font.dwFontSize.Y ); if (*face) { printf( " %s", face ); if (cur_font.FontWeight == 700) putchar( '+' ); } printf( " (default" ); if ((cur_font.dwFontSize.X != defcon.font.X && defcon.font.X != 0) || cur_font.dwFontSize.Y != defcon.font.Y || strcmp( face, defcon.face ) != 0) { if (defcon.font.X == 0) printf( ": %d", defcon.font.Y ); else printf( ": %d x %d", defcon.font.X, defcon.font.Y ); if (*defcon.face) { printf( " %s", defcon.face ); if (defcon.weight == 700) putchar( '+' ); } } printf( ")\nAttribute: %d (#%.2X; default", csbi.wAttributes, csbi.wAttributes ); if (csbi.wAttributes != defcon.attr) printf( ": %lu/#%.2lX", defcon.attr, defcon.attr ); printf( ")\nQuick edit: %s (default", (mode & ENABLE_QUICK_EDIT_MODE) ? "on" : "off" ); if (!!(mode & ENABLE_QUICK_EDIT_MODE) != defcon.quickedit) printf( ": %s", defcon.quickedit ? "on" : "off" ); printf( ")\nInsert mode: %s (default", (mode & ENABLE_INSERT_MODE) ? "on" : "off" ); if (!!(mode & ENABLE_INSERT_MODE) != defcon.insmode) printf( ": %s", defcon.insmode ? "on" : "off" ); printf( ")\nCursor: %lu%% (%sdefault", cci.dwSize, (!cci.bVisible) ? "hidden; " : "" ); if (cci.dwSize != defcon.cursor) printf( ": %lu%%", defcon.cursor ); puts( ")" ); return rc; } if ((display & BUF) && !(display & (BUF_COLS | BUF_ROWS))) { printf( "Buffer: %d x %d\n", csbi.dwSize.X, csbi.dwSize.Y ); } else { if (display & BUF_COLS) { printf( "Buffer: %d columns\n", csbi.dwSize.X ); } if (display & BUF_ROWS) { printf( "Buffer: %d rows\n", csbi.dwSize.Y ); } } if ((display & WIN) && !(display & (WIN_COLS | WIN_ROWS))) { printf( "Window: %d x %d\n", cur_win.X, cur_win.Y ); } else { if (display & WIN_COLS) { printf( "Window: %d columns\n", cur_win.X ); } if (display & WIN_ROWS) { printf( "Window: %d rows\n", cur_win.Y ); } } if (display & MAX_WIN) { printf( "Largest%s: %d x %d\n", (display & (WIN | WIN_COLS | WIN_ROWS)) ? "" : " window", max_win.X, max_win.Y ); } else { if (display & MAX_COLS) { printf( "Largest%s: %d columns\n", (display & (WIN | WIN_COLS | WIN_ROWS)) ? "" : " window", max_win.X ); } if (display & MAX_ROWS) { printf( "Largest%s: %d rows\n", (display & (WIN | WIN_COLS | WIN_ROWS)) ? "" : " window", max_win.Y ); } } if ((display & FONT) && !(display & (FONT_WID | FONT_HYT))) { printf( "Font: %d x %d", cur_font.dwFontSize.X, cur_font.dwFontSize.Y ); if (*cur_font.FaceName) { printf( " %S", cur_font.FaceName ); if (cur_font.FontWeight == 700) putchar( '+' ); } putchar( '\n' ); } else { if (display & FONT_WID) { printf( "Font: %d pixels wide\n", cur_font.dwFontSize.X ); } if (display & FONT_HYT) { printf( "Font: %d pixels high\n", cur_font.dwFontSize.Y ); } } if (display & ATTR) { printf( "Attribute: %d (#%.2X)\n", csbi.wAttributes, csbi.wAttributes ); } if (display & QUICKEDIT) { printf( "Quick edit: %s\n", (mode & ENABLE_QUICK_EDIT_MODE) ? "on" : "off" ); } if (display & INSMODE) { printf( "Insert mode: %s\n", (mode & ENABLE_INSERT_MODE) ? "on" : "off" ); } if (display & CURSOR) { printf( "Cursor: %lu%%%s\n", cci.dwSize, (!cci.bVisible) ? " (hidden)" : "" ); } if ((display & DEF_BUF) && !(display & (DEF_BUF_COLS | DEF_BUF_ROWS))) { printf( "Default buffer: %d x %d\n", defcon.buf.X, defcon.buf.Y ); } else { if (display & DEF_BUF_COLS) { printf( "Default buffer: %d columns\n", defcon.buf.X ); } if (display & DEF_BUF_ROWS) { printf( "Default buffer: %d rows\n", defcon.buf.Y ); } } if ((display & DEF_WIN) && !(display & (DEF_WIN_COLS | DEF_WIN_ROWS))) { printf( "Default window: %d x %d", defcon.win.X, defcon.win.Y ); if (defcon.pos.X != -1) printf( " @ %d,%d", defcon.pos.X, defcon.pos.Y ); putchar( '\n' ); } else { if (display & DEF_WIN_COLS) { printf( "Default window: %d columns\n", defcon.win.X ); } if (display & DEF_WIN_ROWS) { printf( "Default window: %d rows\n", defcon.win.Y ); } } if ((display & DEF_FONT) && !(display & (DEF_FONT_WID | DEF_FONT_HYT))) { printf( "Default font: " ); if (defcon.font.X == 0) printf( "%d", defcon.font.Y ); else printf( "%d x %d", defcon.font.X, defcon.font.Y ); if (*defcon.face) { printf( " %s", defcon.face ); if (defcon.weight == 700) putchar( '+' ); } putchar( '\n' ); } else { if (display & DEF_FONT_WID) { printf( "Default font: %d pixels wide\n", defcon.font.X ); } if (display & DEF_FONT_HYT) { printf( "Default font: %d pixels high\n", defcon.font.Y ); } } if (display & DEF_ATTR) { printf( "Default attribute: %lu (#%.2lX)\n", defcon.attr, defcon.attr ); } if (display & DEF_QUICKEDIT) { printf( "Default quick edit: %s\n", (defcon.quickedit) ? "on" : "off" ); } if (display & DEF_INSMODE) { printf( "Default insert mode: %s\n", (defcon.insmode) ? "on" : "off" ); } if (display & DEF_CURSOR) { printf( "Default cursor: %lu%%\n", defcon.cursor ); } } return rc; } if (option.f) { COORD old_win = cur_win; font_size(); if (!option.quiet) { // Show the new font dimensions if iterating through the fonts. if (!option.font.X && !option.font.Y && !option.facelen) { printf( "Font: %d x %d", cur_font.dwFontSize.X, cur_font.dwFontSize.Y ); if (*cur_font.FaceName) { printf( " %S", cur_font.FaceName ); if (cur_font.FontWeight == 700) putchar( '+' ); } putchar( '\n' ); } // Warn if the new font resized the window. if (!option.buf.X && !option.buf.Y && !option.win.X && !option.win.Y) { if (old_win.X != cur_win.X) { if (old_win.Y != cur_win.Y) printf( "Window reduced to %d x %d.\n", cur_win.X, cur_win.Y ); else printf( "Window reduced to %d columns.\n", cur_win.X ); } else if (old_win.Y != cur_win.Y) printf( "Window reduced to %d rows.\n", cur_win.Y ); } } } // Set maximum values based on the new font. if (option.buf.X == -1) option.buf.X = max_win.X; if (option.buf.Y == -1) option.buf.Y = max_win.Y; if (option.win.X == -1) option.win.X = max_win.X; if (option.win.Y == -1) option.win.Y = max_win.Y; // If using only cols OR rows with 'a', keep the existing other. if (option.a) { if (option.win.X == 0) option.win.X = (option.buf.X == 0) ? cur_win.X : option.buf.X; if (option.win.Y == 0) option.win.Y = (option.buf.Y == 0) ? cur_win.Y : option.buf.Y; } // If the buffer wasn't specified, ensure it's at least as big as the window. if (option.buf.X == 0) option.buf.X = max( csbi.dwSize.X, option.win.X ); if (option.buf.Y == 0) option.buf.Y = max( csbi.dwSize.Y, option.win.Y ); // If the window wasn't specified, ensure it's no bigger than the buffer. if (option.win.X == 0) option.win.X = min( option.buf.X, cur_win.X ); if (option.win.Y == 0) option.win.Y = min( option.buf.Y, cur_win.Y ); // The buffer must still be at least as big as the window. if (option.buf.X < option.win.X) option.buf.X = option.win.X; if (option.buf.Y < option.win.Y) option.buf.Y = option.win.Y; if (option.win.X > max_win.X) { if (option.win.Y > max_win.Y) fprintf( stderr, "Window too big: %d x %d (max. %d x %d).\n", option.win.X, option.win.Y, max_win.X, max_win.Y ); else fprintf( stderr, "Window too wide: %d (max. %d).\n", option.win.X, max_win.X ); return E_OPTION; } else if (option.win.Y > max_win.Y) { fprintf( stderr, "Window too high: %d (max. %d).\n", option.win.Y, max_win.Y ); return E_OPTION; } // Resizing needs to be done in a particular order, since the buffer // cannot be made smaller than the window, and the window cannot be // made bigger than the buffer. if (option.buf.X < cur_win.X) win_size( option.win.X, cur_win.Y ); if (option.buf.Y < cur_win.Y) win_size( cur_win.X, option.win.Y ); buf_size( option.buf.X, option.buf.Y ); win_size( option.win.X, option.win.Y ); win_pos(); return rc; } void buf_size( SHORT x, SHORT y ) { COORD size; if (x == csbi.dwSize.X && y == csbi.dwSize.Y) return; size.X = x; size.Y = y; if (!SetConsoleScreenBufferSize( con, size )) { fprintf( stderr, "Unable to set buffer size: %d x %d.\n", x, y ); exit( E_CONSOLE ); } csbi.dwSize.X = x; csbi.dwSize.Y = y; } void win_size( SHORT x, SHORT y ) { SMALL_RECT win; if (x == cur_win.X && y == cur_win.Y) return; win.Left = 0; win.Top = 0; win.Right = x - cur_win.X; win.Bottom = y - cur_win.Y; if (win.Bottom + csbi.srWindow.Bottom >= csbi.dwSize.Y) { win.Top = -win.Bottom; win.Bottom = 0; } if (!SetConsoleWindowInfo( con, FALSE, &win )) { fprintf( stderr, "Unable to set console window: %d x %d.\n", x, y ); exit( E_CONSOLE ); } cur_win.X = x; cur_win.Y = y; } void font_size( void ) { CONSOLE_FONT font[MAX_FONTS]; CONSOLE_SCREEN_BUFFER_INFO csbi; int fonts; BOOL find = TRUE; int fnt = -1, d, d1; int j; fonts = GetNumberOfConsoleFonts(); if (fonts > MAX_FONTS) fonts = MAX_FONTS; // These don't appear to fail. GetConsoleFontInfo( con, 0, fonts, font ); for (j = fonts; --j >= 0;) font[j].dwFontSize = GetConsoleFontSize( con, font[j].nFont ); // Find the next largest font capable of displaying the window. if (option.font.X == 0 && option.font.Y == 0) { RECT desktop; int wid, hyt; SystemParametersInfo( SPI_GETWORKAREA, 0, &desktop, 0 ); desktop.bottom -= desktop.top + GetSystemMetrics( SM_CYCAPTION ); desktop.right -= desktop.left; wid = (option.win.X == -1) ? max_win.X : (option.win.X != 0) ? option.win.X : (!option.a || option.buf.X == 0) ? cur_win.X : option.buf.X; hyt = (option.win.Y == -1) ? max_win.Y : (option.win.Y != 0) ? option.win.Y : (!option.a || option.buf.Y == 0) ? cur_win.Y : option.buf.Y; find = FALSE; for (j = cur_font.nFont; j >= 0; --j) { desktop.left = desktop.right / font[j].dwFontSize.X; desktop.top = desktop.bottom / font[j].dwFontSize.Y; if (wid <= desktop.left && hyt <= desktop.top) { fnt = j; option.font.Y = font[j].dwFontSize.Y; find = TRUE; break; } } } else { // Changing the height of the current font always works with TrueType. if ((cur_font.FontFamily & 4) && !option.facelen && !option.font.X && !option.fi) option.facelen = 1; if (option.facelen) find = FALSE; } if (find) { d = 255; // Find a font of a particular height, closest to the current width. if (option.font.X == 0) { for (j = 0; j < fonts; ++j) { if (font[j].dwFontSize.Y == option.font.Y) { d1 = font[j].dwFontSize.X - cur_font.dwFontSize.X; if (d1 < 0) d1 = -d1; if (d1 < d) { fnt = j; if (d1 == 0) break; d = d1; } } } } else { for (j = 0; j < fonts; ++j) { if (font[j].dwFontSize.X == option.font.X) { // Find a font of a particular width, closest to the current height. if (option.font.Y == 0) { d1 = font[j].dwFontSize.Y - cur_font.dwFontSize.Y; if (d1 < 0) d1 = -d1; if (d1 < d) { fnt = j; if (d1 == 0) break; d = d1; } } // Find an exact font size. else if (font[j].dwFontSize.Y == option.font.Y) { fnt = j; break; } } } } } if (fnt < 0 && !option.facelen) { fputs( "Unable to find font ", stderr ); if (option.font.X == 0 && option.font.Y == 0) fprintf( stderr, "to fit the window %d x %d on screen.\n", option.win.X, option.win.Y ); else if (option.font.X == 0) fprintf( stderr, "of height %d.\n", option.font.Y ); else if (option.font.Y == 0) fprintf( stderr, "of width %d.\n", option.font.X ); else fprintf( stderr, "%d x %d.\n", option.font.X, option.font.Y ); exit( E_OPTION ); } if (option.facelen) { cur_font.FontFamily = FF_DONTCARE; cur_font.dwFontSize = option.font; SetCurrentConsoleFontEx( con, 0, &cur_font ); GetCurrentConsoleFontEx( con, 0, &cur_font ); } else { // If dimensions were given, ensure the index still matches them. if (option.font.X != 0 || option.font.Y != 0) { while (option.fi > 0 && fnt + 1 < fonts) { if (font[fnt+1].dwFontSize.X != font[fnt].dwFontSize.X || font[fnt+1].dwFontSize.Y != font[fnt].dwFontSize.Y) break; ++fnt; --option.fi; } } else { fnt += option.fi; if (fnt < 0) fnt = 0; else if (fnt > fonts - 1) fnt = fonts - 1; } if (font[fnt].nFont == cur_font.nFont) return; if (!SetConsoleFont( con, font[fnt].nFont )) { fprintf( stderr, "Unable to set font: %d x %d.\n", font[fnt].dwFontSize.X, font[fnt].dwFontSize.Y ); exit( E_CONSOLE ); } if (GetCurrentConsoleFontEx) GetCurrentConsoleFontEx( con, 0, &cur_font ); else { cur_font.nFont = font[fnt].nFont; cur_font.dwFontSize = font[fnt].dwFontSize; } } // Setting a larger font may reduce the size of the window. GetConsoleScreenBufferInfo( con, &csbi ); cur_win.X = csbi.srWindow.Right - csbi.srWindow.Left + 1; cur_win.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; max_win = GetLargestConsoleWindowSize( con ); } // Translate a letter to a position mask. // Returns the mask or 0 if invalid. int pos_mask( char let ) { switch (let) { case 'l': return POS_LEFT; case 'h': return POS_HMID; case 'r': return POS_RIGHT; case 't': return POS_TOP; case 'v': return POS_VMID; case 'b': return POS_BOTTOM; } return 0; } // Reposition the window to keep it on-screen, or at a specific location. void win_pos( void ) { HWND win; RECT desktop, window; int scroll_wid, scroll_hyt; BOOL move = FALSE; SystemParametersInfo( SPI_GETWORKAREA, 0, &desktop, 0 ); win = GetConsoleWindow(); // Needs a bit of time to resize. Sleep( 10 ); GetWindowRect( win, &window ); scroll_wid = (option.buf.Y > option.win.Y) ? GetSystemMetrics( SM_CXVSCROLL ) : 0; scroll_hyt = (option.buf.X > option.win.X) ? GetSystemMetrics( SM_CYHSCROLL ) : 0; if (option.p) { int wid = window.right - window.left; int hyt = window.bottom - window.top; int left = desktop.right - wid; int top = desktop.bottom - hyt; if (option.p & POS_HMID) { // Center the actual console screen, rather than the window itself. window.left = (left + scroll_wid + desktop.left) / 2; } if (option.p & POS_VMID) { window.top = (top - GetSystemMetrics( SM_CYCAPTION ) + scroll_hyt + desktop.top) / 2; } if (option.p & POS_LEFT) { window.left = desktop.left; } if (option.p & POS_RIGHT) { window.left = left; } if (option.p & POS_TOP) { window.top = desktop.top; } if (option.p & POS_BOTTOM) { window.top = top; } window.right = window.left + wid; window.bottom = window.top + hyt; move = TRUE; } else { // Creating a maximum window may move it off the top and left, so put it // back if the window becomes smaller. if (window.left < desktop.left) { window.right += desktop.left - window.left; window.left = desktop.left; move = TRUE; } if (window.top < desktop.top) { window.bottom += desktop.top - window.top; window.top = desktop.top; move = TRUE; } } // If the new size has gone off-screen, bring it back. if (window.right > desktop.right) { window.left -= window.right - desktop.right; if (window.left < desktop.left) { if (scroll_wid) { int con_wid = cur_win.X * cur_font.dwFontSize.X; int win_wid = desktop.right - window.left; int frame_wid = (win_wid - scroll_wid - con_wid) / 2; // Ensure at least four pixels of the scroll bar are visible, provided // that doesn't remove any text. window.left = desktop.left - frame_wid / 2; while (window.left + frame_wid + con_wid + 4 > desktop.right) --window.left; if (window.left < desktop.left - frame_wid) window.left = desktop.left - frame_wid; } else { window.left = (window.left + desktop.left) / 2; } } move = TRUE; } if (window.bottom > desktop.bottom) { window.top -= window.bottom - desktop.bottom; if (window.top < desktop.top) { int con_hyt = cur_win.Y * cur_font.dwFontSize.Y; int win_hyt = window.bottom - (window.bottom - desktop.bottom) - window.top; int frame_hyt = (win_hyt - GetSystemMetrics( SM_CYCAPTION ) - scroll_hyt - con_hyt) / 2; if (scroll_hyt) window.bottom = desktop.bottom + frame_hyt + scroll_hyt - 4; else window.bottom = desktop.bottom + frame_hyt / 2; window.top = window.bottom - win_hyt; } move = TRUE; } if (move) SetWindowPos( win, 0, window.left, window.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); } // Enumerate the console TrueType fonts, looking for a unique prefix. BOOL find_font( VOID ) { HKEY hKey; char value[16], data[LF_FACESIZE], face[LF_FACESIZE]; DWORD vlen, len; int cp; int i; BOOL rc; if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\" "Microsoft\\" "Windows NT\\" "CurrentVersion\\" "Console\\" "TrueTypeFont", 0, KEY_QUERY_VALUE, &hKey )) { return FALSE; } rc = FALSE; *face = '\0'; cp = GetConsoleOutputCP(); for (i = 0;; ++i) { vlen = sizeof(value); len = sizeof(data); if (ERROR_NO_MORE_ITEMS == RegEnumValue( hKey, i, value, &vlen, NULL, NULL, (LPBYTE)data, &len )) break; if (*data == '*') { if (atoi( value ) != cp) continue; strcpy( data, data + 1 ); } if (_strnicmp( data, option.face, option.facelen ) == 0) { if (!rc) { rc = TRUE; strcpy( face, data ); } else { rc = FALSE; break; } } } RegCloseKey( hKey ); if (rc) mbstowcs( cur_font.FaceName, face, LF_FACESIZE ); return rc; } void read_console_defaults( HKEY hKey ) { DWORD len; #define RegQuery( len_, val_, var_ ) \ len = len_; \ RegQueryValueEx( hKey, val_, NULL, NULL, (LPBYTE)var_, &len ); RegQuery( 4, "CursorSize", &defcon.cursor ); RegQuery( LF_FACESIZE, "FaceName", defcon.face ); RegQuery( 4, "FontSize", &defcon.font ); RegQuery( 4, "FontWeight", &defcon.weight ); RegQuery( 4, "InsertMode", &defcon.insmode ); RegQuery( 4, "QuickEdit", &defcon.quickedit ); RegQuery( 4, "ScreenBufferSize", &defcon.buf ); RegQuery( 4, "ScreenColors", &defcon.attr ); RegQuery( 4, "WindowPosition", &defcon.pos ); RegQuery( 4, "WindowSize", &defcon.win ); } void GetConsoleDefaults( VOID ) { HKEY hKey, hApp; WCHAR title[MAX_PATH*2]; if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_CURRENT_USER, "Console", 0, KEY_QUERY_VALUE, &hKey )) { return; } read_console_defaults( hKey ); if (GetConsoleOriginalTitleW && GetConsoleOriginalTitleW( title, sizeof(title) / sizeof(WCHAR) )) { LPWSTR p; for (p = title; *p; ++p) if (*p == '\\') *p = '_'; if (ERROR_SUCCESS == RegOpenKeyExW( hKey,title, 0, KEY_QUERY_VALUE, &hApp )) { read_console_defaults( hApp ); RegCloseKey( hApp ); } } RegCloseKey( hKey ); if (defcon.font.X == 0 && defcon.font.Y == 0) { defcon.font.X = 8; defcon.font.Y = 12; } } /* Undocumented console font functions. These functions are only available under NT (only tested in XP, though). */ #if 0 // Retrieve a list of available console fonts. // Returns 0 for failure, nonzero for success. BOOL GetConsoleFontInfo( HANDLE hConsoleOutput, // handle of console screen buffer BOOL bMax, // FALSE for current window size, TRUE for max. DWORD nSize, // size of array PCONSOLE_FONT lpConsoleFont // pointer to array to receive font info ); // Determine the number of available console fonts. DWORD GetNumberOfConsoleFonts( VOID ); // Set the console font. It appears the TrueType fonts are only indexed after // being used. To be able to select a different TrueType font pre-Vista, it // is still necessary to go through the Properties once. The font (and its // bold/normal counterpart) are then inserted into the list, potentially // changing the order of the current fonts. // Returns 0 for failure, nonzero for success. BOOL SetConsoleFont( HANDLE hConsoleOutput, // handle of console screen buffer DWORD nFont // font index from lpConsoleFont } #endif // Get the functions and the current font. BOOL InitConsoleFont( VOID ) { HMODULE hLib; hLib = GetModuleHandle( "KERNEL32.DLL" ); if (hLib == NULL) return FALSE; #define GetProc( proc ) \ proc = (proc##T)GetProcAddress( hLib, #proc ); GetProc( GetConsoleFontInfo ); GetProc( GetConsoleFontSize ); GetProc( GetConsoleOriginalTitleW ); GetProc( GetConsoleWindow ); GetProc( GetCurrentConsoleFont ); GetProc( GetCurrentConsoleFontEx ); GetProc( GetNumberOfConsoleFonts ); GetProc( SetConsoleFont ); GetProc( SetCurrentConsoleFontEx ); #undef GetProc if (GetConsoleWindow == NULL) GetConsoleWindow = GetForegroundWindow; if (GetCurrentConsoleFont == NULL) return FALSE; if (GetCurrentConsoleFontEx == NULL) { CONSOLE_FONT fi; GetCurrentConsoleFont( con, 0, &fi ); cur_font.nFont = fi.nFont; cur_font.dwFontSize = GetConsoleFontSize( con, fi.nFont ); } else { GetCurrentConsoleFontEx( con, 0, &cur_font ); cur_font.dwFontSize = GetConsoleFontSize( con, cur_font.nFont ); } return TRUE; } // Wrap any lines in TEXT longer than the screen to COL. This assumes one byte // occupies one cell (newline being the only exception). void wrap_text( int col, const char* text ) { static int x, b; int s, w, i; s = i = 0; for (; text[i]; ++i) { if (x == csbi.dwSize.X) { // If it's a space that wrapped, discard it and its companions. if (text[i] == ' ') { // We need a newline if there are other spaces before this one, or if // being redirected; otherwise the screen has already wrapped. BOOL nl = redir; if (text[i-1] == ' ') { nl = TRUE; while (text[i-1] == ' ') --i; } printf( "%.*s", i - s, text + s ); if (nl) putchar( '\n' ); for (x = 0; x < col; ++x) putchar( ' ' ); b = x; while (text[i+1] == ' ') ++i; s = i + 1; continue; } // If it's a newline that wrapped, discard it when writing to the screen. if (text[i] == '\n') { if (!redir) { printf( "%.*s", i - s, text + s ); s = i + 1; } x = b = 0; continue; } // Find the start of the word. for (w = i; text[w-1] != ' ' && x > b;) --x, --w; if (x == b) { // The word is longer than the screen. Wrap it as-is when writing to // the screen; wrap after it when redirecting. if (!redir) { printf( "%.*s", i - s, text + s ); s = i; for (x = 0; x < col; ++x) putchar( ' ' ); b = x++; continue; } while (text[++i] != ' ' && text[i] != '\n' && text[i] != '\0') ; if (text[i] == '\0') break; if (text[i] == '\n') { x = 0; continue; } w = i; while (text[++w] == ' ') ; } i = w; while (text[w-1] == ' ') --w; printf( "%.*s\n", w - s, text + s ); for (x = 0; x < col; ++x) putchar( ' ' ); s = i; } if (text[i] == '\n') x = 0; else ++x; } printf( "%s", text + s ); } void help( BOOL brief ) { const char* ref = (brief) ? " (see full help)" : " (see below)"; wrap_text( 0, "Console Settings by Jason Hood .\n" "Version " PVERS " (" PDATE "). Public Domain.\n" "http://misc.adoxa.vze.com/\n" "\n" "Display or change (temporarily) properties of the console.\n" "\n" ); wrap_text( 3, "cs [m|d|l] [a|b|w|f] [COLS][xROWS] [c[COLS]] [r[ROWS]] [,[FONT]] [p[N]] " "[o[ATTR]] [e[0|1]] [i[0|1]] [u[N]] [q|v]\n" "\n" ); wrap_text( 6, "COLS width of the buffer, window or font\n" "ROWS height of the buffer, window or font\n" "FONT relative index number (default 1)" ); if (GetCurrentConsoleFontEx) { wrap_text( 6, "\n" " face name" ); wrap_text( 6, ref ); } wrap_text( 6, "\n" "ATTR set text attribute" ); wrap_text( 6, ref ); wrap_text( 6, "\n" "a apply size to buffer and window\n" "b apply size to buffer (and possibly window)\n" "w apply size to window (and possibly buffer)\n" "f apply size to font" ); wrap_text( 6, ref ); wrap_text( 6, "\n" " automatically choose a font to achieve the desired window size\n" "m display maximum window size\n" "d display default values" ); if (!GetConsoleOriginalTitleW) wrap_text( 6, " (for the console, not the title)" ); wrap_text( 6, "\n" " by itself, set everything to default\n" "l display current (local) values (undo 'm' or 'd')\n" "p position the window" ); wrap_text( 6, ref ); wrap_text( 6, "\n" "e quick edit mode\n" "i insert mode\n" "u cursor (0 to hide, 1 to show, otherwise size as a percentage)\n" "q prevent output of messages (error messages are still displayed)\n" "v display all properties\n" ); if (!brief) { wrap_text( 2, "\n" "* By default, columns will apply to both the buffer and window, " "but rows will only apply to the window.\n" "* If no values are given, the current, maximum and/or default values will be " "displayed; ERRORLEVEL is set to the last specified.\n" "* COLS and ROWS may be 'm' to use the maximum window size.\n" "* The values may be 'd' to use the default.\n" "* TrueType fonts must first be selected in \"Properties\" " ); if (GetCurrentConsoleFontEx) wrap_text( 2, "or by face name " ); wrap_text( 2, "before being available via index and setting by " ); wrap_text( 2, (GetCurrentConsoleFontEx) ? "width.\n" : "size.\n" ); if (GetCurrentConsoleFontEx) wrap_text( 2, "* Face name need only be a unique prefix; suffix with '+' for bold, or use " "'-' to make current bold font regular.\n" ); wrap_text( 2, "* Attribute is a decimal number (e.g. \"o31\"), or a hexadecimal number " "prefixed with '#' (e.g. \"o#1e\"); please use \"COLOR /?\" for the " "available numbers.\n" ); wrap_text( 9, "* N is 0 for the middle of the screen (default);\n" " 1 for the top-left corner; 5 for the middle at the top;\n" " 2 for the top-right corner; 6 for the middle at the bottom;\n" " 3 for the bottom-left corner; 7 for the middle at the left;\n" " 4 for the bottom-right corner; 8 for the middle at the right.\n" " Or, it may be a letter from each column:\n" " l for the left; t for the top;\n" " h for the middle; v for the middle;\n" " r for the right; b for the bottom.\n" ); } exit( E_OK ); }