Clean up console interface to be less likely to fail to define the width and height. Update notes in the PDF. Add the PDF for newer Yamaha even if I don't have one (and the protocol has significant differences).
243 lines
7.7 KiB
C++
243 lines
7.7 KiB
C++
|
|
// Something for later
|
|
//
|
|
// #include <windows.h>
|
|
// #include <stdio.h>
|
|
//
|
|
// void enable_ansi_escape_sequences(void) {
|
|
// HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
// DWORD mode = 0;
|
|
//
|
|
// if (!GetConsoleMode(hOut, &mode)) {
|
|
// return; // handle error if needed
|
|
// }
|
|
//
|
|
// mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
//
|
|
// SetConsoleMode(hOut, mode);
|
|
// }
|
|
//
|
|
// int main() {
|
|
// enable_ansi_escape_sequences();
|
|
//
|
|
// printf("\x1b[32mGreen text\x1b[0m\n");
|
|
// printf("\x1b[31mRed text\x1b[0m\n");
|
|
//
|
|
// return 0;
|
|
// }
|
|
|
|
#include "stdafx.h"
|
|
#include <Windows.h>
|
|
#include <stdio.h>
|
|
#include <conio.h>
|
|
#include "ConsoleHandler.h"
|
|
|
|
// For special cursor positioning
|
|
static bool consoleInit = false;
|
|
static HANDLE hStdout, hStdin;
|
|
static CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
static WORD wOldColorAttrs; // Save the current console colors
|
|
|
|
static short consoleWidth = 0;
|
|
static short consoleHeight = 0;
|
|
static short scrollBot = 0; // set at init: consoleHeight - 1
|
|
static short scrollTop = 0; // set at init: consoleHeight - consoleScrollHeight - 1
|
|
|
|
void Console_SetColor(WORD color) {
|
|
SetConsoleTextAttribute(hStdout, color);
|
|
}
|
|
void Console_RestoreColor() {
|
|
SetConsoleTextAttribute(hStdout, wOldColorAttrs);
|
|
}
|
|
|
|
|
|
void Console_Init(short Left, short Top, short Width, short Height, short bottomScrollHeight) {
|
|
hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
|
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
fprintf(stderr, "Error: Unable to get console buffer info. Code: %lu\n", GetLastError());
|
|
exit(1);
|
|
}
|
|
wOldColorAttrs = csbi.wAttributes;
|
|
scrollBot = Height - 1;
|
|
scrollTop = Height - bottomScrollHeight - 1;
|
|
|
|
|
|
|
|
#if 1
|
|
COORD max = GetLargestConsoleWindowSize(hStdout);
|
|
SHORT w = (Width > max.X) ? max.X : Width;
|
|
SHORT h = (Height > max.Y) ? max.Y : Height;
|
|
|
|
SMALL_RECT win = { 0, 0, (SHORT)(w - 1), (SHORT)(h - 1) };
|
|
// Enlarge buffer first (for growth), then set window.
|
|
SetConsoleScreenBufferSize(hStdout, { w, h });
|
|
SetConsoleWindowInfo(hStdout, TRUE, &win);
|
|
#else
|
|
// Desired size (width x height)
|
|
COORD bufferSize = { 0, 0 };
|
|
bufferSize.X = (csbi.dwSize.X < Width) ? Width : csbi.dwSize.X; // columns
|
|
bufferSize.Y = (csbi.dwSize.Y < Height) ? Height : csbi.dwSize.Y; // rows
|
|
|
|
// Step 2: Set new buffer size
|
|
if (!SetConsoleScreenBufferSize(hStdout, bufferSize)) {
|
|
fprintf(stderr, "Error: Unable to set console buffer size. Code: %lu\n", GetLastError());
|
|
|
|
// figure out why ...
|
|
CONSOLE_SCREEN_BUFFER_INFOEX info;
|
|
info.cbSize = sizeof(info);
|
|
if (!GetConsoleScreenBufferInfoEx(hStdout, &info)) {
|
|
// handle error
|
|
}
|
|
fprintf(stderr, "Width[%u] > info.dwMaximumWindowSize.X[%u] || Height[%u] > info.dwMaximumWindowSize.Y[%u]\n",
|
|
Width, info.dwMaximumWindowSize.X, Height, info.dwMaximumWindowSize.Y);
|
|
fprintf(stderr, "Width[%u] < GetSystemMetrics(SM_CXMIN)[%u] || Height[%u] < GetSystemMetrics(SM_CYMIN)[%u]\n",
|
|
Width, GetSystemMetrics(SM_CXMIN), Height, GetSystemMetrics(SM_CYMIN));
|
|
exit(1);
|
|
}
|
|
|
|
// Step 3: Set final window size to match buffer
|
|
// The final window size we want to set
|
|
SMALL_RECT newWindow = { 0 };
|
|
newWindow.Left = 0;
|
|
newWindow.Top = 0;
|
|
newWindow.Right = bufferSize.X - 1;
|
|
newWindow.Bottom = bufferSize.Y - 1;
|
|
|
|
if (!SetConsoleWindowInfo(hStdout, TRUE, &newWindow)) {
|
|
fprintf(stderr, "Error: Unable to set console window size. Code: %lu\n", GetLastError());
|
|
CONSOLE_SCREEN_BUFFER_INFOEX info;
|
|
info.cbSize = sizeof(info);
|
|
if (!GetConsoleScreenBufferInfoEx(hStdout, &info)) {
|
|
// handle error
|
|
}
|
|
fprintf(stderr, "Width[%u] > info.dwMaximumWindowSize.X[%u] || Height[%u] > info.dwMaximumWindowSize.Y[%u]\n",
|
|
Width, info.dwMaximumWindowSize.X, Height, info.dwMaximumWindowSize.Y);
|
|
fprintf(stderr, "Width[%u] < GetSystemMetrics(SM_CXMIN)[%u] || Height[%u] < GetSystemMetrics(SM_CYMIN)[%u]\n",
|
|
Width, GetSystemMetrics(SM_CXMIN), Height, GetSystemMetrics(SM_CYMIN));
|
|
exit(1);
|
|
}
|
|
// end
|
|
|
|
Console_SetWindowPosition(Left, Top);
|
|
#endif
|
|
}
|
|
|
|
void Console_Close() {
|
|
SetConsoleTextAttribute(hStdout, wOldColorAttrs);
|
|
}
|
|
|
|
void Console_Cls() {
|
|
COORD coordScreen = { 0, 0 }; // home for the cursor
|
|
DWORD cCharsWritten;
|
|
DWORD dwConSize;
|
|
|
|
// Get the number of character cells in the current buffer.
|
|
if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
return;
|
|
}
|
|
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
|
// Fill the entire screen with blanks.
|
|
if (!FillConsoleOutputCharacter(hStdout, // 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;
|
|
}
|
|
// Get the current text attribute.
|
|
if (!GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
return;
|
|
}
|
|
// Set the buffer's attributes accordingly.
|
|
if (!FillConsoleOutputAttribute(hStdout, // 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;
|
|
}
|
|
// Put the cursor at its home coordinates.
|
|
SetConsoleCursorPosition(hStdout, coordScreen);
|
|
}
|
|
|
|
void Console_SetWindowPosition(int x, int y) {
|
|
HWND hwnd = GetConsoleWindow();
|
|
if (!hwnd) return;
|
|
// Move the window to (x,y) in screen coordinates without changing size or z-order
|
|
SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
|
}
|
|
|
|
void Console_Write(const char *text) {
|
|
DWORD written;
|
|
WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr);
|
|
}
|
|
|
|
void Console_WriteAt(short x, short y, const char *text) {
|
|
DWORD written;
|
|
if (hStdout) {
|
|
Console_SetCursor(x, y);
|
|
WriteConsole(hStdout, text, (DWORD)strlen(text), &written, nullptr);
|
|
} else {
|
|
printf("%s\n", text);
|
|
}
|
|
}
|
|
|
|
void Console_SetCursor(short x, short y) {
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
csbi.dwCursorPosition.X = (short)((x < 0) ? csbi.srWindow.Right + x : x);
|
|
csbi.dwCursorPosition.Y = (short)((y < 0) ? csbi.srWindow.Bottom + 1 + y : y);
|
|
SetConsoleCursorPosition(hStdout, csbi.dwCursorPosition);
|
|
}
|
|
|
|
void Console_ScrollBottomRegion() {
|
|
short topLine = scrollTop + 1;
|
|
short bottomLine = scrollBot;
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
if (topLine < 0) topLine = csbi.srWindow.Bottom + topLine;
|
|
if (bottomLine < 0) bottomLine = csbi.srWindow.Bottom + bottomLine;
|
|
SMALL_RECT scrollRect = { 0, topLine, csbi.dwMaximumWindowSize.X - 1, bottomLine };
|
|
COORD dest = { 0, topLine - 1 };
|
|
CHAR_INFO fill = { ' ', { FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE } };
|
|
ScrollConsoleScreenBuffer(hStdout, &scrollRect, &scrollRect, dest, &fill);
|
|
_putch('\r'); // Cursor to left margin
|
|
}
|
|
|
|
bool Console_AdvanceToNextLineIfNotRoomFor(short x, int scroll) {
|
|
bool advanced = false;
|
|
GetConsoleScreenBufferInfo(hStdout, &csbi);
|
|
if (csbi.dwCursorPosition.X + x > csbi.dwMaximumWindowSize.X) {
|
|
advanced = true;
|
|
if (scroll == 1) {
|
|
Console_ScrollBottomRegion();
|
|
} else {
|
|
csbi.dwCursorPosition.Y++;
|
|
}
|
|
Console_SetCursor(0, csbi.dwCursorPosition.Y);
|
|
}
|
|
return advanced;
|
|
}
|
|
|
|
// Console_SetCursorVisibility
|
|
//
|
|
// Set the state of the cursor and provide the prior state so it
|
|
// can be restored
|
|
//
|
|
// @param[in] bool the desired state, true is visible
|
|
// @returns the prior state, true is visible
|
|
//
|
|
bool Console_SetCursorVisibility(bool visible) {
|
|
CONSOLE_CURSOR_INFO cursorInfo;
|
|
bool priorState = true;
|
|
|
|
if (!GetConsoleCursorInfo(hStdout, &cursorInfo)) {
|
|
// printf("***** Error: Unable to get cursor info.\n");
|
|
return priorState;
|
|
}
|
|
priorState = cursorInfo.bVisible;
|
|
cursorInfo.bVisible = visible; // true = show, false = hide
|
|
if (!SetConsoleCursorInfo(hStdout, &cursorInfo)) {
|
|
// std::cerr << "Error: Unable to set cursor info.\n";
|
|
}
|
|
return priorState;
|
|
} |