-
-
Save nutbread/e24c9a557de3ecba4bcc to your computer and use it in GitHub Desktop.
Colored command prompt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// g++ -O3 -DNDEBUG -std=c++11 -o ccmd ccmd.cpp | |
// For usage info: ccmd -? | |
// Create a shortcut as: "C:\Windows\System32\cmd.exe" /C "path\to\ccmd.exe" [extra args] | |
#define UNICODE | |
#define _UNICODE | |
#include <windows.h> | |
#include <cstdio> | |
#include <iostream> | |
#include <sstream> | |
#include <cstring> | |
#include <cstdlib> | |
#include <cstdint> | |
#include <cassert> | |
using namespace std; | |
// Windows API | |
// If this gives re-declaration errors, simply un-comment the next line | |
// /* | |
// https://code.google.com/p/conemu-maximus5/issues/attachmentText?id=982&aid=9820000000&name=colors_test.cpp | |
typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX { | |
ULONG cbSize; | |
COORD dwSize; | |
COORD dwCursorPosition; | |
WORD wAttributes; | |
SMALL_RECT srWindow; | |
COORD dwMaximumWindowSize; | |
WORD wPopupAttributes; | |
BOOL bFullscreenSupported; | |
COLORREF ColorTable[16]; | |
} CONSOLE_SCREEN_BUFFER_INFOEX, *PCONSOLE_SCREEN_BUFFER_INFOEX; | |
extern "C" { | |
BOOL WINAPI | |
GetConsoleScreenBufferInfoEx( | |
HANDLE hConsoleOutput, | |
PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx | |
); | |
BOOL WINAPI | |
SetConsoleScreenBufferInfoEx( | |
HANDLE hConsoleOutput, | |
PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx | |
); | |
} | |
// */ | |
// Data structures | |
struct ThreadData { | |
bool active; | |
CONSOLE_SCREEN_BUFFER_INFOEX* consoleInfo; | |
HANDLE consoleHandle; | |
int hue; | |
int saturation; | |
int value; | |
double hueSpeed; | |
int sleepMs; | |
}; | |
// Extended WaitForSingleObject | |
bool | |
waitForSingleObject2( | |
HANDLE handle | |
) { | |
// WaitForSingleObject(handle, INFINITE); | |
while (true) { | |
DWORD ret = MsgWaitForMultipleObjects( | |
1, // nCount | |
&handle, // pHandles | |
false, // bWaitAll | |
INFINITE, // dwMilliseconds | |
QS_ALLINPUT // dwWakeMask | |
); | |
if (ret == WAIT_OBJECT_0) { | |
return true; | |
} | |
if (ret != WAIT_OBJECT_0 + 1) { | |
return false; | |
} | |
// Message pump | |
MSG msg; | |
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
} | |
} | |
// Color conversion | |
constexpr int HueMax = 256 * 6; | |
uint32_t | |
hsvToRgb( | |
int hue, | |
int sat, | |
int val | |
) { | |
assert(hue >= 0); | |
assert(hue < HueMax); | |
assert(sat >= 0); | |
assert(sat < 256); | |
assert(val >= 0); | |
assert(val < 256); | |
unsigned char vMin = val - static_cast<unsigned char>((val / 255.0 * sat / 255.0) * 255); | |
unsigned char vMax = val; | |
unsigned char vSpan = vMax - vMin; | |
int rgb[3]; | |
if (hue < 256 * 1) { | |
rgb[0] = vMax; | |
rgb[1] = vMin + ((hue - 0) * vSpan) / 255; | |
rgb[2] = vMin; | |
} | |
else if (hue < 256 * 2) { | |
rgb[0] = vMax - ((hue - 256) * vSpan) / 255; | |
rgb[1] = vMax; | |
rgb[2] = vMin; | |
} | |
else if (hue < 256 * 3) { | |
rgb[0] = vMin; | |
rgb[1] = vMax; | |
rgb[2] = vMin + ((hue - 256 * 2) * vSpan) / 255; | |
} | |
else if (hue < 256 * 4) { | |
rgb[0] = vMin; | |
rgb[1] = vMax - ((hue - 256 * 3) * vSpan) / 255; | |
rgb[2] = vMax; | |
} | |
else if (hue < 256 * 5) { | |
rgb[0] = vMin + ((hue - 256 * 4) * vSpan) / 255; | |
rgb[1] = vMin; | |
rgb[2] = vMax; | |
} | |
else { | |
rgb[0] = vMax; | |
rgb[1] = vMin; | |
rgb[2] = vMax - ((hue - 256 * 5) * vSpan) / 255; | |
} | |
return (rgb[0] | (rgb[1] << 8) | (rgb[2] << 16)); | |
}; | |
// Color managing thread | |
DWORD WINAPI | |
threadFunction( | |
void* data | |
) { | |
ThreadData* tData = static_cast<ThreadData*>(data); | |
CONSOLE_SCREEN_BUFFER_INFOEX* consoleInfo = tData->consoleInfo; | |
HANDLE consoleHandle = tData->consoleHandle; | |
double hue = tData->hue; | |
double hueSpeed = HueMax / tData->hueSpeed; | |
int saturation = tData->saturation; | |
int value = tData->value; | |
int sleepMs = tData->sleepMs; | |
int color; | |
while (tData->active) { | |
// Update only the text color | |
color = hsvToRgb(static_cast<int>(hue), saturation, value); | |
consoleInfo->ColorTable[7] = color; // static_cast<int>((rand() / static_cast<double>(RAND_MAX)) * 0xFFFFFF); | |
SetConsoleScreenBufferInfoEx(consoleHandle, consoleInfo); | |
// Change hue | |
hue += hueSpeed * sleepMs / 1000.0; | |
while (hue > HueMax) hue -= HueMax; | |
// Sleep | |
Sleep(sleepMs); | |
} | |
return 0; | |
} | |
// Signal handlers | |
void signalHandler( | |
int signal | |
) { | |
} | |
BOOL WINAPI signalHandlerCtrlC( | |
DWORD dwCtrlType | |
) { | |
return TRUE; | |
} | |
double atofWide( | |
const wchar_t* string | |
) { | |
double v = 0.0; | |
wistringstream wss; | |
wss.str(string); | |
wss >> v; | |
return v; | |
} | |
int atoiWide( | |
const wchar_t* string | |
) { | |
int v = 0; | |
wistringstream wss; | |
wss.str(string); | |
wss >> v; | |
return v; | |
} | |
// Main | |
int main( | |
int argc, | |
char** argv | |
) { | |
#ifdef UNICODE | |
// Setup wchar command line | |
const TCHAR* cmdLine = GetCommandLine(); | |
if (cmdLine == nullptr) return -1; | |
int wargc = 0; | |
WCHAR** wargv = CommandLineToArgvW(cmdLine, &wargc); | |
#endif | |
if (wargc > 1 && (wcscmp(wargv[1], L"/?") == 0 || wcscmp(wargv[1], L"-?") == 0)) { | |
cerr << "Usage:\n" | |
" ccmd [executable] [hue_speed] [sleep_ms] [hue_start] [saturation_start] [value_start]\n\n" | |
"Ranges:\n" | |
" hue_speed: (0,inf)\n" | |
" sleep_ms: (0,inf)\n" | |
" hue_start: [0,256*6)\n" | |
" saturation_start: [0,256)\n" | |
" value_start: [0,256)\n\n" | |
"Defaults:\n" | |
" ccmd cmd.exe 10 100 256 128 220\n"; | |
return -1; | |
} | |
// Arguments | |
ThreadData threadData; | |
threadData.active = true; | |
threadData.hue = 256; | |
threadData.saturation = 128; | |
threadData.value = 220; | |
threadData.hueSpeed = 10.0; // seconds it takes to do a full hue cycle | |
threadData.sleepMs = 100; | |
int argid = 1; | |
double vd; | |
int vi; | |
const wchar_t* commandLine = L"cmd.exe"; | |
if (argid < wargc) commandLine = wargv[argid++]; | |
if (argid < wargc && (vd = atofWide(wargv[argid++])) > 0.0) threadData.hueSpeed = vd; | |
if (argid < wargc && (vi = atoiWide(wargv[argid++])) > 0) threadData.sleepMs = vi; | |
if (argid < wargc && (vi = atoiWide(wargv[argid++])) >= 0 && vi < HueMax) threadData.hue = vi; | |
if (argid < wargc && (vi = atoiWide(wargv[argid++])) >= 0 && vi < 256) threadData.saturation = vi; | |
if (argid < wargc && (vi = atoiWide(wargv[argid++])) >= 0 && vi < 256) threadData.value = vi; | |
// Signals | |
SetConsoleCtrlHandler(&signalHandlerCtrlC, true); | |
// Get console info | |
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); | |
CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo; | |
CONSOLE_SCREEN_BUFFER_INFOEX consoleInfoNew; | |
consoleInfo.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); | |
GetConsoleScreenBufferInfoEx(consoleHandle, &consoleInfo); | |
++consoleInfo.srWindow.Right; | |
++consoleInfo.srWindow.Bottom; | |
memcpy(&consoleInfoNew, &consoleInfo, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)); | |
CONSOLE_CURSOR_INFO cursorInfo; | |
GetConsoleCursorInfo(consoleHandle, &cursorInfo); | |
threadData.consoleInfo = &consoleInfoNew; | |
threadData.consoleHandle = consoleHandle; | |
// Setup new process | |
SECURITY_ATTRIBUTES processAttr; | |
processAttr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
processAttr.lpSecurityDescriptor = nullptr; | |
processAttr.bInheritHandle = TRUE; | |
SECURITY_ATTRIBUTES threadAttr; | |
threadAttr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
threadAttr.lpSecurityDescriptor = nullptr; | |
threadAttr.bInheritHandle = TRUE; | |
STARTUPINFOW startupInfo; | |
ZeroMemory(&startupInfo, sizeof(STARTUPINFOW)); | |
startupInfo.cb = sizeof(STARTUPINFOW); | |
PROCESS_INFORMATION processInfo; | |
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); | |
unsigned int commandLineLength = wcslen(commandLine) + 1; | |
wchar_t* commandLineTemp = new wchar_t[commandLineLength]; | |
memcpy(commandLineTemp, commandLine, commandLineLength * sizeof(wchar_t)); | |
BOOL b = CreateProcessW( | |
nullptr, // lpApplicationName | |
commandLineTemp, // lpCommandLine | |
&processAttr, // lpProcessAttributes | |
&threadAttr, // lpThreadAttributes | |
TRUE, // bInheritHandles | |
0, // dwCreationFlags | |
nullptr, // lpEnvironment | |
nullptr, // lpCurrentDirectory | |
&startupInfo, // lpStartupInfo | |
&processInfo // lpProcessInformation | |
); | |
delete [] commandLineTemp; | |
// Failure | |
if (!b) { | |
return 1; | |
} | |
// Spawn thread | |
SECURITY_ATTRIBUTES threadAttr2; | |
threadAttr2.nLength = sizeof(SECURITY_ATTRIBUTES); | |
threadAttr2.lpSecurityDescriptor = nullptr; | |
threadAttr2.bInheritHandle = FALSE; | |
// Create thread | |
HANDLE threadHandle = CreateThread( | |
&threadAttr2, // lpThreadAttributes, | |
0, // dwStackSize, | |
threadFunction, // lpStartAddress, | |
static_cast<void*>(&threadData), // lpParameter, | |
0, // dwCreationFlags, | |
nullptr // lpThreadId | |
); | |
// Failure | |
if (threadHandle == NULL) { | |
return 1; | |
} | |
// Join | |
waitForSingleObject2(processInfo.hProcess); | |
// Join thread | |
threadData.active = false; | |
waitForSingleObject2(threadHandle); | |
// Reset colors | |
SetConsoleScreenBufferInfoEx(consoleHandle, &consoleInfo); | |
SetConsoleCursorInfo(consoleHandle, &cursorInfo); | |
// Done | |
#ifdef UNICODE | |
LocalFree(wargv); | |
#endif | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment